diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index 10a2e7039a75..5a39e51d42d7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -193,6 +194,119 @@ gf100_fifo_recover(struct gf100_fifo *fifo, struct nvkm_engine *engine, nvkm_fifo_kevent(&fifo->base, chid); } +static const struct nvkm_enum +gf100_fifo_fault_engine[] = { + { 0x00, "PGRAPH", NULL, NVKM_ENGINE_GR }, + { 0x03, "PEEPHOLE", NULL, NVKM_ENGINE_IFB }, + { 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR }, + { 0x05, "BAR3", NULL, NVKM_SUBDEV_INSTMEM }, + { 0x07, "PFIFO", NULL, NVKM_ENGINE_FIFO }, + { 0x10, "PMSVLD", NULL, NVKM_ENGINE_MSVLD }, + { 0x11, "PMSPPP", NULL, NVKM_ENGINE_MSPPP }, + { 0x13, "PCOUNTER" }, + { 0x14, "PMSPDEC", NULL, NVKM_ENGINE_MSPDEC }, + { 0x15, "PCE0", NULL, NVKM_ENGINE_CE0 }, + { 0x16, "PCE1", NULL, NVKM_ENGINE_CE1 }, + { 0x17, "PMU" }, + {} +}; + +static const struct nvkm_enum +gf100_fifo_fault_reason[] = { + { 0x00, "PT_NOT_PRESENT" }, + { 0x01, "PT_TOO_SHORT" }, + { 0x02, "PAGE_NOT_PRESENT" }, + { 0x03, "VM_LIMIT_EXCEEDED" }, + { 0x04, "NO_CHANNEL" }, + { 0x05, "PAGE_SYSTEM_ONLY" }, + { 0x06, "PAGE_READ_ONLY" }, + { 0x0a, "COMPRESSED_SYSRAM" }, + { 0x0c, "INVALID_STORAGE_TYPE" }, + {} +}; + +static const struct nvkm_enum +gf100_fifo_fault_hubclient[] = { + { 0x01, "PCOPY0" }, + { 0x02, "PCOPY1" }, + { 0x04, "DISPATCH" }, + { 0x05, "CTXCTL" }, + { 0x06, "PFIFO" }, + { 0x07, "BAR_READ" }, + { 0x08, "BAR_WRITE" }, + { 0x0b, "PVP" }, + { 0x0c, "PMSPPP" }, + { 0x0d, "PMSVLD" }, + { 0x11, "PCOUNTER" }, + { 0x12, "PMU" }, + { 0x14, "CCACHE" }, + { 0x15, "CCACHE_POST" }, + {} +}; + +static const struct nvkm_enum +gf100_fifo_fault_gpcclient[] = { + { 0x01, "TEX" }, + { 0x0c, "ESETUP" }, + { 0x0e, "CTXCTL" }, + { 0x0f, "PROP" }, + {} +}; + +static void +gf100_fifo_fault(struct nvkm_fifo *base, struct nvkm_fault_data *info) +{ + struct gf100_fifo *fifo = gf100_fifo(base); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + const struct nvkm_enum *er, *eu, *ec; + struct nvkm_engine *engine = NULL; + struct nvkm_fifo_chan *chan; + unsigned long flags; + char gpcid[8] = ""; + + er = nvkm_enum_find(gf100_fifo_fault_reason, info->reason); + eu = nvkm_enum_find(gf100_fifo_fault_engine, info->engine); + if (info->hub) { + ec = nvkm_enum_find(gf100_fifo_fault_hubclient, info->client); + } else { + ec = nvkm_enum_find(gf100_fifo_fault_gpcclient, info->client); + snprintf(gpcid, sizeof(gpcid), "GPC%d/", info->gpc); + } + + if (eu && eu->data2) { + switch (eu->data2) { + case NVKM_SUBDEV_BAR: + nvkm_bar_bar1_reset(device); + break; + case NVKM_SUBDEV_INSTMEM: + nvkm_bar_bar2_reset(device); + break; + case NVKM_ENGINE_IFB: + nvkm_mask(device, 0x001718, 0x00000000, 0x00000000); + break; + default: + engine = nvkm_device_engine(device, eu->data2); + break; + } + } + + chan = nvkm_fifo_chan_inst(&fifo->base, info->inst, &flags); + + nvkm_error(subdev, + "%s fault at %010llx engine %02x [%s] client %02x [%s%s] " + "reason %02x [%s] on channel %d [%010llx %s]\n", + info->access ? "write" : "read", info->addr, + info->engine, eu ? eu->name : "", + info->client, gpcid, ec ? ec->name : "", + info->reason, er ? er->name : "", chan ? chan->chid : -1, + info->inst, chan ? chan->object.client->name : "unknown"); + + if (engine && chan) + gf100_fifo_recover(fifo, engine, (void *)chan); + nvkm_fifo_chan_put(&fifo->base, flags, &chan); +} + static const struct nvkm_enum gf100_fifo_sched_reason[] = { { 0x0a, "CTXSW_TIMEOUT" }, @@ -255,125 +369,28 @@ gf100_fifo_intr_sched(struct gf100_fifo *fifo) } } -static const struct nvkm_enum -gf100_fifo_fault_engine[] = { - { 0x00, "PGRAPH", NULL, NVKM_ENGINE_GR }, - { 0x03, "PEEPHOLE", NULL, NVKM_ENGINE_IFB }, - { 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR }, - { 0x05, "BAR3", NULL, NVKM_SUBDEV_INSTMEM }, - { 0x07, "PFIFO", NULL, NVKM_ENGINE_FIFO }, - { 0x10, "PMSVLD", NULL, NVKM_ENGINE_MSVLD }, - { 0x11, "PMSPPP", NULL, NVKM_ENGINE_MSPPP }, - { 0x13, "PCOUNTER" }, - { 0x14, "PMSPDEC", NULL, NVKM_ENGINE_MSPDEC }, - { 0x15, "PCE0", NULL, NVKM_ENGINE_CE0 }, - { 0x16, "PCE1", NULL, NVKM_ENGINE_CE1 }, - { 0x17, "PMU" }, - {} -}; - -static const struct nvkm_enum -gf100_fifo_fault_reason[] = { - { 0x00, "PT_NOT_PRESENT" }, - { 0x01, "PT_TOO_SHORT" }, - { 0x02, "PAGE_NOT_PRESENT" }, - { 0x03, "VM_LIMIT_EXCEEDED" }, - { 0x04, "NO_CHANNEL" }, - { 0x05, "PAGE_SYSTEM_ONLY" }, - { 0x06, "PAGE_READ_ONLY" }, - { 0x0a, "COMPRESSED_SYSRAM" }, - { 0x0c, "INVALID_STORAGE_TYPE" }, - {} -}; - -static const struct nvkm_enum -gf100_fifo_fault_hubclient[] = { - { 0x01, "PCOPY0" }, - { 0x02, "PCOPY1" }, - { 0x04, "DISPATCH" }, - { 0x05, "CTXCTL" }, - { 0x06, "PFIFO" }, - { 0x07, "BAR_READ" }, - { 0x08, "BAR_WRITE" }, - { 0x0b, "PVP" }, - { 0x0c, "PMSPPP" }, - { 0x0d, "PMSVLD" }, - { 0x11, "PCOUNTER" }, - { 0x12, "PMU" }, - { 0x14, "CCACHE" }, - { 0x15, "CCACHE_POST" }, - {} -}; - -static const struct nvkm_enum -gf100_fifo_fault_gpcclient[] = { - { 0x01, "TEX" }, - { 0x0c, "ESETUP" }, - { 0x0e, "CTXCTL" }, - { 0x0f, "PROP" }, - {} -}; - -static void -gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit) +void +gf100_fifo_intr_fault(struct nvkm_fifo *fifo, int unit) { - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; + struct nvkm_device *device = fifo->engine.subdev.device; u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10)); u32 valo = nvkm_rd32(device, 0x002804 + (unit * 0x10)); u32 vahi = nvkm_rd32(device, 0x002808 + (unit * 0x10)); - u32 stat = nvkm_rd32(device, 0x00280c + (unit * 0x10)); - u32 gpc = (stat & 0x1f000000) >> 24; - u32 client = (stat & 0x00001f00) >> 8; - u32 write = (stat & 0x00000080); - u32 hub = (stat & 0x00000040); - u32 reason = (stat & 0x0000000f); - const struct nvkm_enum *er, *eu, *ec; - struct nvkm_engine *engine = NULL; - struct nvkm_fifo_chan *chan; - unsigned long flags; - char gpcid[8] = ""; + u32 type = nvkm_rd32(device, 0x00280c + (unit * 0x10)); + struct nvkm_fault_data info; - er = nvkm_enum_find(gf100_fifo_fault_reason, reason); - eu = nvkm_enum_find(gf100_fifo_fault_engine, unit); - if (hub) { - ec = nvkm_enum_find(gf100_fifo_fault_hubclient, client); - } else { - ec = nvkm_enum_find(gf100_fifo_fault_gpcclient, client); - snprintf(gpcid, sizeof(gpcid), "GPC%d/", gpc); - } + info.inst = (u64)inst << 12; + info.addr = ((u64)vahi << 32) | valo; + info.time = 0; + info.engine = unit; + info.valid = 1; + info.gpc = (type & 0x1f000000) >> 24; + info.client = (type & 0x00001f00) >> 8; + info.access = (type & 0x00000080) >> 7; + info.hub = (type & 0x00000040) >> 6; + info.reason = (type & 0x0000000f); - if (eu && eu->data2) { - switch (eu->data2) { - case NVKM_SUBDEV_BAR: - nvkm_bar_bar1_reset(device); - break; - case NVKM_SUBDEV_INSTMEM: - nvkm_bar_bar2_reset(device); - break; - case NVKM_ENGINE_IFB: - nvkm_mask(device, 0x001718, 0x00000000, 0x00000000); - break; - default: - engine = nvkm_device_engine(device, eu->data2); - break; - } - } - - chan = nvkm_fifo_chan_inst(&fifo->base, (u64)inst << 12, &flags); - - nvkm_error(subdev, - "%s fault at %010llx engine %02x [%s] client %02x [%s%s] " - "reason %02x [%s] on channel %d [%010llx %s]\n", - write ? "write" : "read", (u64)vahi << 32 | valo, - unit, eu ? eu->name : "", client, gpcid, ec ? ec->name : "", - reason, er ? er->name : "", chan ? chan->chid : -1, - (u64)inst << 12, - chan ? chan->object.client->name : "unknown"); - - if (engine && chan) - gf100_fifo_recover(fifo, engine, (void *)chan); - nvkm_fifo_chan_put(&fifo->base, flags, &chan); + nvkm_fifo_fault(fifo, &info); } static const struct nvkm_bitfield @@ -518,7 +535,7 @@ gf100_fifo_intr(struct nvkm_fifo *base) u32 mask = nvkm_rd32(device, 0x00259c); while (mask) { u32 unit = __ffs(mask); - gf100_fifo_intr_fault(fifo, unit); + gf100_fifo_intr_fault(&fifo->base, unit); nvkm_wr32(device, 0x00259c, (1 << unit)); mask &= ~(1 << unit); } @@ -655,6 +672,7 @@ gf100_fifo = { .init = gf100_fifo_init, .fini = gf100_fifo_fini, .intr = gf100_fifo_intr, + .fault = gf100_fifo_fault, .uevent_init = gf100_fifo_uevent_init, .uevent_fini = gf100_fifo_uevent_fini, .chan = { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 1053fe796466..ac9abcc1470a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -666,7 +666,7 @@ gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit) info.client = (type & 0x00001f00) >> 8; info.access = (type & 0x00000080) >> 7; info.hub = (type & 0x00000040) >> 6; - info.reason = (type & 0x000000ff); + info.reason = (type & 0x0000001f); nvkm_fifo_fault(&fifo->base, &info); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h index c66f5370b21f..0ef8baab513e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h @@ -37,4 +37,6 @@ struct nvkm_fifo_func { void nv04_fifo_intr(struct nvkm_fifo *); void nv04_fifo_pause(struct nvkm_fifo *, unsigned long *); void nv04_fifo_start(struct nvkm_fifo *, unsigned long *); + +void gf100_fifo_intr_fault(struct nvkm_fifo *, int); #endif