Misc fixes for reset and new packets for userspace usage. * 'drm-fixes-3.8' of git://people.freedesktop.org/~agd5f/linux: drm/radeon: add WAIT_UNTIL to evergreen VM safe reg list drm/radeon: add support for MEM_WRITE packet drm/radeon: restore modeset late in GPU reset path drm/radeon: avoid deadlock in pm path when waiting for fence drm/radeon: don't leave fence blocked process on failed GPU reset
Unified · Split
| @@ -2654,6 +2654,35 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, · 2653 unmodified lines | ||
| 2654 | 2654 | ib[idx+4] = upper_32_bits(offset) & 0xff; |
| 2655 | 2655 | } |
| 2656 | 2656 | break; |
| 2657 | + case PACKET3_MEM_WRITE: | |
| 2658 | + { | |
| 2659 | + u64 offset; | |
| 2660 | + | |
| 2661 | + if (pkt->count != 3) { | |
| 2662 | + DRM_ERROR("bad MEM_WRITE (invalid count)\n"); | |
| 2663 | + return -EINVAL; | |
| 2664 | + } | |
| 2665 | + r = evergreen_cs_packet_next_reloc(p, &reloc); | |
| 2666 | + if (r) { | |
| 2667 | + DRM_ERROR("bad MEM_WRITE (missing reloc)\n"); | |
| 2668 | + return -EINVAL; | |
| 2669 | + } | |
| 2670 | + offset = radeon_get_ib_value(p, idx+0); | |
| 2671 | + offset += ((u64)(radeon_get_ib_value(p, idx+1) & 0xff)) << 32UL; | |
| 2672 | + if (offset & 0x7) { | |
| 2673 | + DRM_ERROR("bad MEM_WRITE (address not qwords aligned)\n"); | |
| 2674 | + return -EINVAL; | |
| 2675 | + } | |
| 2676 | + if ((offset + 8) > radeon_bo_size(reloc->robj)) { | |
| 2677 | + DRM_ERROR("bad MEM_WRITE bo too small: 0x%llx, 0x%lx\n", | |
| 2678 | + offset + 8, radeon_bo_size(reloc->robj)); | |
| 2679 | + return -EINVAL; | |
| 2680 | + } | |
| 2681 | + offset += reloc->lobj.gpu_offset; | |
| 2682 | + ib[idx+0] = offset; | |
| 2683 | + ib[idx+1] = upper_32_bits(offset) & 0xff; | |
| 2684 | + break; | |
| 2685 | + } | |
| 2657 | 2686 | case PACKET3_COPY_DW: |
| 2658 | 2687 | if (pkt->count != 4) { |
| 2659 | 2688 | DRM_ERROR("bad COPY_DW (invalid count)\n"); |
| @@ -3287,6 +3316,7 @@ static bool evergreen_vm_reg_valid(u32 reg) · 627 unmodified lines | ||
| 3287 | 3316 | |
| 3288 | 3317 | /* check config regs */ |
| 3289 | 3318 | switch (reg) { |
| 3319 | + case WAIT_UNTIL: | |
| 3290 | 3320 | case GRBM_GFX_INDEX: |
| 3291 | 3321 | case CP_STRMOUT_CNTL: |
| 3292 | 3322 | case CP_COHER_CNTL: |
| @@ -2294,6 +2294,35 @@ static int r600_packet3_check(struct radeon_cs_parser *p, · 2293 unmodified lines | ||
| 2294 | 2294 | ib[idx+4] = upper_32_bits(offset) & 0xff; |
| 2295 | 2295 | } |
| 2296 | 2296 | break; |
| 2297 | + case PACKET3_MEM_WRITE: | |
| 2298 | + { | |
| 2299 | + u64 offset; | |
| 2300 | + | |
| 2301 | + if (pkt->count != 3) { | |
| 2302 | + DRM_ERROR("bad MEM_WRITE (invalid count)\n"); | |
| 2303 | + return -EINVAL; | |
| 2304 | + } | |
| 2305 | + r = r600_cs_packet_next_reloc(p, &reloc); | |
| 2306 | + if (r) { | |
| 2307 | + DRM_ERROR("bad MEM_WRITE (missing reloc)\n"); | |
| 2308 | + return -EINVAL; | |
| 2309 | + } | |
| 2310 | + offset = radeon_get_ib_value(p, idx+0); | |
| 2311 | + offset += ((u64)(radeon_get_ib_value(p, idx+1) & 0xff)) << 32UL; | |
| 2312 | + if (offset & 0x7) { | |
| 2313 | + DRM_ERROR("bad MEM_WRITE (address not qwords aligned)\n"); | |
| 2314 | + return -EINVAL; | |
| 2315 | + } | |
| 2316 | + if ((offset + 8) > radeon_bo_size(reloc->robj)) { | |
| 2317 | + DRM_ERROR("bad MEM_WRITE bo too small: 0x%llx, 0x%lx\n", | |
| 2318 | + offset + 8, radeon_bo_size(reloc->robj)); | |
| 2319 | + return -EINVAL; | |
| 2320 | + } | |
| 2321 | + offset += reloc->lobj.gpu_offset; | |
| 2322 | + ib[idx+0] = offset; | |
| 2323 | + ib[idx+1] = upper_32_bits(offset) & 0xff; | |
| 2324 | + break; | |
| 2325 | + } | |
| 2297 | 2326 | case PACKET3_COPY_DW: |
| 2298 | 2327 | if (pkt->count != 4) { |
| 2299 | 2328 | DRM_ERROR("bad COPY_DW (invalid count)\n"); |
| @@ -225,12 +225,13 @@ struct radeon_fence { · 224 unmodified lines | ||
| 225 | 225 | int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring); |
| 226 | 226 | int radeon_fence_driver_init(struct radeon_device *rdev); |
| 227 | 227 | void radeon_fence_driver_fini(struct radeon_device *rdev); |
| 228 | +void radeon_fence_driver_force_completion(struct radeon_device *rdev); | |
| 228 | 229 | int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence **fence, int ring); |
| 229 | 230 | void radeon_fence_process(struct radeon_device *rdev, int ring); |
| 230 | 231 | bool radeon_fence_signaled(struct radeon_fence *fence); |
| 231 | 232 | int radeon_fence_wait(struct radeon_fence *fence, bool interruptible); |
| 232 | 233 | int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring); |
| 233 | −void radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring); | |
| 234 | +int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring); | |
| 234 | 235 | int radeon_fence_wait_any(struct radeon_device *rdev, |
| 235 | 236 | struct radeon_fence **fences, |
| 236 | 237 | bool intr); |
| @@ -1164,6 +1164,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) · 1163 unmodified lines | ||
| 1164 | 1164 | struct drm_crtc *crtc; |
| 1165 | 1165 | struct drm_connector *connector; |
| 1166 | 1166 | int i, r; |
| 1167 | + bool force_completion = false; | |
| 1167 | 1168 | |
| 1168 | 1169 | if (dev == NULL || dev->dev_private == NULL) { |
| 1169 | 1170 | return -ENODEV; |
| @@ -1206,8 +1207,16 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) · 36 unmodified lines | ||
| 1206 | 1207 | |
| 1207 | 1208 | mutex_lock(&rdev->ring_lock); |
| 1208 | 1209 | /* wait for gpu to finish processing current batch */ |
| 1209 | − for (i = 0; i < RADEON_NUM_RINGS; i++) | |
| 1210 | − radeon_fence_wait_empty_locked(rdev, i); | |
| 1210 | + for (i = 0; i < RADEON_NUM_RINGS; i++) { | |
| 1211 | + r = radeon_fence_wait_empty_locked(rdev, i); | |
| 1212 | + if (r) { | |
| 1213 | + /* delay GPU reset to resume */ | |
| 1214 | + force_completion = true; | |
| 1215 | + } | |
| 1216 | + } | |
| 1217 | + if (force_completion) { | |
| 1218 | + radeon_fence_driver_force_completion(rdev); | |
| 1219 | + } | |
| 1211 | 1220 | mutex_unlock(&rdev->ring_lock); |
| 1212 | 1221 | |
| 1213 | 1222 | radeon_save_bios_scratch_regs(rdev); |
| @@ -1338,7 +1347,6 @@ retry: · 124 unmodified lines | ||
| 1338 | 1347 | } |
| 1339 | 1348 | |
| 1340 | 1349 | radeon_restore_bios_scratch_regs(rdev); |
| 1341 | − drm_helper_resume_force_mode(rdev->ddev); | |
| 1342 | 1350 | |
| 1343 | 1351 | if (!r) { |
| 1344 | 1352 | for (i = 0; i < RADEON_NUM_RINGS; ++i) { |
| @@ -1358,11 +1366,14 @@ retry: · 13 unmodified lines | ||
| 1358 | 1366 | } |
| 1359 | 1367 | } |
| 1360 | 1368 | } else { |
| 1369 | + radeon_fence_driver_force_completion(rdev); | |
| 1361 | 1370 | for (i = 0; i < RADEON_NUM_RINGS; ++i) { |
| 1362 | 1371 | kfree(ring_data[i]); |
| 1363 | 1372 | } |
| 1364 | 1373 | } |
| 1365 | 1374 | |
| 1375 | + drm_helper_resume_force_mode(rdev->ddev); | |
| 1376 | + | |
| 1366 | 1377 | ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); |
| 1367 | 1378 | if (r) { |
| 1368 | 1379 | /* bad news, how to tell it to userspace ? */ |
| @@ -68,9 +68,10 @@ · 67 unmodified lines | ||
| 68 | 68 | * 2.25.0 - eg+: new info request for num SE and num SH |
| 69 | 69 | * 2.26.0 - r600-eg: fix htile size computation |
| 70 | 70 | * 2.27.0 - r600-SI: Add CS ioctl support for async DMA |
| 71 | + * 2.28.0 - r600-eg: Add MEM_WRITE packet support | |
| 71 | 72 | */ |
| 72 | 73 | #define KMS_DRIVER_MAJOR 2 |
| 73 | −#define KMS_DRIVER_MINOR 27 | |
| 74 | +#define KMS_DRIVER_MINOR 28 | |
| 74 | 75 | #define KMS_DRIVER_PATCHLEVEL 0 |
| 75 | 76 | int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); |
| 76 | 77 | int radeon_driver_unload_kms(struct drm_device *dev); |
| @@ -609,26 +609,20 @@ int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring) · 608 unmodified lines | ||
| 609 | 609 | * Returns 0 if the fences have passed, error for all other cases. |
| 610 | 610 | * Caller must hold ring lock. |
| 611 | 611 | */ |
| 612 | −void radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring) | |
| 612 | +int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring) | |
| 613 | 613 | { |
| 614 | 614 | uint64_t seq = rdev->fence_drv[ring].sync_seq[ring]; |
| 615 | + int r; | |
| 615 | 616 | |
| 616 | − while(1) { | |
| 617 | − int r; | |
| 618 | − r = radeon_fence_wait_seq(rdev, seq, ring, false, false); | |
| 617 | + r = radeon_fence_wait_seq(rdev, seq, ring, false, false); | |
| 618 | + if (r) { | |
| 619 | 619 | if (r == -EDEADLK) { |
| 620 | − mutex_unlock(&rdev->ring_lock); | |
| 621 | − r = radeon_gpu_reset(rdev); | |
| 622 | − mutex_lock(&rdev->ring_lock); | |
| 623 | − if (!r) | |
| 624 | − continue; | |
| 625 | − } | |
| 626 | − if (r) { | |
| 627 | − dev_err(rdev->dev, "error waiting for ring to become" | |
| 628 | − " idle (%d)\n", r); | |
| 620 | + return -EDEADLK; | |
| 629 | 621 | } |
| 630 | − return; | |
| 622 | + dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%d)\n", | |
| 623 | + ring, r); | |
| 631 | 624 | } |
| 625 | + return 0; | |
| 632 | 626 | } |
| 633 | 627 | |
| 634 | 628 | /** |
| @@ -854,13 +848,17 @@ int radeon_fence_driver_init(struct radeon_device *rdev) · 219 unmodified lines | ||
| 854 | 848 | */ |
| 855 | 849 | void radeon_fence_driver_fini(struct radeon_device *rdev) |
| 856 | 850 | { |
| 857 | − int ring; | |
| 851 | + int ring, r; | |
| 858 | 852 | |
| 859 | 853 | mutex_lock(&rdev->ring_lock); |
| 860 | 854 | for (ring = 0; ring < RADEON_NUM_RINGS; ring++) { |
| 861 | 855 | if (!rdev->fence_drv[ring].initialized) |
| 862 | 856 | continue; |
| 863 | − radeon_fence_wait_empty_locked(rdev, ring); | |
| 857 | + r = radeon_fence_wait_empty_locked(rdev, ring); | |
| 858 | + if (r) { | |
| 859 | + /* no need to trigger GPU reset as we are unloading */ | |
| 860 | + radeon_fence_driver_force_completion(rdev); | |
| 861 | + } | |
| 864 | 862 | wake_up_all(&rdev->fence_queue); |
| 865 | 863 | radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg); |
| 866 | 864 | rdev->fence_drv[ring].initialized = false; |
| @@ -868,6 +866,25 @@ void radeon_fence_driver_fini(struct radeon_device *rdev) · 1 unmodified line | ||
| 868 | 866 | mutex_unlock(&rdev->ring_lock); |
| 869 | 867 | } |
| 870 | 868 | |
| 869 | +/** | |
| 870 | + * radeon_fence_driver_force_completion - force all fence waiter to complete | |
| 871 | + * | |
| 872 | + * @rdev: radeon device pointer | |
| 873 | + * | |
| 874 | + * In case of GPU reset failure make sure no process keep waiting on fence | |
| 875 | + * that will never complete. | |
| 876 | + */ | |
| 877 | +void radeon_fence_driver_force_completion(struct radeon_device *rdev) | |
| 878 | +{ | |
| 879 | + int ring; | |
| 880 | + | |
| 881 | + for (ring = 0; ring < RADEON_NUM_RINGS; ring++) { | |
| 882 | + if (!rdev->fence_drv[ring].initialized) | |
| 883 | + continue; | |
| 884 | + radeon_fence_write(rdev, rdev->fence_drv[ring].sync_seq[ring], ring); | |
| 885 | + } | |
| 886 | +} | |
| 887 | + | |
| 871 | 888 | |
| 872 | 889 | /* |
| 873 | 890 | * Fence debugfs |
| @@ -234,7 +234,7 @@ static void radeon_set_power_state(struct radeon_device *rdev) · 233 unmodified lines | ||
| 234 | 234 | |
| 235 | 235 | static void radeon_pm_set_clocks(struct radeon_device *rdev) |
| 236 | 236 | { |
| 237 | − int i; | |
| 237 | + int i, r; | |
| 238 | 238 | |
| 239 | 239 | /* no need to take locks, etc. if nothing's going to change */ |
| 240 | 240 | if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) && |
| @@ -248,8 +248,17 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev) · 7 unmodified lines | ||
| 248 | 248 | /* wait for the rings to drain */ |
| 249 | 249 | for (i = 0; i < RADEON_NUM_RINGS; i++) { |
| 250 | 250 | struct radeon_ring *ring = &rdev->ring[i]; |
| 251 | − if (ring->ready) | |
| 252 | − radeon_fence_wait_empty_locked(rdev, i); | |
| 251 | + if (!ring->ready) { | |
| 252 | + continue; | |
| 253 | + } | |
| 254 | + r = radeon_fence_wait_empty_locked(rdev, i); | |
| 255 | + if (r) { | |
| 256 | + /* needs a GPU reset dont reset here */ | |
| 257 | + mutex_unlock(&rdev->ring_lock); | |
| 258 | + up_write(&rdev->pm.mclk_lock); | |
| 259 | + mutex_unlock(&rdev->ddev->struct_mutex); | |
| 260 | + return; | |
| 261 | + } | |
| 253 | 262 | } |
| 254 | 263 | |
| 255 | 264 | radeon_unmap_vram_bos(rdev); |