aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2013-03-01 22:21:31 -0500
committerBen Skeggs <bskeggs@redhat.com>2013-03-03 20:46:35 -0500
commit9f9bdaaf07dee47f73a160e6e4c64f67ee26c1d7 (patch)
tree22566ba653d7300deb84ce15e5c879bdb9f7734f /drivers
parent42bed34c364786b3757f9d788d8ed39120e8f1b5 (diff)
drm/nv50-: prevent some races between modesetting and page flipping
nexuiz-glx + gnome-shell is able to trigger this a lot of the time. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c189
1 files changed, 106 insertions, 83 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index e26caf63db0c..87a5a56ed358 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -55,9 +55,9 @@
55 55
56/* offsets in shared sync bo of various structures */ 56/* offsets in shared sync bo of various structures */
57#define EVO_SYNC(c, o) ((c) * 0x0100 + (o)) 57#define EVO_SYNC(c, o) ((c) * 0x0100 + (o))
58#define EVO_MAST_NTFY EVO_SYNC( 0, 0x00) 58#define EVO_MAST_NTFY EVO_SYNC( 0, 0x00)
59#define EVO_FLIP_SEM0(c) EVO_SYNC((c), 0x00) 59#define EVO_FLIP_SEM0(c) EVO_SYNC((c) + 1, 0x00)
60#define EVO_FLIP_SEM1(c) EVO_SYNC((c), 0x10) 60#define EVO_FLIP_SEM1(c) EVO_SYNC((c) + 1, 0x10)
61 61
62#define EVO_CORE_HANDLE (0xd1500000) 62#define EVO_CORE_HANDLE (0xd1500000)
63#define EVO_CHAN_HANDLE(t,i) (0xd15c0000 | (((t) & 0x00ff) << 8) | (i)) 63#define EVO_CHAN_HANDLE(t,i) (0xd15c0000 | (((t) & 0x00ff) << 8) | (i))
@@ -341,10 +341,8 @@ struct nv50_curs {
341 341
342struct nv50_sync { 342struct nv50_sync {
343 struct nv50_dmac base; 343 struct nv50_dmac base;
344 struct { 344 u32 addr;
345 u32 offset; 345 u32 data;
346 u16 value;
347 } sem;
348}; 346};
349 347
350struct nv50_ovly { 348struct nv50_ovly {
@@ -471,13 +469,33 @@ nv50_display_crtc_sema(struct drm_device *dev, int crtc)
471 return nv50_disp(dev)->sync; 469 return nv50_disp(dev)->sync;
472} 470}
473 471
472struct nv50_display_flip {
473 struct nv50_disp *disp;
474 struct nv50_sync *chan;
475};
476
477static bool
478nv50_display_flip_wait(void *data)
479{
480 struct nv50_display_flip *flip = data;
481 if (nouveau_bo_rd32(flip->disp->sync, flip->chan->addr / 4) ==
482 flip->chan->data);
483 return true;
484 usleep_range(1, 2);
485 return false;
486}
487
474void 488void
475nv50_display_flip_stop(struct drm_crtc *crtc) 489nv50_display_flip_stop(struct drm_crtc *crtc)
476{ 490{
477 struct nv50_sync *sync = nv50_sync(crtc); 491 struct nouveau_device *device = nouveau_dev(crtc->dev);
492 struct nv50_display_flip flip = {
493 .disp = nv50_disp(crtc->dev),
494 .chan = nv50_sync(crtc),
495 };
478 u32 *push; 496 u32 *push;
479 497
480 push = evo_wait(sync, 8); 498 push = evo_wait(flip.chan, 8);
481 if (push) { 499 if (push) {
482 evo_mthd(push, 0x0084, 1); 500 evo_mthd(push, 0x0084, 1);
483 evo_data(push, 0x00000000); 501 evo_data(push, 0x00000000);
@@ -487,8 +505,10 @@ nv50_display_flip_stop(struct drm_crtc *crtc)
487 evo_data(push, 0x00000000); 505 evo_data(push, 0x00000000);
488 evo_mthd(push, 0x0080, 1); 506 evo_mthd(push, 0x0080, 1);
489 evo_data(push, 0x00000000); 507 evo_data(push, 0x00000000);
490 evo_kick(push, sync); 508 evo_kick(push, flip.chan);
491 } 509 }
510
511 nv_wait_cb(device, nv50_display_flip_wait, &flip);
492} 512}
493 513
494int 514int
@@ -496,11 +516,10 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
496 struct nouveau_channel *chan, u32 swap_interval) 516 struct nouveau_channel *chan, u32 swap_interval)
497{ 517{
498 struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); 518 struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
499 struct nv50_disp *disp = nv50_disp(crtc->dev);
500 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); 519 struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
501 struct nv50_sync *sync = nv50_sync(crtc); 520 struct nv50_sync *sync = nv50_sync(crtc);
521 int head = nv_crtc->index, ret;
502 u32 *push; 522 u32 *push;
503 int ret;
504 523
505 swap_interval <<= 4; 524 swap_interval <<= 4;
506 if (swap_interval == 0) 525 if (swap_interval == 0)
@@ -510,66 +529,64 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
510 if (unlikely(push == NULL)) 529 if (unlikely(push == NULL))
511 return -EBUSY; 530 return -EBUSY;
512 531
513 /* synchronise with the rendering channel, if necessary */ 532 if (chan && nv_mclass(chan->object) < NV84_CHANNEL_IND_CLASS) {
514 if (likely(chan)) { 533 ret = RING_SPACE(chan, 8);
515 if (nv_mclass(chan->object) < NV84_CHANNEL_IND_CLASS) { 534 if (ret)
516 ret = RING_SPACE(chan, 8); 535 return ret;
517 if (ret) 536
518 return ret; 537 BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2);
519 538 OUT_RING (chan, NvEvoSema0 + head);
520 BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 2); 539 OUT_RING (chan, sync->addr ^ 0x10);
521 OUT_RING (chan, NvEvoSema0 + nv_crtc->index); 540 BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1);
522 OUT_RING (chan, sync->sem.offset); 541 OUT_RING (chan, sync->data + 1);
523 BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_RELEASE, 1); 542 BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_OFFSET, 2);
524 OUT_RING (chan, 0xf00d0000 | sync->sem.value); 543 OUT_RING (chan, sync->addr);
525 BEGIN_NV04(chan, 0, NV11_SUBCHAN_SEMAPHORE_OFFSET, 2); 544 OUT_RING (chan, sync->data);
526 OUT_RING (chan, sync->sem.offset ^ 0x10); 545 } else
527 OUT_RING (chan, 0x74b1e000); 546 if (chan && nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) {
528 } else 547 u64 addr = nv84_fence_crtc(chan, head) + sync->addr;
529 if (nv_mclass(chan->object) < NVC0_CHANNEL_IND_CLASS) { 548 ret = RING_SPACE(chan, 12);
530 u64 offset = nv84_fence_crtc(chan, nv_crtc->index); 549 if (ret)
531 offset += sync->sem.offset; 550 return ret;
532 551
533 ret = RING_SPACE(chan, 12); 552 BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1);
534 if (ret) 553 OUT_RING (chan, chan->vram);
535 return ret; 554 BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
536 555 OUT_RING (chan, upper_32_bits(addr ^ 0x10));
537 BEGIN_NV04(chan, 0, NV11_SUBCHAN_DMA_SEMAPHORE, 1); 556 OUT_RING (chan, lower_32_bits(addr ^ 0x10));
538 OUT_RING (chan, chan->vram); 557 OUT_RING (chan, sync->data + 1);
539 BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); 558 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG);
540 OUT_RING (chan, upper_32_bits(offset)); 559 BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
541 OUT_RING (chan, lower_32_bits(offset)); 560 OUT_RING (chan, upper_32_bits(addr));
542 OUT_RING (chan, 0xf00d0000 | sync->sem.value); 561 OUT_RING (chan, lower_32_bits(addr));
543 OUT_RING (chan, 0x00000002); 562 OUT_RING (chan, sync->data);
544 BEGIN_NV04(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); 563 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL);
545 OUT_RING (chan, upper_32_bits(offset)); 564 } else
546 OUT_RING (chan, lower_32_bits(offset ^ 0x10)); 565 if (chan) {
547 OUT_RING (chan, 0x74b1e000); 566 u64 addr = nv84_fence_crtc(chan, head) + sync->addr;
548 OUT_RING (chan, 0x00000001); 567 ret = RING_SPACE(chan, 10);
549 } else { 568 if (ret)
550 u64 offset = nv84_fence_crtc(chan, nv_crtc->index); 569 return ret;
551 offset += sync->sem.offset; 570
552 571 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
553 ret = RING_SPACE(chan, 10); 572 OUT_RING (chan, upper_32_bits(addr ^ 0x10));
554 if (ret) 573 OUT_RING (chan, lower_32_bits(addr ^ 0x10));
555 return ret; 574 OUT_RING (chan, sync->data + 1);
556 575 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_WRITE_LONG |
557 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); 576 NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD);
558 OUT_RING (chan, upper_32_bits(offset)); 577 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4);
559 OUT_RING (chan, lower_32_bits(offset)); 578 OUT_RING (chan, upper_32_bits(addr));
560 OUT_RING (chan, 0xf00d0000 | sync->sem.value); 579 OUT_RING (chan, lower_32_bits(addr));
561 OUT_RING (chan, 0x00001002); 580 OUT_RING (chan, sync->data);
562 BEGIN_NVC0(chan, 0, NV84_SUBCHAN_SEMAPHORE_ADDRESS_HIGH, 4); 581 OUT_RING (chan, NV84_SUBCHAN_SEMAPHORE_TRIGGER_ACQUIRE_EQUAL |
563 OUT_RING (chan, upper_32_bits(offset)); 582 NVC0_SUBCHAN_SEMAPHORE_TRIGGER_YIELD);
564 OUT_RING (chan, lower_32_bits(offset ^ 0x10)); 583 }
565 OUT_RING (chan, 0x74b1e000);
566 OUT_RING (chan, 0x00001001);
567 }
568 584
585 if (chan) {
586 sync->addr ^= 0x10;
587 sync->data++;
569 FIRE_RING (chan); 588 FIRE_RING (chan);
570 } else { 589 } else {
571 nouveau_bo_wr32(disp->sync, sync->sem.offset / 4,
572 0xf00d0000 | sync->sem.value);
573 evo_sync(crtc->dev); 590 evo_sync(crtc->dev);
574 } 591 }
575 592
@@ -583,9 +600,9 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
583 evo_data(push, 0x40000000); 600 evo_data(push, 0x40000000);
584 } 601 }
585 evo_mthd(push, 0x0088, 4); 602 evo_mthd(push, 0x0088, 4);
586 evo_data(push, sync->sem.offset); 603 evo_data(push, sync->addr);
587 evo_data(push, 0xf00d0000 | sync->sem.value); 604 evo_data(push, sync->data++);
588 evo_data(push, 0x74b1e000); 605 evo_data(push, sync->data);
589 evo_data(push, NvEvoSync); 606 evo_data(push, NvEvoSync);
590 evo_mthd(push, 0x00a0, 2); 607 evo_mthd(push, 0x00a0, 2);
591 evo_data(push, 0x00000000); 608 evo_data(push, 0x00000000);
@@ -613,9 +630,6 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
613 evo_mthd(push, 0x0080, 1); 630 evo_mthd(push, 0x0080, 1);
614 evo_data(push, 0x00000000); 631 evo_data(push, 0x00000000);
615 evo_kick(push, sync); 632 evo_kick(push, sync);
616
617 sync->sem.offset ^= 0x10;
618 sync->sem.value++;
619 return 0; 633 return 0;
620} 634}
621 635
@@ -1387,7 +1401,8 @@ nv50_crtc_create(struct drm_device *dev, struct nouveau_object *core, int index)
1387 if (ret) 1401 if (ret)
1388 goto out; 1402 goto out;
1389 1403
1390 head->sync.sem.offset = EVO_SYNC(1 + index, 0x00); 1404 head->sync.addr = EVO_FLIP_SEM0(index);
1405 head->sync.data = 0x00000000;
1391 1406
1392 /* allocate overlay resources */ 1407 /* allocate overlay resources */
1393 ret = nv50_pioc_create(disp->core, NV50_DISP_OIMM_CLASS, index, 1408 ret = nv50_pioc_create(disp->core, NV50_DISP_OIMM_CLASS, index,
@@ -2120,15 +2135,23 @@ nv50_display_fini(struct drm_device *dev)
2120int 2135int
2121nv50_display_init(struct drm_device *dev) 2136nv50_display_init(struct drm_device *dev)
2122{ 2137{
2123 u32 *push = evo_wait(nv50_mast(dev), 32); 2138 struct nv50_disp *disp = nv50_disp(dev);
2124 if (push) { 2139 struct drm_crtc *crtc;
2125 evo_mthd(push, 0x0088, 1); 2140 u32 *push;
2126 evo_data(push, NvEvoSync); 2141
2127 evo_kick(push, nv50_mast(dev)); 2142 push = evo_wait(nv50_mast(dev), 32);
2128 return 0; 2143 if (!push)
2144 return -EBUSY;
2145
2146 list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
2147 struct nv50_sync *sync = nv50_sync(crtc);
2148 nouveau_bo_wr32(disp->sync, sync->addr / 4, sync->data);
2129 } 2149 }
2130 2150
2131 return -EBUSY; 2151 evo_mthd(push, 0x0088, 1);
2152 evo_data(push, NvEvoSync);
2153 evo_kick(push, nv50_mast(dev));
2154 return 0;
2132} 2155}
2133 2156
2134void 2157void