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 | |
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>
-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 *); |