Commit e43c872c authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau/fifo: merge mmu fault handlers together



After updating GF100 implementation from the GK104/TU102 ones, and using
the new runlist/engine topology info, all three handlers become (almost)
identical.

- there's a temporary kludge to call through to the HW-specific recovery
- engine fault mapping info determined at load time, not on every fault

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
Reviewed-by: default avatarLyude Paul <lyude@redhat.com>
parent 923f1ff5
Loading
Loading
Loading
Loading
+73 −37
Original line number Diff line number Diff line
@@ -295,7 +295,7 @@ gf100_fifo_recover(struct gf100_fifo *fifo, struct nvkm_engine *engine,
}

static const struct nvkm_enum
gf100_fifo_fault_engine[] = {
gf100_fifo_mmu_fault_engine[] = {
	{ 0x00, "PGRAPH", NULL, NVKM_ENGINE_GR },
	{ 0x03, "PEEPHOLE", NULL, NVKM_ENGINE_IFB },
	{ 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR },
@@ -312,7 +312,7 @@ gf100_fifo_fault_engine[] = {
};

static const struct nvkm_enum
gf100_fifo_fault_reason[] = {
gf100_fifo_mmu_fault_reason[] = {
	{ 0x00, "PT_NOT_PRESENT" },
	{ 0x01, "PT_TOO_SHORT" },
	{ 0x02, "PAGE_NOT_PRESENT" },
@@ -326,7 +326,7 @@ gf100_fifo_fault_reason[] = {
};

static const struct nvkm_enum
gf100_fifo_fault_hubclient[] = {
gf100_fifo_mmu_fault_hubclient[] = {
	{ 0x01, "PCOPY0" },
	{ 0x02, "PCOPY1" },
	{ 0x04, "DISPATCH" },
@@ -345,7 +345,7 @@ gf100_fifo_fault_hubclient[] = {
};

static const struct nvkm_enum
gf100_fifo_fault_gpcclient[] = {
gf100_fifo_mmu_fault_gpcclient[] = {
	{ 0x01, "TEX" },
	{ 0x0c, "ESETUP" },
	{ 0x0e, "CTXCTL" },
@@ -353,29 +353,48 @@ gf100_fifo_fault_gpcclient[] = {
	{}
};

static void
gf100_fifo_fault(struct nvkm_fifo *base, struct nvkm_fault_data *info)
const struct nvkm_enum
gf100_fifo_mmu_fault_access[] = {
	{ 0x00, "READ" },
	{ 0x01, "WRITE" },
	{}
};

void
gf100_fifo_mmu_fault_recover(struct nvkm_fifo *fifo, struct nvkm_fault_data *info)
{
	struct gf100_fifo *fifo = gf100_fifo(base);
	struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
	struct nvkm_subdev *subdev = &fifo->engine.subdev;
	struct nvkm_device *device = subdev->device;
	const struct nvkm_enum *er, *eu, *ec;
	const struct nvkm_enum *er, *ee, *ec, *ea;
	struct nvkm_engine *engine = NULL;
	struct nvkm_fifo_chan *chan;
	struct nvkm_runl *runl;
	struct nvkm_engn *engn;
	unsigned long flags;
	char gpcid[8] = "";
	char ct[8] = "HUB/";

	/* Lookup engine by MMU fault ID. */
	nvkm_runl_foreach(runl, fifo) {
		engn = nvkm_runl_find_engn(engn, runl, engn->fault == info->engine);
		if (engn) {
			engine = engn->engine;
			break;
		}
	}

	er = nvkm_enum_find(gf100_fifo_fault_reason, info->reason);
	eu = nvkm_enum_find(gf100_fifo_fault_engine, info->engine);
	er = nvkm_enum_find(fifo->func->mmu_fault->reason, info->reason);
	ee = nvkm_enum_find(fifo->func->mmu_fault->engine, info->engine);
	if (info->hub) {
		ec = nvkm_enum_find(gf100_fifo_fault_hubclient, info->client);
		ec = nvkm_enum_find(fifo->func->mmu_fault->hubclient, info->client);
	} else {
		ec = nvkm_enum_find(gf100_fifo_fault_gpcclient, info->client);
		snprintf(gpcid, sizeof(gpcid), "GPC%d/", info->gpc);
		ec = nvkm_enum_find(fifo->func->mmu_fault->gpcclient, info->client);
		snprintf(ct, sizeof(ct), "GPC%d/", info->gpc);
	}
	ea = nvkm_enum_find(fifo->func->mmu_fault->access, info->access);

	if (eu && eu->data2) {
		switch (eu->data2) {
	/* Handle BAR faults. */
	if (ee && ee->data2) {
		switch (ee->data2) {
		case NVKM_SUBDEV_BAR:
			nvkm_bar_bar1_reset(device);
			break;
@@ -386,30 +405,39 @@ gf100_fifo_fault(struct nvkm_fifo *base, struct nvkm_fault_data *info)
			nvkm_mask(device, 0x001718, 0x00000000, 0x00000000);
			break;
		default:
			engine = nvkm_device_engine(device, eu->data2, eu->inst);
			break;
		}
	}

	chan = nvkm_fifo_chan_inst(&fifo->base, info->inst, &flags);
	chan = nvkm_fifo_chan_inst(fifo, 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");

		   "fault %02x [%s] at %016llx engine %02x [%s] client %02x "
		   "[%s%s] reason %02x [%s] on channel %d [%010llx %s]\n",
		   info->access, ea ? ea->name : "", info->addr,
		   info->engine, ee ? ee->name : engine ? engine->subdev.name : "",
		   info->client, ct, ec ? ec->name : "",
		   info->reason, er ? er->name : "",
		   chan ? chan->id : -1, info->inst, chan ? chan->name : "unknown");

	/* Handle host/engine faults. */
	if (fifo->func->recover_chan && chan)
		fifo->func->recover_chan(fifo, chan->id);
	else
	if (engine && chan)
		gf100_fifo_recover(fifo, engine, (void *)chan);
	nvkm_fifo_chan_put(&fifo->base, flags, &chan);
		gf100_fifo_recover(gf100_fifo(fifo), engine, (void *)chan);

	nvkm_fifo_chan_put(fifo, flags, &chan);
}

static const struct nvkm_fifo_func_mmu_fault
gf100_fifo_mmu_fault = {
	.recover = gf100_fifo_fault,
	.recover = gf100_fifo_mmu_fault_recover,
	.access = gf100_fifo_mmu_fault_access,
	.engine = gf100_fifo_mmu_fault_engine,
	.reason = gf100_fifo_mmu_fault_reason,
	.hubclient = gf100_fifo_mmu_fault_hubclient,
	.gpcclient = gf100_fifo_mmu_fault_gpcclient,
};

static const struct nvkm_enum
@@ -498,6 +526,19 @@ gf100_fifo_intr_mmu_fault_unit(struct nvkm_fifo *fifo, int unit)
	nvkm_fifo_fault(fifo, &info);
}

void
gf100_fifo_intr_mmu_fault(struct nvkm_fifo *fifo)
{
	struct nvkm_device *device = fifo->engine.subdev.device;
	unsigned long mask = nvkm_rd32(device, 0x00259c);
	int unit;

	for_each_set_bit(unit, &mask, 32) {
		fifo->func->intr_mmu_fault_unit(fifo, unit);
		nvkm_wr32(device, 0x00259c, BIT(unit));
	}
}

bool
gf100_fifo_intr_pbdma(struct nvkm_fifo *fifo)
{
@@ -609,13 +650,7 @@ gf100_fifo_intr(struct nvkm_inth *inth)
	}

	if (stat & 0x10000000) {
		u32 mask = nvkm_rd32(device, 0x00259c);
		while (mask) {
			u32 unit = __ffs(mask);
			gf100_fifo_intr_mmu_fault_unit(fifo, unit);
			nvkm_wr32(device, 0x00259c, (1 << unit));
			mask &= ~(1 << unit);
		}
		gf100_fifo_intr_mmu_fault(fifo);
		stat &= ~0x10000000;
	}

@@ -783,6 +818,7 @@ gf100_fifo = {
	.init_pbdmas = gf100_fifo_init_pbdmas,
	.fini = gf100_fifo_fini,
	.intr = gf100_fifo_intr,
	.intr_mmu_fault_unit = gf100_fifo_intr_mmu_fault_unit,
	.mmu_fault = &gf100_fifo_mmu_fault,
	.engine_id = gf100_fifo_engine_id,
	.nonstall = &gf100_fifo_nonstall,
+21 −116
Original line number Diff line number Diff line
@@ -30,10 +30,8 @@
#include "cgrp.h"
#include "changk104.h"

#include <core/client.h>
#include <core/gpuobj.h>
#include <subdev/bar.h>
#include <subdev/fault.h>
#include <subdev/mc.h>
#include <subdev/timer.h>
#include <subdev/top.h>
@@ -474,7 +472,7 @@ gk104_fifo_recover_engn(struct gk104_fifo *fifo, int engn)
	if (!status.faulted && engine) {
		mmui = nvkm_top_fault_id(device, engine->subdev.type, engine->subdev.inst);
		if (mmui < 0) {
			const struct nvkm_enum *en = fifo->func->fault.engine;
			const struct nvkm_enum *en = fifo->func->mmu_fault->engine;
			for (; en && en->name; en++) {
				if (en->data2 == engine->subdev.type &&
				    en->inst  == engine->subdev.inst) {
@@ -512,15 +510,8 @@ gk104_fifo_recover_engn(struct gk104_fifo *fifo, int engn)
	schedule_work(&fifo->recover.work);
}

const struct nvkm_enum
gk104_fifo_fault_access[] = {
	{ 0x0, "READ" },
	{ 0x1, "WRITE" },
	{}
};

const struct nvkm_enum
gk104_fifo_fault_engine[] = {
static const struct nvkm_enum
gk104_fifo_mmu_fault_engine[] = {
	{ 0x00, "GR", NULL, NVKM_ENGINE_GR },
	{ 0x01, "DISPLAY" },
	{ 0x02, "CAPTURE" },
@@ -528,14 +519,14 @@ gk104_fifo_fault_engine[] = {
	{ 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR },
	{ 0x05, "BAR2", NULL, NVKM_SUBDEV_INSTMEM },
	{ 0x06, "SCHED" },
	{ 0x07, "HOST0", NULL, NVKM_ENGINE_FIFO },
	{ 0x08, "HOST1", NULL, NVKM_ENGINE_FIFO },
	{ 0x09, "HOST2", NULL, NVKM_ENGINE_FIFO },
	{ 0x0a, "HOST3", NULL, NVKM_ENGINE_FIFO },
	{ 0x0b, "HOST4", NULL, NVKM_ENGINE_FIFO },
	{ 0x0c, "HOST5", NULL, NVKM_ENGINE_FIFO },
	{ 0x0d, "HOST6", NULL, NVKM_ENGINE_FIFO },
	{ 0x0e, "HOST7", NULL, NVKM_ENGINE_FIFO },
	{ 0x07, "HOST0" },
	{ 0x08, "HOST1" },
	{ 0x09, "HOST2" },
	{ 0x0a, "HOST3" },
	{ 0x0b, "HOST4" },
	{ 0x0c, "HOST5" },
	{ 0x0d, "HOST6" },
	{ 0x0e, "HOST7" },
	{ 0x0f, "HOSTSR" },
	{ 0x10, "MSVLD", NULL, NVKM_ENGINE_MSVLD },
	{ 0x11, "MSPPP", NULL, NVKM_ENGINE_MSPPP },
@@ -551,7 +542,7 @@ gk104_fifo_fault_engine[] = {
};

const struct nvkm_enum
gk104_fifo_fault_reason[] = {
gk104_fifo_mmu_fault_reason[] = {
	{ 0x00, "PDE" },
	{ 0x01, "PDE_SIZE" },
	{ 0x02, "PTE" },
@@ -572,7 +563,7 @@ gk104_fifo_fault_reason[] = {
};

const struct nvkm_enum
gk104_fifo_fault_hubclient[] = {
gk104_fifo_mmu_fault_hubclient[] = {
	{ 0x00, "VIP" },
	{ 0x01, "CE0" },
	{ 0x02, "CE1" },
@@ -609,7 +600,7 @@ gk104_fifo_fault_hubclient[] = {
};

const struct nvkm_enum
gk104_fifo_fault_gpcclient[] = {
gk104_fifo_mmu_fault_gpcclient[] = {
	{ 0x00, "L1_0" }, { 0x01, "T1_0" }, { 0x02, "PE_0" },
	{ 0x03, "L1_1" }, { 0x04, "T1_1" }, { 0x05, "PE_1" },
	{ 0x06, "L1_2" }, { 0x07, "T1_2" }, { 0x08, "PE_2" },
@@ -634,89 +625,14 @@ gk104_fifo_fault_gpcclient[] = {
	{}
};

void
gk104_fifo_fault(struct nvkm_fifo *base, struct nvkm_fault_data *info)
{
	struct gk104_fifo *fifo = gk104_fifo(base);
	struct nvkm_subdev *subdev = &fifo->base.engine.subdev;
	struct nvkm_device *device = subdev->device;
	const struct nvkm_enum *er, *ee, *ec, *ea;
	struct nvkm_engine *engine = NULL;
	struct nvkm_fifo_chan *chan;
	unsigned long flags;
	const char *en = "";
	char ct[8] = "HUB/";

	er = nvkm_enum_find(fifo->func->fault.reason, info->reason);
	ee = nvkm_enum_find(fifo->func->fault.engine, info->engine);
	if (info->hub) {
		ec = nvkm_enum_find(fifo->func->fault.hubclient, info->client);
	} else {
		ec = nvkm_enum_find(fifo->func->fault.gpcclient, info->client);
		snprintf(ct, sizeof(ct), "GPC%d/", info->gpc);
	}
	ea = nvkm_enum_find(fifo->func->fault.access, info->access);

	if (ee && ee->data2) {
		switch (ee->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, ee->data2, 0);
			break;
		}
	}

	if (ee == NULL) {
		struct nvkm_subdev *subdev = nvkm_top_fault(device, info->engine);
		if (subdev) {
			if (subdev->func == &nvkm_engine)
				engine = container_of(subdev, typeof(*engine), subdev);
			en = engine->subdev.name;
		}
	} else {
		en = ee->name;
	}

	spin_lock_irqsave(&fifo->base.lock, flags);
	chan = nvkm_fifo_chan_inst_locked(&fifo->base, info->inst);

	nvkm_error(subdev,
		   "fault %02x [%s] at %016llx engine %02x [%s] client %02x "
		   "[%s%s] reason %02x [%s] on channel %d [%010llx %s]\n",
		   info->access, ea ? ea->name : "", info->addr,
		   info->engine, ee ? ee->name : en,
		   info->client, ct, ec ? ec->name : "",
		   info->reason, er ? er->name : "", chan ? chan->chid : -1,
		   info->inst, chan ? chan->object.client->name : "unknown");

	/* Kill the channel that caused the fault. */
	if (chan)
		gk104_fifo_recover_chan(&fifo->base, chan->chid);

	/* Channel recovery will probably have already done this for the
	 * correct engine(s), but just in case we can't find the channel
	 * information...
	 */
	if (engine) {
		int engn = fifo->base.func->engine_id(&fifo->base, engine);
		if (engn >= 0 && engn != GK104_FIFO_ENGN_SW)
			gk104_fifo_recover_engn(fifo, engn);
	}

	spin_unlock_irqrestore(&fifo->base.lock, flags);
}

const struct nvkm_fifo_func_mmu_fault
gk104_fifo_mmu_fault = {
	.recover = gk104_fifo_fault,
	.recover = gf100_fifo_mmu_fault_recover,
	.access = gf100_fifo_mmu_fault_access,
	.engine = gk104_fifo_mmu_fault_engine,
	.reason = gk104_fifo_mmu_fault_reason,
	.hubclient = gk104_fifo_mmu_fault_hubclient,
	.gpcclient = gk104_fifo_mmu_fault_gpcclient,
};

static const struct nvkm_enum
@@ -884,13 +800,7 @@ gk104_fifo_intr(struct nvkm_inth *inth)
	}

	if (stat & 0x10000000) {
		u32 mask = nvkm_rd32(device, 0x00259c);
		while (mask) {
			u32 unit = __ffs(mask);
			fifo->func->intr_mmu_fault_unit(fifo, unit);
			nvkm_wr32(device, 0x00259c, (1 << unit));
			mask &= ~(1 << unit);
		}
		gf100_fifo_intr_mmu_fault(fifo);
		stat &= ~0x10000000;
	}

@@ -1105,11 +1015,6 @@ gk104_fifo = {
	.intr = gk104_fifo_intr,
	.intr_mmu_fault_unit = gf100_fifo_intr_mmu_fault_unit,
	.mmu_fault = &gk104_fifo_mmu_fault,
	.fault.access = gk104_fifo_fault_access,
	.fault.engine = gk104_fifo_fault_engine,
	.fault.reason = gk104_fifo_fault_reason,
	.fault.hubclient = gk104_fifo_fault_hubclient,
	.fault.gpcclient = gk104_fifo_fault_gpcclient,
	.engine_id = gk104_fifo_engine_id,
	.recover_chan = gk104_fifo_recover_chan,
	.runlist = &gk104_fifo_runlist,
+0 −14
Original line number Diff line number Diff line
@@ -69,11 +69,6 @@ int gk104_fifo_oneinit(struct nvkm_fifo *);
void gk104_fifo_init(struct nvkm_fifo *base);
void gk104_fifo_fini(struct nvkm_fifo *base);

extern const struct nvkm_enum gk104_fifo_fault_access[];
extern const struct nvkm_enum gk104_fifo_fault_engine[];
extern const struct nvkm_enum gk104_fifo_fault_reason[];
extern const struct nvkm_enum gk104_fifo_fault_hubclient[];
extern const struct nvkm_enum gk104_fifo_fault_gpcclient[];
extern const struct gk104_fifo_runlist_func gk104_fifo_runlist;
void gk104_fifo_runlist_chan(struct gk104_fifo_chan *,
			     struct nvkm_memory *, u32);
@@ -84,17 +79,8 @@ extern const struct gk104_fifo_runlist_func gk110_fifo_runlist;
void gk110_fifo_runlist_cgrp(struct nvkm_fifo_cgrp *,
			     struct nvkm_memory *, u32);

void gk208_fifo_pbdma_init_timeout(struct gk104_fifo *);

extern const struct nvkm_enum gm107_fifo_fault_engine[];
extern const struct gk104_fifo_runlist_func gm107_fifo_runlist;

extern const struct nvkm_enum gp100_fifo_fault_engine[];

extern const struct nvkm_enum gv100_fifo_fault_access[];
extern const struct nvkm_enum gv100_fifo_fault_reason[];
extern const struct nvkm_enum gv100_fifo_fault_hubclient[];
extern const struct nvkm_enum gv100_fifo_fault_gpcclient[];
void gv100_fifo_runlist_cgrp(struct nvkm_fifo_cgrp *,
			     struct nvkm_memory *, u32);
void gv100_fifo_runlist_chan(struct gk104_fifo_chan *,
+0 −5
Original line number Diff line number Diff line
@@ -88,11 +88,6 @@ gk110_fifo = {
	.intr = gk104_fifo_intr,
	.intr_mmu_fault_unit = gf100_fifo_intr_mmu_fault_unit,
	.mmu_fault = &gk104_fifo_mmu_fault,
	.fault.access = gk104_fifo_fault_access,
	.fault.engine = gk104_fifo_fault_engine,
	.fault.reason = gk104_fifo_fault_reason,
	.fault.hubclient = gk104_fifo_fault_hubclient,
	.fault.gpcclient = gk104_fifo_fault_gpcclient,
	.engine_id = gk104_fifo_engine_id,
	.recover_chan = gk104_fifo_recover_chan,
	.runlist = &gk110_fifo_runlist,
+0 −5
Original line number Diff line number Diff line
@@ -62,11 +62,6 @@ gk208_fifo = {
	.intr = gk104_fifo_intr,
	.intr_mmu_fault_unit = gf100_fifo_intr_mmu_fault_unit,
	.mmu_fault = &gk104_fifo_mmu_fault,
	.fault.access = gk104_fifo_fault_access,
	.fault.engine = gk104_fifo_fault_engine,
	.fault.reason = gk104_fifo_fault_reason,
	.fault.hubclient = gk104_fifo_fault_hubclient,
	.fault.gpcclient = gk104_fifo_fault_gpcclient,
	.engine_id = gk104_fifo_engine_id,
	.recover_chan = gk104_fifo_recover_chan,
	.runlist = &gk110_fifo_runlist,
Loading