Browse Source

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

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Ben Skeggs 10 years ago
parent
commit
41a634064d

+ 5 - 1
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 {

+ 8 - 1
drivers/gpu/drm/nouveau/include/nvif/object.h

@@ -3,6 +3,12 @@
 
 #include <nvif/os.h>
 
+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);

+ 1 - 1
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

+ 11 - 10
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);
 

+ 6 - 5
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);

+ 7 - 6
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;
 }
 

+ 40 - 13
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;
 }

+ 14 - 5
drivers/gpu/drm/nouveau/nvkm/core/parent.c

@@ -25,6 +25,8 @@
 #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,
@@ -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++;
 			}
 		}