diff options
| author | Alexandre Courbot <acourbot@nvidia.com> | 2015-04-27 04:25:11 -0400 |
|---|---|---|
| committer | Ben Skeggs <bskeggs@redhat.com> | 2015-07-27 04:56:08 -0400 |
| commit | 4a8cf4513dd4279d342eb41abdb9db65285732b3 (patch) | |
| tree | 9be14036678741f746ff90fdca0a41246079469d /drivers/gpu | |
| parent | 19bf09cecfec1891069f1d5353a0298debd98713 (diff) | |
drm/nouveau/gr/gf100: wait for GR idle after GO_IDLE bundle
After submitting a GO_IDLE bundle, one must wait for GR to effectively
be idle before submitting the next bundle. Failure to do so may result
in undefined behavior in some rare cases.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Reported-by: Kary Jin <karyj@nvidia.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
| -rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 37 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h | 1 |
2 files changed, 38 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 01efc2c96045..ca11ddb6ed46 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c | |||
| @@ -663,6 +663,37 @@ gf100_gr_zbc_init(struct gf100_gr_priv *priv) | |||
| 663 | gf100_gr_zbc_clear_depth(priv, index); | 663 | gf100_gr_zbc_clear_depth(priv, index); |
| 664 | } | 664 | } |
| 665 | 665 | ||
| 666 | /** | ||
| 667 | * Wait until GR goes idle. GR is considered idle if it is disabled by the | ||
| 668 | * MC (0x200) register, or GR is not busy and a context switch is not in | ||
| 669 | * progress. | ||
| 670 | */ | ||
| 671 | int | ||
| 672 | gf100_gr_wait_idle(struct gf100_gr_priv *priv) | ||
| 673 | { | ||
| 674 | unsigned long end_jiffies = jiffies + msecs_to_jiffies(2000); | ||
| 675 | bool gr_enabled, ctxsw_active, gr_busy; | ||
| 676 | |||
| 677 | do { | ||
| 678 | /* | ||
| 679 | * required to make sure FIFO_ENGINE_STATUS (0x2640) is | ||
| 680 | * up-to-date | ||
| 681 | */ | ||
| 682 | nv_rd32(priv, 0x400700); | ||
| 683 | |||
| 684 | gr_enabled = nv_rd32(priv, 0x200) & 0x1000; | ||
| 685 | ctxsw_active = nv_rd32(priv, 0x2640) & 0x8000; | ||
| 686 | gr_busy = nv_rd32(priv, 0x40060c) & 0x1; | ||
| 687 | |||
| 688 | if (!gr_enabled || (!gr_busy && !ctxsw_active)) | ||
| 689 | return 0; | ||
| 690 | } while (time_before(jiffies, end_jiffies)); | ||
| 691 | |||
| 692 | nv_error(priv, "wait for idle timeout (en: %d, ctxsw: %d, busy: %d)\n", | ||
| 693 | gr_enabled, ctxsw_active, gr_busy); | ||
| 694 | return -EAGAIN; | ||
| 695 | } | ||
| 696 | |||
| 666 | void | 697 | void |
| 667 | gf100_gr_mmio(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p) | 698 | gf100_gr_mmio(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p) |
| 668 | { | 699 | { |
| @@ -699,6 +730,12 @@ gf100_gr_icmd(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p) | |||
| 699 | 730 | ||
| 700 | while (addr < next) { | 731 | while (addr < next) { |
| 701 | nv_wr32(priv, 0x400200, addr); | 732 | nv_wr32(priv, 0x400200, addr); |
| 733 | /** | ||
| 734 | * Wait for GR to go idle after submitting a | ||
| 735 | * GO_IDLE bundle | ||
| 736 | */ | ||
| 737 | if ((addr & 0xffff) == 0xe100) | ||
| 738 | gf100_gr_wait_idle(priv); | ||
| 702 | nv_wait(priv, 0x400700, 0x00000004, 0x00000000); | 739 | nv_wait(priv, 0x400700, 0x00000004, 0x00000000); |
| 703 | addr += init->pitch; | 740 | addr += init->pitch; |
| 704 | } | 741 | } |
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h index 8af1a89eda84..c9533fdac4fc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h | |||
| @@ -181,6 +181,7 @@ struct gf100_gr_oclass { | |||
| 181 | int ppc_nr; | 181 | int ppc_nr; |
| 182 | }; | 182 | }; |
| 183 | 183 | ||
| 184 | int gf100_gr_wait_idle(struct gf100_gr_priv *); | ||
| 184 | void gf100_gr_mmio(struct gf100_gr_priv *, const struct gf100_gr_pack *); | 185 | void gf100_gr_mmio(struct gf100_gr_priv *, const struct gf100_gr_pack *); |
| 185 | void gf100_gr_icmd(struct gf100_gr_priv *, const struct gf100_gr_pack *); | 186 | void gf100_gr_icmd(struct gf100_gr_priv *, const struct gf100_gr_pack *); |
| 186 | void gf100_gr_mthd(struct gf100_gr_priv *, const struct gf100_gr_pack *); | 187 | void gf100_gr_mthd(struct gf100_gr_priv *, const struct gf100_gr_pack *); |
