DRM uses this to setup fence-related items.
- nouveau_chan.runlist will always be "0" for the moment, not an issue
as GPUs prior to ampere have system-wide channel IDs,
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Reviewed-by: Lyude Paul <lyude@redhat.com>
/* Returns the number of available runlists. */
#define NV_DEVICE_HOST_RUNLISTS NV_DEVICE_HOST(0x00000000)
-/* Returns the number of available channels. */
+/* Returns the number of available channels (0 if per-runlist). */
#define NV_DEVICE_HOST_CHANNELS NV_DEVICE_HOST(0x00000001)
/* Returns a mask of available engine types on runlist(data). */
#define NV_DEVICE_HOST_RUNLIST_ENGINES_SEC2 0x00004000
#define NV_DEVICE_HOST_RUNLIST_ENGINES_NVDEC 0x00008000
#define NV_DEVICE_HOST_RUNLIST_ENGINES_NVENC 0x00010000
+/* Returns the number of available channels on runlist(data). */
+#define NV_DEVICE_HOST_RUNLIST_CHANNELS NV_DEVICE_HOST(0x00000101)
#endif
return ret;
}
+void
+nouveau_channels_fini(struct nouveau_drm *drm)
+{
+ kfree(drm->runl);
+}
+
int
nouveau_channels_init(struct nouveau_drm *drm)
{
struct nv_device_info_v1 m;
struct {
struct nv_device_info_v1_data channels;
+ struct nv_device_info_v1_data runlists;
} v;
} args = {
.m.version = 1,
.m.count = sizeof(args.v) / sizeof(args.v.channels),
.v.channels.mthd = NV_DEVICE_HOST_CHANNELS,
+ .v.runlists.mthd = NV_DEVICE_HOST_RUNLISTS,
};
struct nvif_object *device = &drm->client.device.object;
- int ret;
+ int ret, i;
ret = nvif_object_mthd(device, NV_DEVICE_V0_INFO, &args, sizeof(args));
- if (ret || args.v.channels.mthd == NV_DEVICE_INFO_INVALID)
+ if (ret ||
+ args.v.runlists.mthd == NV_DEVICE_INFO_INVALID || !args.v.runlists.data ||
+ args.v.channels.mthd == NV_DEVICE_INFO_INVALID)
return -ENODEV;
- drm->chan.nr = args.v.channels.data;
- drm->chan.context_base = dma_fence_context_alloc(drm->chan.nr);
+ drm->chan_nr = drm->chan_total = args.v.channels.data;
+ drm->runl_nr = fls64(args.v.runlists.data);
+ drm->runl = kcalloc(drm->runl_nr, sizeof(*drm->runl), GFP_KERNEL);
+ if (!drm->runl)
+ return -ENOMEM;
+
+ if (drm->chan_nr == 0) {
+ for (i = 0; i < drm->runl_nr; i++) {
+ if (!(args.v.runlists.data & BIT(i)))
+ continue;
+
+ args.v.channels.mthd = NV_DEVICE_HOST_RUNLIST_CHANNELS;
+ args.v.channels.data = i;
+
+ ret = nvif_object_mthd(device, NV_DEVICE_V0_INFO, &args, sizeof(args));
+ if (ret || args.v.channels.mthd == NV_DEVICE_INFO_INVALID)
+ return -ENODEV;
+
+ drm->runl[i].chan_nr = args.v.channels.data;
+ drm->runl[i].chan_id_base = drm->chan_total;
+ drm->runl[i].context_base = dma_fence_context_alloc(drm->runl[i].chan_nr);
+
+ drm->chan_total += drm->runl[i].chan_nr;
+ }
+ } else {
+ drm->runl[0].context_base = dma_fence_context_alloc(drm->chan_nr);
+ for (i = 1; i < drm->runl_nr; i++)
+ drm->runl[i].context_base = drm->runl[0].context_base;
+
+ }
+
return 0;
}
struct nouveau_drm *drm;
struct nouveau_vmm *vmm;
+ int runlist;
int chid;
u64 inst;
u32 token;
};
int nouveau_channels_init(struct nouveau_drm *);
+void nouveau_channels_fini(struct nouveau_drm *);
int nouveau_channel_new(struct nouveau_drm *, struct nvif_device *, bool priv, u64 runm,
u32 vram, u32 gart, struct nouveau_channel **);
nouveau_accel_gr_fini(drm);
if (drm->fence)
nouveau_fence(drm)->dtor(drm);
+ nouveau_channels_fini(drm);
}
static void
void *fence;
/* Global channel management. */
+ int chan_total; /* Number of channels across all runlists. */
+ int chan_nr; /* 0 if per-runlist CHIDs. */
+ int runl_nr;
struct {
- int nr;
+ int chan_nr;
+ int chan_id_base;
u64 context_base;
- } chan;
+ } *runl;
/* context for accelerated drm-internal operations */
struct nouveau_channel *cechan;
fence->ops != &nouveau_fence_ops_uevent)
return NULL;
- if (fence->context < drm->chan.context_base ||
- fence->context >= drm->chan.context_base + drm->chan.nr)
- return NULL;
-
return from_fence(fence);
}
INIT_LIST_HEAD(&fctx->flip);
INIT_LIST_HEAD(&fctx->pending);
spin_lock_init(&fctx->lock);
- fctx->context = chan->drm->chan.context_base + chan->chid;
+ fctx->context = chan->drm->runl[chan->runlist].context_base + chan->chid;
if (chan == chan->drm->cechan)
strcpy(fctx->name, "copy engine channel");
args.host.version = 0;
args.host.type = NVIF_CHAN_EVENT_V0_NON_STALL_INTR;
- ret = nvif_event_ctor(&chan->user, "fenceNonStallIntr", chan->chid,
+ ret = nvif_event_ctor(&chan->user, "fenceNonStallIntr", (chan->runlist << 16) | chan->chid,
nouveau_fence_wait_uevent_handler, false,
&args.base, sizeof(args), &fctx->event);
return ret;
}
+static inline u32
+nv84_fence_chid(struct nouveau_channel *chan)
+{
+ return chan->drm->runl[chan->runlist].chan_id_base + chan->chid;
+}
+
static int
nv84_fence_emit(struct nouveau_fence *fence)
{
struct nouveau_channel *chan = fence->channel;
struct nv84_fence_chan *fctx = chan->fence;
- u64 addr = fctx->vma->addr + chan->chid * 16;
+ u64 addr = fctx->vma->addr + nv84_fence_chid(chan) * 16;
return fctx->base.emit32(chan, addr, fence->base.seqno);
}
struct nouveau_channel *prev, struct nouveau_channel *chan)
{
struct nv84_fence_chan *fctx = chan->fence;
- u64 addr = fctx->vma->addr + prev->chid * 16;
+ u64 addr = fctx->vma->addr + nv84_fence_chid(prev) * 16;
return fctx->base.sync32(chan, addr, fence->base.seqno);
}
nv84_fence_read(struct nouveau_channel *chan)
{
struct nv84_fence_priv *priv = chan->drm->fence;
- return nouveau_bo_rd32(priv->bo, chan->chid * 16/4);
+ return nouveau_bo_rd32(priv->bo, nv84_fence_chid(chan) * 16/4);
}
static void
struct nv84_fence_priv *priv = chan->drm->fence;
struct nv84_fence_chan *fctx = chan->fence;
- nouveau_bo_wr32(priv->bo, chan->chid * 16 / 4, fctx->base.sequence);
+ nouveau_bo_wr32(priv->bo, nv84_fence_chid(chan) * 16 / 4, fctx->base.sequence);
mutex_lock(&priv->mutex);
nouveau_vma_del(&fctx->vma);
mutex_unlock(&priv->mutex);
struct nv84_fence_priv *priv = drm->fence;
int i;
- priv->suspend = vmalloc(array_size(sizeof(u32), drm->chan.nr));
+ priv->suspend = vmalloc(array_size(sizeof(u32), drm->chan_total));
if (priv->suspend) {
- for (i = 0; i < drm->chan.nr; i++)
+ for (i = 0; i < drm->chan_total; i++)
priv->suspend[i] = nouveau_bo_rd32(priv->bo, i*4);
}
int i;
if (priv->suspend) {
- for (i = 0; i < drm->chan.nr; i++)
+ for (i = 0; i < drm->chan_total; i++)
nouveau_bo_wr32(priv->bo, i*4, priv->suspend[i]);
vfree(priv->suspend);
priv->suspend = NULL;
* will lose CPU/GPU coherency!
*/
NOUVEAU_GEM_DOMAIN_GART | NOUVEAU_GEM_DOMAIN_COHERENT;
- ret = nouveau_bo_new(&drm->client, 16 * drm->chan.nr, 0,
+ ret = nouveau_bo_new(&drm->client, 16 * drm->chan_total, 0,
domain, 0, 0, NULL, NULL, &priv->bo);
if (ret == 0) {
ret = nouveau_bo_pin(priv->bo, domain, false);
return 0;
}
return -EINVAL;
+ case NV_DEVICE_HOST_RUNLIST_CHANNELS:
+ if (!fifo->chid) {
+ runl = nvkm_runl_get(fifo, *data, 0);
+ if (runl) {
+ *data = runl->chid->nr;
+ return 0;
+ }
+ }
+ return -EINVAL;
default:
break;
}