summaryrefslogtreecommitdiff
path: root/nvkm/engine/fifo
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2014-02-23 23:50:50 +1000
committerBen Skeggs <bskeggs@redhat.com>2014-03-26 10:58:00 +1000
commitae059790e326b38a4dfbb4beb5de505c61322a56 (patch)
tree8071e92093d18e7102dd64a3c6bb38a4534886c2 /nvkm/engine/fifo
parent646f671ca5f1d27f831989ebc7a1f69913e7e7e8 (diff)
downloadnouveau-ae059790e326b38a4dfbb4beb5de505c61322a56.tar.gz
fifo/nve0: attempt to recover from engine ctxsw timeouts
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'nvkm/engine/fifo')
-rw-r--r--nvkm/engine/fifo/nve0.c44
1 files changed, 44 insertions, 0 deletions
diff --git a/nvkm/engine/fifo/nve0.c b/nvkm/engine/fifo/nve0.c
index 072998b19..e68368a37 100644
--- a/nvkm/engine/fifo/nve0.c
+++ b/nvkm/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