__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 {
 
 
 #include <nvif/os.h>
 
+struct nvif_sclass {
+       s32 oclass;
+       int minver;
+       int maxver;
+};
+
 struct nvif_object {
        struct nvif_client *client;
        u32 handle;
                      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);
 
 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
 
        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;
 
        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;
        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;
                        }
                }
        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;
                        }
                }
        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;
                        }
                }
                oclass = init->class;
        }
 
+       nvif_object_sclass_put(&sclass);
        if (!oclass)
                return nouveau_abi16_put(abi16, -EINVAL);
 
 
 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;
        /*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;
                }
        }
 
+       nvif_object_sclass_put(&sclass);
        if (ret) {
                NV_ERROR(drm, "failed to initialise sync subsystem, %d\n", ret);
                nouveau_accel_fini(drm);
 
                 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;
 }
 
 
                                     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;
 }
 
 #include <core/client.h>
 #include <core/engine.h>
 
+#include <nvif/ioctl.h>
+
 int
 nvkm_parent_sclass(struct nvkm_object *parent, s32 handle,
                   struct nvkm_object **pengine,
 }
 
 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;
 
        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;
                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++;
                        }
                }