Commit a7cf0180 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/fifo/gk104-: require explicit runlist selection for channel allocation

We didn't used to be aware that runlist/engine IDs weren't the same thing,
or that there was such variability in configuration between GPUs.

By exposing this information to a client, and giving it explicit control
of which runlist it's allocating a channel on, we're able to make better
choices.

The immediate effect of this is that on GPUs where CE0 is the "GRCE", we
will now be allocating a copy engine running asynchronously to GR for BO
migrations - as intended.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent cc362050
...@@ -4,25 +4,11 @@ ...@@ -4,25 +4,11 @@
struct kepler_channel_gpfifo_a_v0 { struct kepler_channel_gpfifo_a_v0 {
__u8 version; __u8 version;
__u8 pad01[5]; __u8 pad01[1];
__u16 chid; __u16 chid;
#define NVA06F_V0_ENGINE_SW 0x00000001
#define NVA06F_V0_ENGINE_GR 0x00000002
#define NVA06F_V0_ENGINE_SEC 0x00000004
#define NVA06F_V0_ENGINE_MSVLD 0x00000010
#define NVA06F_V0_ENGINE_MSPDEC 0x00000020
#define NVA06F_V0_ENGINE_MSPPP 0x00000040
#define NVA06F_V0_ENGINE_MSENC 0x00000080
#define NVA06F_V0_ENGINE_VIC 0x00000100
#define NVA06F_V0_ENGINE_NVDEC 0x00000200
#define NVA06F_V0_ENGINE_NVENC0 0x00000400
#define NVA06F_V0_ENGINE_NVENC1 0x00000800
#define NVA06F_V0_ENGINE_CE0 0x00010000
#define NVA06F_V0_ENGINE_CE1 0x00020000
#define NVA06F_V0_ENGINE_CE2 0x00040000
__u32 engines;
__u32 ilength; __u32 ilength;
__u64 ioffset; __u64 ioffset;
__u64 runlist;
__u64 vmm; __u64 vmm;
}; };
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <nvif/client.h> #include <nvif/client.h>
#include <nvif/driver.h> #include <nvif/driver.h>
#include <nvif/fifo.h>
#include <nvif/ioctl.h> #include <nvif/ioctl.h>
#include <nvif/class.h> #include <nvif/class.h>
#include <nvif/cl0002.h> #include <nvif/cl0002.h>
...@@ -256,6 +257,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) ...@@ -256,6 +257,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv); struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv);
struct nouveau_abi16_chan *chan; struct nouveau_abi16_chan *chan;
struct nvif_device *device; struct nvif_device *device;
u64 engine;
int ret; int ret;
if (unlikely(!abi16)) if (unlikely(!abi16))
...@@ -268,25 +270,26 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) ...@@ -268,25 +270,26 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
/* hack to allow channel engine type specification on kepler */ /* hack to allow channel engine type specification on kepler */
if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) { if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
if (init->fb_ctxdma_handle != ~0) if (init->fb_ctxdma_handle == ~0) {
init->fb_ctxdma_handle = NVA06F_V0_ENGINE_GR; switch (init->tt_ctxdma_handle) {
else { case 0x01: engine = NV_DEVICE_INFO_ENGINE_GR ; break;
init->fb_ctxdma_handle = 0; case 0x02: engine = NV_DEVICE_INFO_ENGINE_MSPDEC; break;
#define _(A,B) if (init->tt_ctxdma_handle & (A)) init->fb_ctxdma_handle |= (B) case 0x04: engine = NV_DEVICE_INFO_ENGINE_MSPPP ; break;
_(0x01, NVA06F_V0_ENGINE_GR); case 0x08: engine = NV_DEVICE_INFO_ENGINE_MSVLD ; break;
_(0x02, NVA06F_V0_ENGINE_MSPDEC); case 0x30: engine = NV_DEVICE_INFO_ENGINE_CE ; break;
_(0x04, NVA06F_V0_ENGINE_MSPPP); default:
_(0x08, NVA06F_V0_ENGINE_MSVLD); return nouveau_abi16_put(abi16, -ENOSYS);
_(0x10, NVA06F_V0_ENGINE_CE0); }
_(0x20, NVA06F_V0_ENGINE_CE1); } else {
_(0x40, NVA06F_V0_ENGINE_MSENC); engine = NV_DEVICE_INFO_ENGINE_GR;
#undef _
} }
/* allow flips to be executed if this is a graphics channel */ if (engine != NV_DEVICE_INFO_ENGINE_CE)
engine = nvif_fifo_runlist(device, engine);
else
engine = nvif_fifo_runlist_ce(device);
init->fb_ctxdma_handle = engine;
init->tt_ctxdma_handle = 0; init->tt_ctxdma_handle = 0;
if (init->fb_ctxdma_handle == NVA06F_V0_ENGINE_GR)
init->tt_ctxdma_handle = 1;
} }
if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0) if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
......
...@@ -214,7 +214,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, ...@@ -214,7 +214,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
static int static int
nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device, nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
u32 engine, struct nouveau_channel **pchan) u64 runlist, struct nouveau_channel **pchan)
{ {
struct nouveau_cli *cli = (void *)device->object.client; struct nouveau_cli *cli = (void *)device->object.client;
static const u16 oclasses[] = { PASCAL_CHANNEL_GPFIFO_A, static const u16 oclasses[] = { PASCAL_CHANNEL_GPFIFO_A,
...@@ -245,9 +245,9 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device, ...@@ -245,9 +245,9 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device,
do { do {
if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) { if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) {
args.kepler.version = 0; args.kepler.version = 0;
args.kepler.engines = engine;
args.kepler.ilength = 0x02000; args.kepler.ilength = 0x02000;
args.kepler.ioffset = 0x10000 + chan->push.addr; args.kepler.ioffset = 0x10000 + chan->push.addr;
args.kepler.runlist = runlist;
args.kepler.vmm = nvif_handle(&cli->vmm.vmm.object); args.kepler.vmm = nvif_handle(&cli->vmm.vmm.object);
size = sizeof(args.kepler); size = sizeof(args.kepler);
} else } else
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <core/tegra.h> #include <core/tegra.h>
#include <nvif/driver.h> #include <nvif/driver.h>
#include <nvif/fifo.h>
#include <nvif/class.h> #include <nvif/class.h>
#include <nvif/cl0002.h> #include <nvif/cl0002.h>
...@@ -358,13 +359,12 @@ nouveau_accel_init(struct nouveau_drm *drm) ...@@ -358,13 +359,12 @@ nouveau_accel_init(struct nouveau_drm *drm)
if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) { if (device->info.family >= NV_DEVICE_INFO_V0_KEPLER) {
ret = nouveau_channel_new(drm, &drm->client.device, ret = nouveau_channel_new(drm, &drm->client.device,
NVA06F_V0_ENGINE_CE0 | nvif_fifo_runlist_ce(device), 0,
NVA06F_V0_ENGINE_CE1, &drm->cechan);
0, &drm->cechan);
if (ret) if (ret)
NV_ERROR(drm, "failed to create ce channel, %d\n", ret); NV_ERROR(drm, "failed to create ce channel, %d\n", ret);
arg0 = NVA06F_V0_ENGINE_GR; arg0 = nvif_fifo_runlist(device, NV_DEVICE_INFO_ENGINE_GR);
arg1 = 1; arg1 = 1;
} else } else
if (device->info.chipset >= 0xa3 && if (device->info.chipset >= 0xa3 &&
......
...@@ -222,62 +222,30 @@ gk104_fifo_gpfifo_func = { ...@@ -222,62 +222,30 @@ gk104_fifo_gpfifo_func = {
.engine_fini = gk104_fifo_gpfifo_engine_fini, .engine_fini = gk104_fifo_gpfifo_engine_fini,
}; };
struct gk104_fifo_chan_func {
u32 engine;
u64 subdev;
};
static int static int
gk104_fifo_gpfifo_new_(const struct gk104_fifo_chan_func *func, gk104_fifo_gpfifo_new_(struct gk104_fifo *fifo, u64 *runlists, u16 *chid,
struct gk104_fifo *fifo, u32 *engmask, u16 *chid,
u64 vmm, u64 ioffset, u64 ilength, u64 vmm, u64 ioffset, u64 ilength,
const struct nvkm_oclass *oclass, const struct nvkm_oclass *oclass,
struct nvkm_object **pobject) struct nvkm_object **pobject)
{ {
struct gk104_fifo_chan *chan; struct gk104_fifo_chan *chan;
int runlist = -1, ret = -ENOSYS, i, j; int runlist = ffs(*runlists) -1, ret, i;
u32 engines = 0, present = 0; unsigned long engm;
u64 subdevs = 0; u64 subdevs = 0;
u64 usermem; u64 usermem;
if (!vmm) if (!vmm || runlist < 0 || runlist >= fifo->runlist_nr)
return -EINVAL; return -EINVAL;
*runlists = BIT_ULL(runlist);
/* Determine which downstream engines are present */ engm = fifo->runlist[runlist].engm;
for (i = 0; i < fifo->engine_nr; i++) { for_each_set_bit(i, &engm, fifo->engine_nr) {
struct nvkm_engine *engine = fifo->engine[i].engine; if (fifo->engine[i].engine)
if (engine) { subdevs |= BIT_ULL(fifo->engine[i].engine->subdev.index);
u64 submask = BIT_ULL(engine->subdev.index);
for (j = 0; func[j].subdev; j++) {
if (func[j].subdev & submask) {
present |= func[j].engine;
break;
}
}
if (!func[j].subdev)
continue;
if (runlist < 0 && (*engmask & present))
runlist = fifo->engine[i].runl;
if (runlist == fifo->engine[i].runl) {
engines |= func[j].engine;
subdevs |= func[j].subdev;
}
}
} }
/* Just an engine mask query? All done here! */ if (subdevs & BIT_ULL(NVKM_ENGINE_GR))
if (!*engmask) { subdevs |= BIT_ULL(NVKM_ENGINE_SW);
*engmask = present;
return nvkm_object_new(oclass, NULL, 0, pobject);
}
/* No runlist? No supported engines. */
*engmask = present;
if (runlist < 0)
return -ENODEV;
*engmask = engines;
/* Allocate the channel. */ /* Allocate the channel. */
if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
...@@ -327,26 +295,6 @@ gk104_fifo_gpfifo_new_(const struct gk104_fifo_chan_func *func, ...@@ -327,26 +295,6 @@ gk104_fifo_gpfifo_new_(const struct gk104_fifo_chan_func *func,
return 0; return 0;
} }
static const struct gk104_fifo_chan_func
gk104_fifo_gpfifo[] = {
{ NVA06F_V0_ENGINE_SW | NVA06F_V0_ENGINE_GR,
BIT_ULL(NVKM_ENGINE_SW) | BIT_ULL(NVKM_ENGINE_GR)
},
{ NVA06F_V0_ENGINE_SEC , BIT_ULL(NVKM_ENGINE_SEC ) },
{ NVA06F_V0_ENGINE_MSVLD , BIT_ULL(NVKM_ENGINE_MSVLD ) },
{ NVA06F_V0_ENGINE_MSPDEC, BIT_ULL(NVKM_ENGINE_MSPDEC) },
{ NVA06F_V0_ENGINE_MSPPP , BIT_ULL(NVKM_ENGINE_MSPPP ) },
{ NVA06F_V0_ENGINE_MSENC , BIT_ULL(NVKM_ENGINE_MSENC ) },
{ NVA06F_V0_ENGINE_VIC , BIT_ULL(NVKM_ENGINE_VIC ) },
{ NVA06F_V0_ENGINE_NVDEC , BIT_ULL(NVKM_ENGINE_NVDEC ) },
{ NVA06F_V0_ENGINE_NVENC0, BIT_ULL(NVKM_ENGINE_NVENC0) },
{ NVA06F_V0_ENGINE_NVENC1, BIT_ULL(NVKM_ENGINE_NVENC1) },
{ NVA06F_V0_ENGINE_CE0 , BIT_ULL(NVKM_ENGINE_CE0 ) },
{ NVA06F_V0_ENGINE_CE1 , BIT_ULL(NVKM_ENGINE_CE1 ) },
{ NVA06F_V0_ENGINE_CE2 , BIT_ULL(NVKM_ENGINE_CE2 ) },
{}
};
int int
gk104_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, gk104_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
void *data, u32 size, struct nvkm_object **pobject) void *data, u32 size, struct nvkm_object **pobject)
...@@ -361,11 +309,12 @@ gk104_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, ...@@ -361,11 +309,12 @@ gk104_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass,
nvif_ioctl(parent, "create channel gpfifo size %d\n", size); nvif_ioctl(parent, "create channel gpfifo size %d\n", size);
if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) {
nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx " nvif_ioctl(parent, "create channel gpfifo vers %d vmm %llx "
"ioffset %016llx ilength %08x engine %08x\n", "ioffset %016llx ilength %08x "
"runlist %016llx\n",
args->v0.version, args->v0.vmm, args->v0.ioffset, args->v0.version, args->v0.vmm, args->v0.ioffset,
args->v0.ilength, args->v0.engines); args->v0.ilength, args->v0.runlist);
return gk104_fifo_gpfifo_new_(gk104_fifo_gpfifo, fifo, return gk104_fifo_gpfifo_new_(fifo,
&args->v0.engines, &args->v0.runlist,
&args->v0.chid, &args->v0.chid,
args->v0.vmm, args->v0.vmm,
args->v0.ioffset, args->v0.ioffset,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment