diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2014-02-23 23:50:50 +1000 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-03-26 14:00:54 +1000 |
commit | 129dcca79c1e981635a349e1589d718f17b6f883 (patch) | |
tree | 8adea39073f535219a5a4c8bdd753e1f1872bceb /drivers/gpu/drm/nouveau/core/engine/fifo | |
parent | 98d1e317e5155898b979b44b31414c7281565654 (diff) | |
download | op-kernel-dev-129dcca79c1e981635a349e1589d718f17b6f883.zip op-kernel-dev-129dcca79c1e981635a349e1589d718f17b6f883.tar.gz |
drm/nve0/fifo: attempt to recover from engine ctxsw timeouts
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/core/engine/fifo')
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c index 072998b..e68368a3 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c @@ -416,6 +416,14 @@ nve0_fifo_engidx(struct nve0_fifo_priv *priv, u32 engn) return engn; } +static inline struct nouveau_engine * +nve0_fifo_engine(struct nve0_fifo_priv *priv, u32 engn) +{ + if (engn >= ARRAY_SIZE(fifo_engine)) + return NULL; + return nouveau_engine(priv, fifo_engine[engn].subdev); +} + static void nve0_fifo_recover_work(struct work_struct *work) { @@ -499,6 +507,34 @@ nve0_fifo_sched_reason[] = { }; static void +nve0_fifo_intr_sched_ctxsw(struct nve0_fifo_priv *priv) +{ + struct nouveau_engine *engine; + struct nve0_fifo_chan *chan; + u32 engn; + + for (engn = 0; engn < ARRAY_SIZE(fifo_engine); engn++) { + u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04)); + u32 busy = (stat & 0x80000000); + u32 next = (stat & 0x07ff0000) >> 16; + u32 chsw = (stat & 0x00008000); + u32 save = (stat & 0x00004000); + u32 load = (stat & 0x00002000); + u32 prev = (stat & 0x000007ff); + u32 chid = load ? next : prev; + (void)save; + + if (busy && chsw) { + if (!(chan = (void *)priv->base.channel[chid])) + continue; + if (!(engine = nve0_fifo_engine(priv, engn))) + continue; + nve0_fifo_recover(priv, engine, chan); + } + } +} + +static void nve0_fifo_intr_sched(struct nve0_fifo_priv *priv) { u32 intr = nv_rd32(priv, 0x00254c); @@ -511,6 +547,14 @@ nve0_fifo_intr_sched(struct nve0_fifo_priv *priv) snprintf(enunk, sizeof(enunk), "UNK%02x", code); nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk); + + switch (code) { + case 0x0a: + nve0_fifo_intr_sched_ctxsw(priv); + break; + default: + break; + } } static void |