drm/nouveau/abi16: implement limited interoperability with usif/nvif

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index 998f5cb..7f50cf5 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -25,6 +25,7 @@
 #include <nvif/driver.h>
 #include <nvif/ioctl.h>
 #include <nvif/class.h>
+#include <nvif/unpack.h>
 
 #include "nouveau_drm.h"
 #include "nouveau_dma.h"
@@ -347,6 +348,44 @@
 }
 
 int
+nouveau_abi16_usif(struct drm_file *file_priv, void *data, u32 size)
+{
+	union {
+		struct nvif_ioctl_v0 v0;
+	} *args = data;
+	struct nouveau_abi16_chan *chan;
+	struct nouveau_abi16 *abi16;
+	int ret;
+
+	if (nvif_unpack(args->v0, 0, 0, true)) {
+		switch (args->v0.type) {
+		case NVIF_IOCTL_V0_NEW:
+		case NVIF_IOCTL_V0_MTHD:
+		case NVIF_IOCTL_V0_SCLASS:
+			break;
+		default:
+			return -EACCES;
+		}
+	} else
+		return ret;
+
+	if (!(abi16 = nouveau_abi16(file_priv)))
+		return -ENOMEM;
+
+	if (args->v0.token != ~0ULL) {
+		if (!(chan = nouveau_abi16_chan(abi16, args->v0.token)))
+			return -EINVAL;
+		args->v0.object = nvif_handle(&chan->chan->user);
+		args->v0.owner  = NVIF_IOCTL_V0_OWNER_ANY;
+		return 0;
+	}
+
+	args->v0.object = nvif_handle(&abi16->device.object);
+	args->v0.owner  = NVIF_IOCTL_V0_OWNER_ANY;
+	return 0;
+}
+
+int
 nouveau_abi16_ioctl_channel_free(ABI16_IOCTL_ARGS)
 {
 	struct drm_nouveau_channel_free *req = data;
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.h b/drivers/gpu/drm/nouveau/nouveau_abi16.h
index fa1d856..841cc55 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.h
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.h
@@ -37,6 +37,7 @@
 int  nouveau_abi16_put(struct nouveau_abi16 *, int);
 void nouveau_abi16_fini(struct nouveau_abi16 *);
 s32  nouveau_abi16_swclass(struct nouveau_drm *);
+int  nouveau_abi16_usif(struct drm_file *, void *data, u32 size);
 
 #define NOUVEAU_GEM_DOMAIN_VRAM      (1 << 1)
 #define NOUVEAU_GEM_DOMAIN_GART      (1 << 2)
diff --git a/drivers/gpu/drm/nouveau/nouveau_usif.c b/drivers/gpu/drm/nouveau/nouveau_usif.c
index cb1182d..89dc4ce 100644
--- a/drivers/gpu/drm/nouveau/nouveau_usif.c
+++ b/drivers/gpu/drm/nouveau/nouveau_usif.c
@@ -24,6 +24,7 @@
 
 #include "nouveau_drm.h"
 #include "nouveau_usif.h"
+#include "nouveau_abi16.h"
 
 #include <nvif/notify.h>
 #include <nvif/unpack.h>
@@ -316,11 +317,21 @@
 	} else
 		goto done;
 
+	/* USIF slightly abuses some return-only ioctl members in order
+	 * to provide interoperability with the older ABI16 objects
+	 */
 	mutex_lock(&cli->mutex);
+	if (argv->v0.route) {
+		if (ret = -EINVAL, argv->v0.route == 0xff)
+			ret = nouveau_abi16_usif(filp, argv, argc);
+		if (ret) {
+			mutex_unlock(&cli->mutex);
+			goto done;
+		}
+	}
+
 	switch (argv->v0.type) {
 	case NVIF_IOCTL_V0_NEW:
-		/* ... except if we're creating children */
-		argv->v0.owner = NVIF_IOCTL_V0_OWNER_ANY;
 		ret = usif_object_new(filp, data, size, argv, argc);
 		break;
 	case NVIF_IOCTL_V0_NTFY_NEW: