Commit eb39c613 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/fifo: expose per-runlist CHID information

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: default avatarBen Skeggs <bskeggs@redhat.com>
Reviewed-by: default avatarLyude Paul <lyude@redhat.com>
parent 6de12538
......@@ -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
......@@ -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;
}
......@@ -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 **);
......
......@@ -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
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
......
......@@ -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;
}
......
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