diff options
author | Dave Airlie <airlied@redhat.com> | 2014-06-03 21:59:31 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2014-06-03 21:59:31 -0400 |
commit | b15eb4ea1533b82762932d32cb220ddf75a09b3d (patch) | |
tree | 414207499aab787c1f0fdb73831e86a9254da679 | |
parent | 5536141dddc265882fa8ddf4366ad0ed85d08a68 (diff) |
Revert "drm/radeon: rework page flip handling v3"
This reverts commit 1aab5514ca9604e0263f658a067da0189c86a35b.
Apply the fixed up version instead.
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_display.c | 245 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_mode.h | 4 |
3 files changed, 115 insertions, 150 deletions
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index dd4da88b3ab1..2eaa3300099e 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
@@ -676,16 +676,14 @@ void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell); | |||
676 | * IRQS. | 676 | * IRQS. |
677 | */ | 677 | */ |
678 | 678 | ||
679 | struct radeon_flip_work { | 679 | struct radeon_unpin_work { |
680 | struct work_struct flip_work; | 680 | struct work_struct work; |
681 | struct work_struct unpin_work; | 681 | struct radeon_device *rdev; |
682 | struct radeon_device *rdev; | 682 | int crtc_id; |
683 | int crtc_id; | 683 | struct radeon_fence *fence; |
684 | struct drm_framebuffer *fb; | ||
685 | struct drm_pending_vblank_event *event; | 684 | struct drm_pending_vblank_event *event; |
686 | struct radeon_bo *old_rbo; | 685 | struct radeon_bo *old_rbo; |
687 | struct radeon_bo *new_rbo; | 686 | u64 new_crtc_base; |
688 | struct radeon_fence *fence; | ||
689 | }; | 687 | }; |
690 | 688 | ||
691 | struct r500_irq_stat_regs { | 689 | struct r500_irq_stat_regs { |
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 6b3de5ca5bc7..88e3cbe11dad 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c | |||
@@ -249,21 +249,16 @@ static void radeon_crtc_destroy(struct drm_crtc *crtc) | |||
249 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | 249 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
250 | 250 | ||
251 | drm_crtc_cleanup(crtc); | 251 | drm_crtc_cleanup(crtc); |
252 | destroy_workqueue(radeon_crtc->flip_queue); | ||
253 | kfree(radeon_crtc); | 252 | kfree(radeon_crtc); |
254 | } | 253 | } |
255 | 254 | ||
256 | /** | 255 | /* |
257 | * radeon_unpin_work_func - unpin old buffer object | 256 | * Handle unpin events outside the interrupt handler proper. |
258 | * | ||
259 | * @__work - kernel work item | ||
260 | * | ||
261 | * Unpin the old frame buffer object outside of the interrupt handler | ||
262 | */ | 257 | */ |
263 | static void radeon_unpin_work_func(struct work_struct *__work) | 258 | static void radeon_unpin_work_func(struct work_struct *__work) |
264 | { | 259 | { |
265 | struct radeon_flip_work *work = | 260 | struct radeon_unpin_work *work = |
266 | container_of(__work, struct radeon_flip_work, unpin_work); | 261 | container_of(__work, struct radeon_unpin_work, work); |
267 | int r; | 262 | int r; |
268 | 263 | ||
269 | /* unpin of the old buffer */ | 264 | /* unpin of the old buffer */ |
@@ -284,19 +279,30 @@ static void radeon_unpin_work_func(struct work_struct *__work) | |||
284 | void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id) | 279 | void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id) |
285 | { | 280 | { |
286 | struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; | 281 | struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; |
287 | struct radeon_flip_work *work; | 282 | struct radeon_unpin_work *work; |
288 | unsigned long flags; | 283 | unsigned long flags; |
289 | u32 update_pending; | 284 | u32 update_pending; |
290 | int vpos, hpos; | 285 | int vpos, hpos; |
291 | 286 | ||
292 | spin_lock_irqsave(&rdev->ddev->event_lock, flags); | 287 | spin_lock_irqsave(&rdev->ddev->event_lock, flags); |
293 | work = radeon_crtc->flip_work; | 288 | work = radeon_crtc->unpin_work; |
294 | if (work == NULL) { | 289 | if (work == NULL || |
290 | (work->fence && !radeon_fence_signaled(work->fence))) { | ||
295 | spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); | 291 | spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); |
296 | return; | 292 | return; |
297 | } | 293 | } |
298 | 294 | /* New pageflip, or just completion of a previous one? */ | |
299 | update_pending = radeon_page_flip_pending(rdev, crtc_id); | 295 | if (!radeon_crtc->deferred_flip_completion) { |
296 | /* do the flip (mmio) */ | ||
297 | radeon_page_flip(rdev, crtc_id, work->new_crtc_base); | ||
298 | update_pending = radeon_page_flip_pending(rdev, crtc_id); | ||
299 | } else { | ||
300 | /* This is just a completion of a flip queued in crtc | ||
301 | * at last invocation. Make sure we go directly to | ||
302 | * completion routine. | ||
303 | */ | ||
304 | update_pending = 0; | ||
305 | } | ||
300 | 306 | ||
301 | /* Has the pageflip already completed in crtc, or is it certain | 307 | /* Has the pageflip already completed in crtc, or is it certain |
302 | * to complete in this vblank? | 308 | * to complete in this vblank? |
@@ -314,9 +320,19 @@ void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id) | |||
314 | */ | 320 | */ |
315 | update_pending = 0; | 321 | update_pending = 0; |
316 | } | 322 | } |
317 | spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); | 323 | if (update_pending) { |
318 | if (!update_pending) | 324 | /* crtc didn't flip in this target vblank interval, |
325 | * but flip is pending in crtc. It will complete it | ||
326 | * in next vblank interval, so complete the flip at | ||
327 | * next vblank irq. | ||
328 | */ | ||
329 | radeon_crtc->deferred_flip_completion = 1; | ||
330 | spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); | ||
331 | return; | ||
332 | } else { | ||
333 | spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); | ||
319 | radeon_crtc_handle_flip(rdev, crtc_id); | 334 | radeon_crtc_handle_flip(rdev, crtc_id); |
335 | } | ||
320 | } | 336 | } |
321 | 337 | ||
322 | /** | 338 | /** |
@@ -330,7 +346,7 @@ void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id) | |||
330 | void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id) | 346 | void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id) |
331 | { | 347 | { |
332 | struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; | 348 | struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; |
333 | struct radeon_flip_work *work; | 349 | struct radeon_unpin_work *work; |
334 | unsigned long flags; | 350 | unsigned long flags; |
335 | 351 | ||
336 | /* this can happen at init */ | 352 | /* this can happen at init */ |
@@ -338,14 +354,15 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id) | |||
338 | return; | 354 | return; |
339 | 355 | ||
340 | spin_lock_irqsave(&rdev->ddev->event_lock, flags); | 356 | spin_lock_irqsave(&rdev->ddev->event_lock, flags); |
341 | work = radeon_crtc->flip_work; | 357 | work = radeon_crtc->unpin_work; |
342 | if (work == NULL) { | 358 | if (work == NULL) { |
343 | spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); | 359 | spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); |
344 | return; | 360 | return; |
345 | } | 361 | } |
346 | 362 | ||
347 | /* Pageflip completed. Clean up. */ | 363 | /* Pageflip (will be) certainly completed in this vblank. Clean up. */ |
348 | radeon_crtc->flip_work = NULL; | 364 | radeon_crtc->unpin_work = NULL; |
365 | radeon_crtc->deferred_flip_completion = 0; | ||
349 | 366 | ||
350 | /* wakeup userspace */ | 367 | /* wakeup userspace */ |
351 | if (work->event) | 368 | if (work->event) |
@@ -355,69 +372,83 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id) | |||
355 | 372 | ||
356 | radeon_fence_unref(&work->fence); | 373 | radeon_fence_unref(&work->fence); |
357 | radeon_irq_kms_pflip_irq_get(rdev, work->crtc_id); | 374 | radeon_irq_kms_pflip_irq_get(rdev, work->crtc_id); |
358 | queue_work(radeon_crtc->flip_queue, &work->unpin_work); | 375 | schedule_work(&work->work); |
359 | } | 376 | } |
360 | 377 | ||
361 | /** | 378 | static int radeon_crtc_page_flip(struct drm_crtc *crtc, |
362 | * radeon_flip_work_func - page flip framebuffer | 379 | struct drm_framebuffer *fb, |
363 | * | 380 | struct drm_pending_vblank_event *event, |
364 | * @work - kernel work item | 381 | uint32_t page_flip_flags) |
365 | * | ||
366 | * Wait for the buffer object to become idle and do the actual page flip | ||
367 | */ | ||
368 | static void radeon_flip_work_func(struct work_struct *__work) | ||
369 | { | 382 | { |
370 | struct radeon_flip_work *work = | 383 | struct drm_device *dev = crtc->dev; |
371 | container_of(__work, struct radeon_flip_work, flip_work); | 384 | struct radeon_device *rdev = dev->dev_private; |
372 | struct radeon_device *rdev = work->rdev; | 385 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); |
373 | struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[work->crtc_id]; | 386 | struct radeon_framebuffer *old_radeon_fb; |
387 | struct radeon_framebuffer *new_radeon_fb; | ||
388 | struct drm_gem_object *obj; | ||
389 | struct radeon_bo *rbo; | ||
390 | struct radeon_unpin_work *work; | ||
391 | unsigned long flags; | ||
392 | u32 tiling_flags, pitch_pixels; | ||
393 | u64 base; | ||
394 | int r; | ||
374 | 395 | ||
375 | struct drm_crtc *crtc = &radeon_crtc->base; | 396 | work = kzalloc(sizeof *work, GFP_KERNEL); |
376 | struct drm_framebuffer *fb = work->fb; | 397 | if (work == NULL) |
398 | return -ENOMEM; | ||
377 | 399 | ||
378 | uint32_t tiling_flags, pitch_pixels; | 400 | work->event = event; |
379 | uint64_t base; | 401 | work->rdev = rdev; |
402 | work->crtc_id = radeon_crtc->crtc_id; | ||
403 | old_radeon_fb = to_radeon_framebuffer(crtc->primary->fb); | ||
404 | new_radeon_fb = to_radeon_framebuffer(fb); | ||
405 | /* schedule unpin of the old buffer */ | ||
406 | obj = old_radeon_fb->obj; | ||
407 | /* take a reference to the old object */ | ||
408 | drm_gem_object_reference(obj); | ||
409 | rbo = gem_to_radeon_bo(obj); | ||
410 | work->old_rbo = rbo; | ||
411 | obj = new_radeon_fb->obj; | ||
412 | rbo = gem_to_radeon_bo(obj); | ||
380 | 413 | ||
381 | unsigned long flags; | 414 | spin_lock(&rbo->tbo.bdev->fence_lock); |
382 | int r; | 415 | if (rbo->tbo.sync_obj) |
416 | work->fence = radeon_fence_ref(rbo->tbo.sync_obj); | ||
417 | spin_unlock(&rbo->tbo.bdev->fence_lock); | ||
383 | 418 | ||
384 | down_read(&rdev->exclusive_lock); | 419 | INIT_WORK(&work->work, radeon_unpin_work_func); |
385 | while (work->fence) { | ||
386 | r = radeon_fence_wait(work->fence, false); | ||
387 | if (r == -EDEADLK) { | ||
388 | up_read(&rdev->exclusive_lock); | ||
389 | r = radeon_gpu_reset(rdev); | ||
390 | down_read(&rdev->exclusive_lock); | ||
391 | } | ||
392 | 420 | ||
393 | if (r) { | 421 | /* We borrow the event spin lock for protecting unpin_work */ |
394 | DRM_ERROR("failed to wait on page flip fence (%d)!\n", | 422 | spin_lock_irqsave(&dev->event_lock, flags); |
395 | r); | 423 | if (radeon_crtc->unpin_work) { |
396 | goto cleanup; | 424 | DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); |
397 | } else | 425 | r = -EBUSY; |
398 | radeon_fence_unref(&work->fence); | 426 | goto unlock_free; |
399 | } | 427 | } |
428 | radeon_crtc->unpin_work = work; | ||
429 | radeon_crtc->deferred_flip_completion = 0; | ||
430 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
400 | 431 | ||
401 | /* pin the new buffer */ | 432 | /* pin the new buffer */ |
402 | DRM_DEBUG_DRIVER("flip-ioctl() cur_fbo = %p, cur_bbo = %p\n", | 433 | DRM_DEBUG_DRIVER("flip-ioctl() cur_fbo = %p, cur_bbo = %p\n", |
403 | work->old_rbo, work->new_rbo); | 434 | work->old_rbo, rbo); |
404 | 435 | ||
405 | r = radeon_bo_reserve(work->new_rbo, false); | 436 | r = radeon_bo_reserve(rbo, false); |
406 | if (unlikely(r != 0)) { | 437 | if (unlikely(r != 0)) { |
407 | DRM_ERROR("failed to reserve new rbo buffer before flip\n"); | 438 | DRM_ERROR("failed to reserve new rbo buffer before flip\n"); |
408 | goto cleanup; | 439 | goto pflip_cleanup; |
409 | } | 440 | } |
410 | /* Only 27 bit offset for legacy CRTC */ | 441 | /* Only 27 bit offset for legacy CRTC */ |
411 | r = radeon_bo_pin_restricted(work->new_rbo, RADEON_GEM_DOMAIN_VRAM, | 442 | r = radeon_bo_pin_restricted(rbo, RADEON_GEM_DOMAIN_VRAM, |
412 | ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27, &base); | 443 | ASIC_IS_AVIVO(rdev) ? 0 : 1 << 27, &base); |
413 | if (unlikely(r != 0)) { | 444 | if (unlikely(r != 0)) { |
414 | radeon_bo_unreserve(work->new_rbo); | 445 | radeon_bo_unreserve(rbo); |
415 | r = -EINVAL; | 446 | r = -EINVAL; |
416 | DRM_ERROR("failed to pin new rbo buffer before flip\n"); | 447 | DRM_ERROR("failed to pin new rbo buffer before flip\n"); |
417 | goto cleanup; | 448 | goto pflip_cleanup; |
418 | } | 449 | } |
419 | radeon_bo_get_tiling_flags(work->new_rbo, &tiling_flags, NULL); | 450 | radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); |
420 | radeon_bo_unreserve(work->new_rbo); | 451 | radeon_bo_unreserve(rbo); |
421 | 452 | ||
422 | if (!ASIC_IS_AVIVO(rdev)) { | 453 | if (!ASIC_IS_AVIVO(rdev)) { |
423 | /* crtc offset is from display base addr not FB location */ | 454 | /* crtc offset is from display base addr not FB location */ |
@@ -455,91 +486,28 @@ static void radeon_flip_work_func(struct work_struct *__work) | |||
455 | base &= ~7; | 486 | base &= ~7; |
456 | } | 487 | } |
457 | 488 | ||
458 | /* We borrow the event spin lock for protecting flip_work */ | 489 | spin_lock_irqsave(&dev->event_lock, flags); |
459 | spin_lock_irqsave(&crtc->dev->event_lock, flags); | 490 | work->new_crtc_base = base; |
491 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
492 | |||
493 | /* update crtc fb */ | ||
494 | crtc->primary->fb = fb; | ||
460 | 495 | ||
461 | /* set the proper interrupt */ | 496 | /* set the proper interrupt */ |
462 | radeon_irq_kms_pflip_irq_get(rdev, radeon_crtc->crtc_id); | 497 | radeon_irq_kms_pflip_irq_get(rdev, radeon_crtc->crtc_id); |
463 | 498 | ||
464 | /* do the flip (mmio) */ | 499 | return 0; |
465 | radeon_page_flip(rdev, radeon_crtc->crtc_id, base); | ||
466 | |||
467 | spin_unlock_irqrestore(&crtc->dev->event_lock, flags); | ||
468 | up_read(&rdev->exclusive_lock); | ||
469 | |||
470 | return; | ||
471 | 500 | ||
472 | cleanup: | 501 | pflip_cleanup: |
473 | drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base); | 502 | spin_lock_irqsave(&dev->event_lock, flags); |
503 | radeon_crtc->unpin_work = NULL; | ||
504 | unlock_free: | ||
505 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
506 | drm_gem_object_unreference_unlocked(old_radeon_fb->obj); | ||
474 | radeon_fence_unref(&work->fence); | 507 | radeon_fence_unref(&work->fence); |
475 | kfree(work); | 508 | kfree(work); |
476 | up_read(&rdev->exclusive_lock); | ||
477 | } | ||
478 | |||
479 | static int radeon_crtc_page_flip(struct drm_crtc *crtc, | ||
480 | struct drm_framebuffer *fb, | ||
481 | struct drm_pending_vblank_event *event, | ||
482 | uint32_t page_flip_flags) | ||
483 | { | ||
484 | struct drm_device *dev = crtc->dev; | ||
485 | struct radeon_device *rdev = dev->dev_private; | ||
486 | struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); | ||
487 | struct radeon_framebuffer *old_radeon_fb; | ||
488 | struct radeon_framebuffer *new_radeon_fb; | ||
489 | struct drm_gem_object *obj; | ||
490 | struct radeon_flip_work *work; | ||
491 | unsigned long flags; | ||
492 | |||
493 | work = kzalloc(sizeof *work, GFP_KERNEL); | ||
494 | if (work == NULL) | ||
495 | return -ENOMEM; | ||
496 | |||
497 | INIT_WORK(&work->flip_work, radeon_flip_work_func); | ||
498 | INIT_WORK(&work->unpin_work, radeon_unpin_work_func); | ||
499 | 509 | ||
500 | work->rdev = rdev; | 510 | return r; |
501 | work->crtc_id = radeon_crtc->crtc_id; | ||
502 | work->fb = fb; | ||
503 | work->event = event; | ||
504 | |||
505 | /* schedule unpin of the old buffer */ | ||
506 | old_radeon_fb = to_radeon_framebuffer(crtc->primary->fb); | ||
507 | obj = old_radeon_fb->obj; | ||
508 | |||
509 | /* take a reference to the old object */ | ||
510 | drm_gem_object_reference(obj); | ||
511 | work->old_rbo = gem_to_radeon_bo(obj); | ||
512 | |||
513 | new_radeon_fb = to_radeon_framebuffer(fb); | ||
514 | obj = new_radeon_fb->obj; | ||
515 | work->new_rbo = gem_to_radeon_bo(obj); | ||
516 | |||
517 | spin_lock(&work->new_rbo->tbo.bdev->fence_lock); | ||
518 | if (work->new_rbo->tbo.sync_obj) | ||
519 | work->fence = radeon_fence_ref(work->new_rbo->tbo.sync_obj); | ||
520 | spin_unlock(&work->new_rbo->tbo.bdev->fence_lock); | ||
521 | |||
522 | /* update crtc fb */ | ||
523 | crtc->primary->fb = fb; | ||
524 | |||
525 | /* We borrow the event spin lock for protecting flip_work */ | ||
526 | spin_lock_irqsave(&crtc->dev->event_lock, flags); | ||
527 | |||
528 | if (radeon_crtc->flip_work) { | ||
529 | DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); | ||
530 | spin_unlock_irqrestore(&crtc->dev->event_lock, flags); | ||
531 | drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base); | ||
532 | radeon_fence_unref(&work->fence); | ||
533 | kfree(work); | ||
534 | return -EBUSY; | ||
535 | } | ||
536 | radeon_crtc->flip_work = work; | ||
537 | |||
538 | spin_unlock_irqrestore(&crtc->dev->event_lock, flags); | ||
539 | |||
540 | queue_work(radeon_crtc->flip_queue, &work->flip_work); | ||
541 | |||
542 | return 0; | ||
543 | } | 511 | } |
544 | 512 | ||
545 | static int | 513 | static int |
@@ -609,7 +577,6 @@ static void radeon_crtc_init(struct drm_device *dev, int index) | |||
609 | 577 | ||
610 | drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256); | 578 | drm_mode_crtc_set_gamma_size(&radeon_crtc->base, 256); |
611 | radeon_crtc->crtc_id = index; | 579 | radeon_crtc->crtc_id = index; |
612 | radeon_crtc->flip_queue = create_singlethread_workqueue("radeon-crtc"); | ||
613 | rdev->mode_info.crtcs[index] = radeon_crtc; | 580 | rdev->mode_info.crtcs[index] = radeon_crtc; |
614 | 581 | ||
615 | if (rdev->family >= CHIP_BONAIRE) { | 582 | if (rdev->family >= CHIP_BONAIRE) { |
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index ea72ad889a11..718be1a932ac 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h | |||
@@ -325,8 +325,8 @@ struct radeon_crtc { | |||
325 | struct drm_display_mode native_mode; | 325 | struct drm_display_mode native_mode; |
326 | int pll_id; | 326 | int pll_id; |
327 | /* page flipping */ | 327 | /* page flipping */ |
328 | struct workqueue_struct *flip_queue; | 328 | struct radeon_unpin_work *unpin_work; |
329 | struct radeon_flip_work *flip_work; | 329 | int deferred_flip_completion; |
330 | /* pll sharing */ | 330 | /* pll sharing */ |
331 | struct radeon_atom_ss ss; | 331 | struct radeon_atom_ss ss; |
332 | bool ss_enabled; | 332 | bool ss_enabled; |