Commit 41a63406 authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/nvif: return min/max versions for supported object classes

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent f58ddf95
...@@ -40,7 +40,11 @@ struct nvif_ioctl_sclass_v0 { ...@@ -40,7 +40,11 @@ struct nvif_ioctl_sclass_v0 {
__u8 version; __u8 version;
__u8 count; __u8 count;
__u8 pad02[6]; __u8 pad02[6];
__s32 oclass[]; struct nvif_ioctl_sclass_oclass_v0 {
__s32 oclass;
__s16 minver;
__s16 maxver;
} oclass[];
}; };
struct nvif_ioctl_new_v0 { struct nvif_ioctl_new_v0 {
......
...@@ -3,6 +3,12 @@ ...@@ -3,6 +3,12 @@
#include <nvif/os.h> #include <nvif/os.h>
struct nvif_sclass {
s32 oclass;
int minver;
int maxver;
};
struct nvif_object { struct nvif_object {
struct nvif_client *client; struct nvif_client *client;
u32 handle; u32 handle;
...@@ -18,7 +24,8 @@ int nvif_object_init(struct nvif_object *, u32 handle, s32 oclass, void *, u32, ...@@ -18,7 +24,8 @@ int nvif_object_init(struct nvif_object *, u32 handle, s32 oclass, void *, u32,
struct nvif_object *); struct nvif_object *);
void nvif_object_fini(struct nvif_object *); void nvif_object_fini(struct nvif_object *);
int nvif_object_ioctl(struct nvif_object *, void *, u32, void **); 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); u32 nvif_object_rd(struct nvif_object *, int, u64);
void nvif_object_wr(struct nvif_object *, int, u64, u32); void nvif_object_wr(struct nvif_object *, int, u64, u32);
int nvif_object_mthd(struct nvif_object *, u32, void *, u32); int nvif_object_mthd(struct nvif_object *, u32, void *, u32);
......
...@@ -47,5 +47,5 @@ void _nvkm_parent_dtor(struct nvkm_object *); ...@@ -47,5 +47,5 @@ void _nvkm_parent_dtor(struct nvkm_object *);
int nvkm_parent_sclass(struct nvkm_object *, s32 handle, int nvkm_parent_sclass(struct nvkm_object *, s32 handle,
struct nvkm_object **pengine, struct nvkm_object **pengine,
struct nvkm_oclass **poclass); struct nvkm_oclass **poclass);
int nvkm_parent_lclass(struct nvkm_object *, s32 *, int); int nvkm_parent_lclass(struct nvkm_object *, void *, int);
#endif #endif
...@@ -369,7 +369,7 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) ...@@ -369,7 +369,7 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)
struct nouveau_abi16_chan *chan; struct nouveau_abi16_chan *chan;
struct nouveau_abi16_ntfy *ntfy; struct nouveau_abi16_ntfy *ntfy;
struct nvif_client *client; struct nvif_client *client;
u32 sclass[32]; struct nvif_sclass *sclass;
s32 oclass = 0; s32 oclass = 0;
int ret, i; int ret, i;
...@@ -384,19 +384,19 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) ...@@ -384,19 +384,19 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)
if (!chan) if (!chan)
return nouveau_abi16_put(abi16, -ENOENT); 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) if (ret < 0)
return nouveau_abi16_put(abi16, ret); return nouveau_abi16_put(abi16, ret);
if ((init->class & 0x00ff) == 0x006e) { if ((init->class & 0x00ff) == 0x006e) {
/* nvsw: compatibility with older 0x*6e class identifier */ /* nvsw: compatibility with older 0x*6e class identifier */
for (i = 0; !oclass && i < ret; i++) { 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_NV04:
case NVIF_IOCTL_NEW_V0_SW_NV10: case NVIF_IOCTL_NEW_V0_SW_NV10:
case NVIF_IOCTL_NEW_V0_SW_NV50: case NVIF_IOCTL_NEW_V0_SW_NV50:
case NVIF_IOCTL_NEW_V0_SW_GF100: case NVIF_IOCTL_NEW_V0_SW_GF100:
oclass = sclass[i]; oclass = sclass[i].oclass;
break; break;
default: default:
break; break;
...@@ -406,8 +406,8 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) ...@@ -406,8 +406,8 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)
if ((init->class & 0x00ff) == 0x00b1) { if ((init->class & 0x00ff) == 0x00b1) {
/* msvld: compatibility with incorrect version exposure */ /* msvld: compatibility with incorrect version exposure */
for (i = 0; i < ret; i++) { for (i = 0; i < ret; i++) {
if ((sclass[i] & 0x00ff) == 0x00b1) { if ((sclass[i].oclass & 0x00ff) == 0x00b1) {
oclass = sclass[i]; oclass = sclass[i].oclass;
break; break;
} }
} }
...@@ -415,8 +415,8 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) ...@@ -415,8 +415,8 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)
if ((init->class & 0x00ff) == 0x00b2) { /* mspdec */ if ((init->class & 0x00ff) == 0x00b2) { /* mspdec */
/* mspdec: compatibility with incorrect version exposure */ /* mspdec: compatibility with incorrect version exposure */
for (i = 0; i < ret; i++) { for (i = 0; i < ret; i++) {
if ((sclass[i] & 0x00ff) == 0x00b2) { if ((sclass[i].oclass & 0x00ff) == 0x00b2) {
oclass = sclass[i]; oclass = sclass[i].oclass;
break; break;
} }
} }
...@@ -424,8 +424,8 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) ...@@ -424,8 +424,8 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)
if ((init->class & 0x00ff) == 0x00b3) { /* msppp */ if ((init->class & 0x00ff) == 0x00b3) { /* msppp */
/* msppp: compatibility with incorrect version exposure */ /* msppp: compatibility with incorrect version exposure */
for (i = 0; i < ret; i++) { for (i = 0; i < ret; i++) {
if ((sclass[i] & 0x00ff) == 0x00b3) { if ((sclass[i].oclass & 0x00ff) == 0x00b3) {
oclass = sclass[i]; oclass = sclass[i].oclass;
break; break;
} }
} }
...@@ -433,6 +433,7 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) ...@@ -433,6 +433,7 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS)
oclass = init->class; oclass = init->class;
} }
nvif_object_sclass_put(&sclass);
if (!oclass) if (!oclass)
return nouveau_abi16_put(abi16, -EINVAL); return nouveau_abi16_put(abi16, -EINVAL);
......
...@@ -152,9 +152,9 @@ static void ...@@ -152,9 +152,9 @@ static void
nouveau_accel_init(struct nouveau_drm *drm) nouveau_accel_init(struct nouveau_drm *drm)
{ {
struct nvif_device *device = &drm->device; struct nvif_device *device = &drm->device;
struct nvif_sclass *sclass;
u32 arg0, arg1; u32 arg0, arg1;
s32 sclass[16]; int ret, i, n;
int ret, i;
if (nouveau_noaccel) if (nouveau_noaccel)
return; return;
...@@ -163,12 +163,12 @@ nouveau_accel_init(struct nouveau_drm *drm) ...@@ -163,12 +163,12 @@ nouveau_accel_init(struct nouveau_drm *drm)
/*XXX: this is crap, but the fence/channel stuff is a little /*XXX: this is crap, but the fence/channel stuff is a little
* backwards in some places. this will be fixed. * 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) if (ret < 0)
return; return;
for (ret = -ENOSYS, i = 0; ret && i < ARRAY_SIZE(sclass); i++) { for (ret = -ENOSYS, i = 0; i < n; i++) {
switch (sclass[i]) { switch (sclass[i].oclass) {
case NV03_CHANNEL_DMA: case NV03_CHANNEL_DMA:
ret = nv04_fence_create(drm); ret = nv04_fence_create(drm);
break; break;
...@@ -195,6 +195,7 @@ nouveau_accel_init(struct nouveau_drm *drm) ...@@ -195,6 +195,7 @@ nouveau_accel_init(struct nouveau_drm *drm)
} }
} }
nvif_object_sclass_put(&sclass);
if (ret) { if (ret) {
NV_ERROR(drm, "failed to initialise sync subsystem, %d\n", ret); NV_ERROR(drm, "failed to initialise sync subsystem, %d\n", ret);
nouveau_accel_fini(drm); nouveau_accel_fini(drm);
......
...@@ -69,29 +69,30 @@ nv50_chan_create(struct nvif_device *device, struct nvif_object *disp, ...@@ -69,29 +69,30 @@ nv50_chan_create(struct nvif_device *device, struct nvif_object *disp,
struct nv50_chan *chan) struct nv50_chan *chan)
{ {
const u32 handle = (oclass[0] << 16) | head; const u32 handle = (oclass[0] << 16) | head;
s32 sclass[8]; struct nvif_sclass *sclass;
int ret, i; int ret, i, n;
chan->device = device; chan->device = device;
ret = nvif_object_sclass(disp, sclass, ARRAY_SIZE(sclass)); ret = n = nvif_object_sclass_get(disp, &sclass);
WARN_ON(ret > ARRAY_SIZE(sclass));
if (ret < 0) if (ret < 0)
return ret; return ret;
while (oclass[0]) { while (oclass[0]) {
for (i = 0; i < ARRAY_SIZE(sclass); i++) { for (i = 0; i < n; i++) {
if (sclass[i] == oclass[0]) { if (sclass[i].oclass == oclass[0]) {
ret = nvif_object_init(disp, handle, oclass[0], ret = nvif_object_init(disp, handle, oclass[0],
data, size, &chan->user); data, size, &chan->user);
if (ret == 0) if (ret == 0)
nvif_object_map(&chan->user); nvif_object_map(&chan->user);
nvif_object_sclass_put(&sclass);
return ret; return ret;
} }
} }
oclass++; oclass++;
} }
nvif_object_sclass_put(&sclass);
return -ENOSYS; return -ENOSYS;
} }
......
...@@ -48,26 +48,53 @@ nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack) ...@@ -48,26 +48,53 @@ nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack)
data, size, hack); data, size, hack);
} }
void
nvif_object_sclass_put(struct nvif_sclass **psclass)
{
kfree(*psclass);
*psclass = NULL;
}
int 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 {
struct nvif_ioctl_v0 ioctl; struct nvif_ioctl_v0 ioctl;
struct nvif_ioctl_sclass_v0 sclass; struct nvif_ioctl_sclass_v0 sclass;
} *args; } *args = NULL;
u32 size = count * sizeof(args->sclass.oclass[0]); int ret, cnt = 0, i;
int ret; u32 size;
if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) while (1) {
size = sizeof(*args) + cnt * sizeof(args->sclass.oclass[0]);
if (!(args = kmalloc(size, GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
args->ioctl.version = 0; args->ioctl.version = 0;
args->ioctl.type = NVIF_IOCTL_V0_SCLASS; args->ioctl.type = NVIF_IOCTL_V0_SCLASS;
args->sclass.version = 0; args->sclass.version = 0;
args->sclass.count = count; 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); kfree(args);
return ret; return ret;
} }
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include <core/client.h> #include <core/client.h>
#include <core/engine.h> #include <core/engine.h>
#include <nvif/ioctl.h>
int int
nvkm_parent_sclass(struct nvkm_object *parent, s32 handle, nvkm_parent_sclass(struct nvkm_object *parent, s32 handle,
struct nvkm_object **pengine, struct nvkm_object **pengine,
...@@ -66,8 +68,9 @@ nvkm_parent_sclass(struct nvkm_object *parent, s32 handle, ...@@ -66,8 +68,9 @@ nvkm_parent_sclass(struct nvkm_object *parent, s32 handle,
} }
int 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_oclass *sclass, *oclass;
struct nvkm_engine *engine; struct nvkm_engine *engine;
int nr = -1, i; int nr = -1, i;
...@@ -75,8 +78,11 @@ nvkm_parent_lclass(struct nvkm_object *parent, s32 *lclass, int size) ...@@ -75,8 +78,11 @@ nvkm_parent_lclass(struct nvkm_object *parent, s32 *lclass, int size)
sclass = nv_parent(parent)->sclass; sclass = nv_parent(parent)->sclass;
while ((oclass = sclass++) && oclass->ofuncs) { while ((oclass = sclass++) && oclass->ofuncs) {
if (++nr < size) if (++nr < size) {
lclass[nr] = oclass->handle; lclass[nr].oclass = oclass->handle;
lclass[nr].minver = -2;
lclass[nr].maxver = -2;
}
} }
mask = nv_parent(parent)->engine; mask = nv_parent(parent)->engine;
...@@ -84,8 +90,11 @@ nvkm_parent_lclass(struct nvkm_object *parent, s32 *lclass, int size) ...@@ -84,8 +90,11 @@ nvkm_parent_lclass(struct nvkm_object *parent, s32 *lclass, int size)
engine = nvkm_engine(parent, i); engine = nvkm_engine(parent, i);
if (engine && (oclass = engine->sclass)) { if (engine && (oclass = engine->sclass)) {
while (oclass->ofuncs) { while (oclass->ofuncs) {
if (++nr < size) if (++nr < size) {
lclass[nr] = oclass->handle; lclass[nr].oclass = oclass->handle;
lclass[nr].minver = -2;
lclass[nr].maxver = -2;
}
oclass++; oclass++;
} }
} }
......
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