Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/radeon: Track the status of a page flip more explicitly

This prevents a panic: radeon_crtc_handle_page_flip() could run before
radeon_flip_work_func(), triggering the BUG_ON() in drm_vblank_put().

Tested-by: Dieter Nützel <Dieter@nuetzel-hh.de>
Reviewed-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Michel Dänzer <michel.daenzer@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Michel Dänzer and committed by
Alex Deucher
a2b6d3b3 b0880e87

+21 -5
+14 -5
drivers/gpu/drm/radeon/radeon_display.c
··· 285 285 void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id) 286 286 { 287 287 struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; 288 - struct radeon_flip_work *work; 289 288 unsigned long flags; 290 289 u32 update_pending; 291 290 int vpos, hpos; ··· 294 295 return; 295 296 296 297 spin_lock_irqsave(&rdev->ddev->event_lock, flags); 297 - work = radeon_crtc->flip_work; 298 - if (work == NULL) { 298 + if (radeon_crtc->flip_status != RADEON_FLIP_SUBMITTED) { 299 + DRM_DEBUG_DRIVER("radeon_crtc->flip_status = %d != " 300 + "RADEON_FLIP_SUBMITTED(%d)\n", 301 + radeon_crtc->flip_status, 302 + RADEON_FLIP_SUBMITTED); 299 303 spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); 300 304 return; 301 305 } ··· 346 344 347 345 spin_lock_irqsave(&rdev->ddev->event_lock, flags); 348 346 work = radeon_crtc->flip_work; 349 - if (work == NULL) { 347 + if (radeon_crtc->flip_status != RADEON_FLIP_SUBMITTED) { 348 + DRM_DEBUG_DRIVER("radeon_crtc->flip_status = %d != " 349 + "RADEON_FLIP_SUBMITTED(%d)\n", 350 + radeon_crtc->flip_status, 351 + RADEON_FLIP_SUBMITTED); 350 352 spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); 351 353 return; 352 354 } 353 355 354 356 /* Pageflip completed. Clean up. */ 357 + radeon_crtc->flip_status = RADEON_FLIP_NONE; 355 358 radeon_crtc->flip_work = NULL; 356 359 357 360 /* wakeup userspace */ ··· 483 476 /* do the flip (mmio) */ 484 477 radeon_page_flip(rdev, radeon_crtc->crtc_id, base); 485 478 479 + radeon_crtc->flip_status = RADEON_FLIP_SUBMITTED; 486 480 spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 487 481 up_read(&rdev->exclusive_lock); 488 482 ··· 552 544 /* We borrow the event spin lock for protecting flip_work */ 553 545 spin_lock_irqsave(&crtc->dev->event_lock, flags); 554 546 555 - if (radeon_crtc->flip_work) { 547 + if (radeon_crtc->flip_status != RADEON_FLIP_NONE) { 556 548 DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); 557 549 spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 558 550 drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base); ··· 560 552 kfree(work); 561 553 return -EBUSY; 562 554 } 555 + radeon_crtc->flip_status = RADEON_FLIP_PENDING; 563 556 radeon_crtc->flip_work = work; 564 557 565 558 /* update crtc fb */
+7
drivers/gpu/drm/radeon/radeon_mode.h
··· 306 306 uint16_t amount; 307 307 }; 308 308 309 + enum radeon_flip_status { 310 + RADEON_FLIP_NONE, 311 + RADEON_FLIP_PENDING, 312 + RADEON_FLIP_SUBMITTED 313 + }; 314 + 309 315 struct radeon_crtc { 310 316 struct drm_crtc base; 311 317 int crtc_id; ··· 337 331 /* page flipping */ 338 332 struct workqueue_struct *flip_queue; 339 333 struct radeon_flip_work *flip_work; 334 + enum radeon_flip_status flip_status; 340 335 /* pll sharing */ 341 336 struct radeon_atom_ss ss; 342 337 bool ss_enabled;