drm/nouveau/fifo: expose per-runlist CHID information
authorBen Skeggs <bskeggs@redhat.com>
Wed, 1 Jun 2022 10:47:25 +0000 (20:47 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 9 Nov 2022 00:44:47 +0000 (10:44 +1000)
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>
drivers/gpu/drm/nouveau/include/nvif/cl0080.h
drivers/gpu/drm/nouveau/nouveau_chan.c
drivers/gpu/drm/nouveau/nouveau_chan.h
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/nouveau/nv84_fence.c
drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c

index 59759c4..8b5a240 100644 (file)
@@ -68,7 +68,7 @@ struct nv_device_time_v0 {
 
 /* 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). */
@@ -90,4 +90,6 @@ struct nv_device_time_v0 {
 #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
index 3b5cbb6..5b7042d 100644 (file)
@@ -543,6 +543,12 @@ nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device,
        return ret;
 }
 
+void
+nouveau_channels_fini(struct nouveau_drm *drm)
+{
+       kfree(drm->runl);
+}
+
 int
 nouveau_channels_init(struct nouveau_drm *drm)
 {
@@ -550,20 +556,53 @@ 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;
 }
index 7ffee79..40467e8 100644 (file)
@@ -16,6 +16,7 @@ struct nouveau_channel {
        struct nouveau_drm *drm;
        struct nouveau_vmm *vmm;
 
+       int runlist;
        int chid;
        u64 inst;
        u32 token;
@@ -55,6 +56,7 @@ struct nouveau_channel {
 };
 
 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 **);
index 1812ffd..4a533b0 100644 (file)
@@ -424,6 +424,7 @@ nouveau_accel_fini(struct nouveau_drm *drm)
        nouveau_accel_gr_fini(drm);
        if (drm->fence)
                nouveau_fence(drm)->dtor(drm);
+       nouveau_channels_fini(drm);
 }
 
 static void
index 6fb6360..d6dd07b 100644 (file)
@@ -174,10 +174,14 @@ struct nouveau_drm {
        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;
index c4c8af1..ee5e9d4 100644 (file)
@@ -77,10 +77,6 @@ nouveau_local_fence(struct dma_fence *fence, struct nouveau_drm *drm)
            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);
 }
 
@@ -184,7 +180,7 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha
        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");
@@ -200,7 +196,7 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha
        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);
 
index c3526a8..a01fd93 100644 (file)
@@ -76,12 +76,18 @@ nv84_fence_sync32(struct nouveau_channel *chan, u64 virtual, u32 sequence)
        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);
 }
@@ -91,7 +97,7 @@ nv84_fence_sync(struct nouveau_fence *fence,
                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);
 }
@@ -100,7 +106,7 @@ static u32
 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
@@ -109,7 +115,7 @@ nv84_fence_context_del(struct nouveau_channel *chan)
        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);
@@ -152,9 +158,9 @@ nv84_fence_suspend(struct nouveau_drm *drm)
        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);
        }
 
@@ -168,7 +174,7 @@ nv84_fence_resume(struct nouveau_drm *drm)
        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;
@@ -216,7 +222,7 @@ nv84_fence_create(struct nouveau_drm *drm)
                  * 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);
index 2ccc0b3..0f603d9 100644 (file)
@@ -271,6 +271,15 @@ nvkm_fifo_info(struct nvkm_engine *engine, u64 mthd, u64 *data)
                        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;
        }