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>
This commit is contained in:
Родитель
19bf09cecf
Коммит
4a8cf4513d
|
@ -663,6 +663,37 @@ gf100_gr_zbc_init(struct gf100_gr_priv *priv)
|
||||||
gf100_gr_zbc_clear_depth(priv, index);
|
gf100_gr_zbc_clear_depth(priv, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait until GR goes idle. GR is considered idle if it is disabled by the
|
||||||
|
* MC (0x200) register, or GR is not busy and a context switch is not in
|
||||||
|
* progress.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
gf100_gr_wait_idle(struct gf100_gr_priv *priv)
|
||||||
|
{
|
||||||
|
unsigned long end_jiffies = jiffies + msecs_to_jiffies(2000);
|
||||||
|
bool gr_enabled, ctxsw_active, gr_busy;
|
||||||
|
|
||||||
|
do {
|
||||||
|
/*
|
||||||
|
* required to make sure FIFO_ENGINE_STATUS (0x2640) is
|
||||||
|
* up-to-date
|
||||||
|
*/
|
||||||
|
nv_rd32(priv, 0x400700);
|
||||||
|
|
||||||
|
gr_enabled = nv_rd32(priv, 0x200) & 0x1000;
|
||||||
|
ctxsw_active = nv_rd32(priv, 0x2640) & 0x8000;
|
||||||
|
gr_busy = nv_rd32(priv, 0x40060c) & 0x1;
|
||||||
|
|
||||||
|
if (!gr_enabled || (!gr_busy && !ctxsw_active))
|
||||||
|
return 0;
|
||||||
|
} while (time_before(jiffies, end_jiffies));
|
||||||
|
|
||||||
|
nv_error(priv, "wait for idle timeout (en: %d, ctxsw: %d, busy: %d)\n",
|
||||||
|
gr_enabled, ctxsw_active, gr_busy);
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gf100_gr_mmio(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p)
|
gf100_gr_mmio(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p)
|
||||||
{
|
{
|
||||||
|
@ -699,6 +730,12 @@ gf100_gr_icmd(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p)
|
||||||
|
|
||||||
while (addr < next) {
|
while (addr < next) {
|
||||||
nv_wr32(priv, 0x400200, addr);
|
nv_wr32(priv, 0x400200, addr);
|
||||||
|
/**
|
||||||
|
* Wait for GR to go idle after submitting a
|
||||||
|
* GO_IDLE bundle
|
||||||
|
*/
|
||||||
|
if ((addr & 0xffff) == 0xe100)
|
||||||
|
gf100_gr_wait_idle(priv);
|
||||||
nv_wait(priv, 0x400700, 0x00000004, 0x00000000);
|
nv_wait(priv, 0x400700, 0x00000004, 0x00000000);
|
||||||
addr += init->pitch;
|
addr += init->pitch;
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,6 +181,7 @@ struct gf100_gr_oclass {
|
||||||
int ppc_nr;
|
int ppc_nr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int gf100_gr_wait_idle(struct gf100_gr_priv *);
|
||||||
void gf100_gr_mmio(struct gf100_gr_priv *, const struct gf100_gr_pack *);
|
void gf100_gr_mmio(struct gf100_gr_priv *, const struct gf100_gr_pack *);
|
||||||
void gf100_gr_icmd(struct gf100_gr_priv *, const struct gf100_gr_pack *);
|
void gf100_gr_icmd(struct gf100_gr_priv *, const struct gf100_gr_pack *);
|
||||||
void gf100_gr_mthd(struct gf100_gr_priv *, const struct gf100_gr_pack *);
|
void gf100_gr_mthd(struct gf100_gr_priv *, const struct gf100_gr_pack *);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче