From 41a634064db489713945e228e216336080ba57f8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:16 +1000 Subject: [PATCH] drm/nouveau/nvif: return min/max versions for supported object classes Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/ioctl.h | 6 ++- drivers/gpu/drm/nouveau/include/nvif/object.h | 9 +++- .../drm/nouveau/include/nvkm/core/parent.h | 2 +- drivers/gpu/drm/nouveau/nouveau_abi16.c | 21 ++++---- drivers/gpu/drm/nouveau/nouveau_drm.c | 11 ++-- drivers/gpu/drm/nouveau/nv50_display.c | 13 ++--- drivers/gpu/drm/nouveau/nvif/object.c | 53 ++++++++++++++----- drivers/gpu/drm/nouveau/nvkm/core/parent.c | 19 +++++-- 8 files changed, 92 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h index 7ac185c6e71f..b0ac0215ebf9 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h +++ b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h @@ -40,7 +40,11 @@ struct nvif_ioctl_sclass_v0 { __u8 version; __u8 count; __u8 pad02[6]; - __s32 oclass[]; + struct nvif_ioctl_sclass_oclass_v0 { + __s32 oclass; + __s16 minver; + __s16 maxver; + } oclass[]; }; struct nvif_ioctl_new_v0 { diff --git a/drivers/gpu/drm/nouveau/include/nvif/object.h b/drivers/gpu/drm/nouveau/include/nvif/object.h index 66d3425e4764..8d815967767f 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/object.h +++ b/drivers/gpu/drm/nouveau/include/nvif/object.h @@ -3,6 +3,12 @@ #include +struct nvif_sclass { + s32 oclass; + int minver; + int maxver; +}; + struct nvif_object { struct nvif_client *client; u32 handle; @@ -18,7 +24,8 @@ int nvif_object_init(struct nvif_object *, u32 handle, s32 oclass, void *, u32, struct nvif_object *); void nvif_object_fini(struct nvif_object *); int nvif_object_ioctl(struct nvif_object *, void *, u32, void **); -int nvif_object_sclass(struct nvif_object *, s32 *, int); +int nvif_object_sclass_get(struct nvif_object *, struct nvif_sclass **); +void nvif_object_sclass_put(struct nvif_sclass **); u32 nvif_object_rd(struct nvif_object *, int, u64); void nvif_object_wr(struct nvif_object *, int, u64, u32); int nvif_object_mthd(struct nvif_object *, u32, void *, u32); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h b/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h index bc4dc1f2403f..45d2066ff97a 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h @@ -47,5 +47,5 @@ void _nvkm_parent_dtor(struct nvkm_object *); int nvkm_parent_sclass(struct nvkm_object *, s32 handle, struct nvkm_object **pengine, struct nvkm_oclass **poclass); -int nvkm_parent_lclass(struct nvkm_object *, s32 *, int); +int nvkm_parent_lclass(struct nvkm_object *, void *, int); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 1b3067ee0442..98c74985e27d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -369,7 +369,7 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) struct nouveau_abi16_chan *chan; struct nouveau_abi16_ntfy *ntfy; struct nvif_client *client; - u32 sclass[32]; + struct nvif_sclass *sclass; s32 oclass = 0; int ret, i; @@ -384,19 +384,19 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) if (!chan) return nouveau_abi16_put(abi16, -ENOENT); - ret = nvif_object_sclass(&chan->chan->user, sclass, ARRAY_SIZE(sclass)); + ret = nvif_object_sclass_get(&chan->chan->user, &sclass); if (ret < 0) return nouveau_abi16_put(abi16, ret); if ((init->class & 0x00ff) == 0x006e) { /* nvsw: compatibility with older 0x*6e class identifier */ for (i = 0; !oclass && i < ret; i++) { - switch (sclass[i]) { + switch (sclass[i].oclass) { case NVIF_IOCTL_NEW_V0_SW_NV04: case NVIF_IOCTL_NEW_V0_SW_NV10: case NVIF_IOCTL_NEW_V0_SW_NV50: case NVIF_IOCTL_NEW_V0_SW_GF100: - oclass = sclass[i]; + oclass = sclass[i].oclass; break; default: break; @@ -406,8 +406,8 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) if ((init->class & 0x00ff) == 0x00b1) { /* msvld: compatibility with incorrect version exposure */ for (i = 0; i < ret; i++) { - if ((sclass[i] & 0x00ff) == 0x00b1) { - oclass = sclass[i]; + if ((sclass[i].oclass & 0x00ff) == 0x00b1) { + oclass = sclass[i].oclass; break; } } @@ -415,8 +415,8 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) if ((init->class & 0x00ff) == 0x00b2) { /* mspdec */ /* mspdec: compatibility with incorrect version exposure */ for (i = 0; i < ret; i++) { - if ((sclass[i] & 0x00ff) == 0x00b2) { - oclass = sclass[i]; + if ((sclass[i].oclass & 0x00ff) == 0x00b2) { + oclass = sclass[i].oclass; break; } } @@ -424,8 +424,8 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) if ((init->class & 0x00ff) == 0x00b3) { /* msppp */ /* msppp: compatibility with incorrect version exposure */ for (i = 0; i < ret; i++) { - if ((sclass[i] & 0x00ff) == 0x00b3) { - oclass = sclass[i]; + if ((sclass[i].oclass & 0x00ff) == 0x00b3) { + oclass = sclass[i].oclass; break; } } @@ -433,6 +433,7 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) oclass = init->class; } + nvif_object_sclass_put(&sclass); if (!oclass) return nouveau_abi16_put(abi16, -EINVAL); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 65ceb6fa4209..37dbd5e1c08f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -152,9 +152,9 @@ static void nouveau_accel_init(struct nouveau_drm *drm) { struct nvif_device *device = &drm->device; + struct nvif_sclass *sclass; u32 arg0, arg1; - s32 sclass[16]; - int ret, i; + int ret, i, n; if (nouveau_noaccel) return; @@ -163,12 +163,12 @@ nouveau_accel_init(struct nouveau_drm *drm) /*XXX: this is crap, but the fence/channel stuff is a little * backwards in some places. this will be fixed. */ - ret = nvif_object_sclass(&device->object, sclass, ARRAY_SIZE(sclass)); + ret = n = nvif_object_sclass_get(&device->object, &sclass); if (ret < 0) return; - for (ret = -ENOSYS, i = 0; ret && i < ARRAY_SIZE(sclass); i++) { - switch (sclass[i]) { + for (ret = -ENOSYS, i = 0; i < n; i++) { + switch (sclass[i].oclass) { case NV03_CHANNEL_DMA: ret = nv04_fence_create(drm); break; @@ -195,6 +195,7 @@ nouveau_accel_init(struct nouveau_drm *drm) } } + nvif_object_sclass_put(&sclass); if (ret) { NV_ERROR(drm, "failed to initialise sync subsystem, %d\n", ret); nouveau_accel_fini(drm); diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 65e70f085325..817ce09acb19 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -69,29 +69,30 @@ nv50_chan_create(struct nvif_device *device, struct nvif_object *disp, struct nv50_chan *chan) { const u32 handle = (oclass[0] << 16) | head; - s32 sclass[8]; - int ret, i; + struct nvif_sclass *sclass; + int ret, i, n; chan->device = device; - ret = nvif_object_sclass(disp, sclass, ARRAY_SIZE(sclass)); - WARN_ON(ret > ARRAY_SIZE(sclass)); + ret = n = nvif_object_sclass_get(disp, &sclass); if (ret < 0) return ret; while (oclass[0]) { - for (i = 0; i < ARRAY_SIZE(sclass); i++) { - if (sclass[i] == oclass[0]) { + for (i = 0; i < n; i++) { + if (sclass[i].oclass == oclass[0]) { ret = nvif_object_init(disp, handle, oclass[0], data, size, &chan->user); if (ret == 0) nvif_object_map(&chan->user); + nvif_object_sclass_put(&sclass); return ret; } } oclass++; } + nvif_object_sclass_put(&sclass); return -ENOSYS; } diff --git a/drivers/gpu/drm/nouveau/nvif/object.c b/drivers/gpu/drm/nouveau/nvif/object.c index 0c09e6433fbb..c3fb6a20f567 100644 --- a/drivers/gpu/drm/nouveau/nvif/object.c +++ b/drivers/gpu/drm/nouveau/nvif/object.c @@ -48,26 +48,53 @@ nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack) data, size, hack); } +void +nvif_object_sclass_put(struct nvif_sclass **psclass) +{ + kfree(*psclass); + *psclass = NULL; +} + int -nvif_object_sclass(struct nvif_object *object, s32 *oclass, int count) +nvif_object_sclass_get(struct nvif_object *object, struct nvif_sclass **psclass) { struct { struct nvif_ioctl_v0 ioctl; struct nvif_ioctl_sclass_v0 sclass; - } *args; - u32 size = count * sizeof(args->sclass.oclass[0]); - int ret; + } *args = NULL; + int ret, cnt = 0, i; + u32 size; - if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) - return -ENOMEM; - args->ioctl.version = 0; - args->ioctl.type = NVIF_IOCTL_V0_SCLASS; - args->sclass.version = 0; - args->sclass.count = count; + while (1) { + size = sizeof(*args) + cnt * sizeof(args->sclass.oclass[0]); + if (!(args = kmalloc(size, GFP_KERNEL))) + return -ENOMEM; + args->ioctl.version = 0; + args->ioctl.type = NVIF_IOCTL_V0_SCLASS; + args->sclass.version = 0; + args->sclass.count = cnt; + + ret = nvif_object_ioctl(object, args, size, NULL); + if (ret == 0 && args->sclass.count <= cnt) + break; + cnt = args->sclass.count; + kfree(args); + if (ret != 0) + return ret; + } + + *psclass = kzalloc(sizeof(**psclass) * args->sclass.count, GFP_KERNEL); + if (*psclass) { + for (i = 0; i < args->sclass.count; i++) { + (*psclass)[i].oclass = args->sclass.oclass[i].oclass; + (*psclass)[i].minver = args->sclass.oclass[i].minver; + (*psclass)[i].maxver = args->sclass.oclass[i].maxver; + } + ret = args->sclass.count; + } else { + ret = -ENOMEM; + } - ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL); - ret = ret ? ret : args->sclass.count; - memcpy(oclass, args->sclass.oclass, size); kfree(args); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/core/parent.c b/drivers/gpu/drm/nouveau/nvkm/core/parent.c index 43abd208b486..aecf5b8901b2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/parent.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/parent.c @@ -25,6 +25,8 @@ #include #include +#include + int nvkm_parent_sclass(struct nvkm_object *parent, s32 handle, struct nvkm_object **pengine, @@ -66,8 +68,9 @@ nvkm_parent_sclass(struct nvkm_object *parent, s32 handle, } int -nvkm_parent_lclass(struct nvkm_object *parent, s32 *lclass, int size) +nvkm_parent_lclass(struct nvkm_object *parent, void *data, int size) { + struct nvif_ioctl_sclass_oclass_v0 *lclass = data; struct nvkm_oclass *sclass, *oclass; struct nvkm_engine *engine; int nr = -1, i; @@ -75,8 +78,11 @@ nvkm_parent_lclass(struct nvkm_object *parent, s32 *lclass, int size) sclass = nv_parent(parent)->sclass; while ((oclass = sclass++) && oclass->ofuncs) { - if (++nr < size) - lclass[nr] = oclass->handle; + if (++nr < size) { + lclass[nr].oclass = oclass->handle; + lclass[nr].minver = -2; + lclass[nr].maxver = -2; + } } mask = nv_parent(parent)->engine; @@ -84,8 +90,11 @@ nvkm_parent_lclass(struct nvkm_object *parent, s32 *lclass, int size) engine = nvkm_engine(parent, i); if (engine && (oclass = engine->sclass)) { while (oclass->ofuncs) { - if (++nr < size) - lclass[nr] = oclass->handle; + if (++nr < size) { + lclass[nr].oclass = oclass->handle; + lclass[nr].minver = -2; + lclass[nr].maxver = -2; + } oclass++; } } -- 2.39.2