[Nouveau] [libdrm 05/13] nouveau: add interfaces to query information about supported classes

Ben Skeggs skeggsb at gmail.com
Wed Nov 25 23:14:02 PST 2015


From: Ben Skeggs <bskeggs at redhat.com>

This will expose functionality supported by newer kernel interfaces.

Current userspace uses the chipset to determine which classes are likely
exposed, which generally works pretty well, but isn't as flexible as it
could be.

Unfortunately, the G98:GF100 video code in Mesa is still relying on the
kernel exposing incorrect vdec classes on some chipsets.  The ABI16
kernel interfaces have a workaround for this in place, but that will no
longer be available once libdrm supports NVIF.

To prevent a regression when NVIF support is added, if there's no kernel
support for NVIF, libdrm will magic up a class list containing correct
vdec classes anyway instead of failing with -ENODEV.

Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
---
 nouveau/abi16.c              | 28 ++++++++++++++++++++++++++++
 nouveau/nouveau-symbol-check |  3 +++
 nouveau/nouveau.c            | 41 +++++++++++++++++++++++++++++++++++++++++
 nouveau/nouveau.h            | 17 +++++++++++++++++
 nouveau/private.h            |  1 +
 5 files changed, 90 insertions(+)

diff --git a/nouveau/abi16.c b/nouveau/abi16.c
index 8f24ba2..34e9fb1 100644
--- a/nouveau/abi16.c
+++ b/nouveau/abi16.c
@@ -29,6 +29,7 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <stddef.h>
+#include <errno.h>
 
 #include "private.h"
 
@@ -148,6 +149,33 @@ abi16_ntfy(struct nouveau_object *obj)
 	return 0;
 }
 
+drm_private int
+abi16_sclass(struct nouveau_object *obj, struct nouveau_sclass **psclass)
+{
+	struct nouveau_sclass *sclass;
+	struct nouveau_device *dev;
+
+	if (!(sclass = *psclass = calloc(8, sizeof(*sclass))))
+		return -ENOMEM;
+
+	switch (obj->oclass) {
+	case NOUVEAU_FIFO_CHANNEL_CLASS:
+		dev = (struct nouveau_device *)obj->parent;
+		if (dev->chipset >= 0x98 &&
+		    dev->chipset != 0xa0 &&
+		    dev->chipset <  0xc0) {
+			*sclass++ = (struct nouveau_sclass){ 0x85b1, -1, -1 };
+			*sclass++ = (struct nouveau_sclass){ 0x85b2, -1, -1 };
+			*sclass++ = (struct nouveau_sclass){ 0x85b3, -1, -1 };
+		}
+		break;
+	default:
+		break;
+	}
+
+	return sclass - *psclass;
+}
+
 drm_private void
 abi16_delete(struct nouveau_object *obj)
 {
diff --git a/nouveau/nouveau-symbol-check b/nouveau/nouveau-symbol-check
index 7330170..38b6ec5 100755
--- a/nouveau/nouveau-symbol-check
+++ b/nouveau/nouveau-symbol-check
@@ -33,8 +33,11 @@ nouveau_device_wrap
 nouveau_getparam
 nouveau_object_del
 nouveau_object_find
+nouveau_object_mclass
 nouveau_object_mthd
 nouveau_object_new
+nouveau_object_sclass_get
+nouveau_object_sclass_put
 nouveau_pushbuf_bufctx
 nouveau_pushbuf_data
 nouveau_pushbuf_del
diff --git a/nouveau/nouveau.c b/nouveau/nouveau.c
index 1871e8c..0017303 100644
--- a/nouveau/nouveau.c
+++ b/nouveau/nouveau.c
@@ -66,6 +66,47 @@ nouveau_object_mthd(struct nouveau_object *obj,
 	return -ENODEV;
 }
 
+void
+nouveau_object_sclass_put(struct nouveau_sclass **psclass)
+{
+	free(*psclass);
+	*psclass = NULL;
+}
+
+int
+nouveau_object_sclass_get(struct nouveau_object *obj,
+			  struct nouveau_sclass **psclass)
+{
+	return abi16_sclass(obj, psclass);
+}
+
+int
+nouveau_object_mclass(struct nouveau_object *obj,
+		      const struct nouveau_mclass *mclass)
+{
+	struct nouveau_sclass *sclass;
+	int ret = -ENODEV;
+	int cnt, i, j;
+
+	cnt = nouveau_object_sclass_get(obj, &sclass);
+	if (cnt < 0)
+		return cnt;
+
+	for (i = 0; ret < 0 && mclass[i].oclass; i++) {
+		for (j = 0; j < cnt; j++) {
+			if (mclass[i].oclass  == sclass[j].oclass &&
+			    mclass[i].version >= sclass[j].minver &&
+			    mclass[i].version <= sclass[j].maxver) {
+				ret = i;
+				break;
+			}
+		}
+	}
+
+	nouveau_object_sclass_put(&sclass);
+	return ret;
+}
+
 static void
 nouveau_object_fini(struct nouveau_object *obj)
 {
diff --git a/nouveau/nouveau.h b/nouveau/nouveau.h
index 4c95409..9f774ab 100644
--- a/nouveau/nouveau.h
+++ b/nouveau/nouveau.h
@@ -63,12 +63,29 @@ struct nv04_notify {
 	uint32_t length;
 };
 
+struct nouveau_sclass {
+	int32_t oclass;
+	int minver;
+	int maxver;
+};
+
+struct nouveau_mclass {
+	int32_t oclass;
+	int version;
+	void *data;
+};
+
 int  nouveau_object_new(struct nouveau_object *parent, uint64_t handle,
 			uint32_t oclass, void *data, uint32_t length,
 			struct nouveau_object **);
 void nouveau_object_del(struct nouveau_object **);
 int  nouveau_object_mthd(struct nouveau_object *, uint32_t mthd,
 			 void *data, uint32_t size);
+int  nouveau_object_sclass_get(struct nouveau_object *,
+			       struct nouveau_sclass **);
+void nouveau_object_sclass_put(struct nouveau_sclass **);
+int  nouveau_object_mclass(struct nouveau_object *,
+			   const struct nouveau_mclass *);
 void *nouveau_object_find(struct nouveau_object *, uint32_t parent_class);
 
 struct nouveau_device {
diff --git a/nouveau/private.h b/nouveau/private.h
index 5f352a4..83060f9 100644
--- a/nouveau/private.h
+++ b/nouveau/private.h
@@ -116,6 +116,7 @@ nouveau_device_open_existing(struct nouveau_device **, int, int, drm_context_t);
 /* abi16.c */
 drm_private bool abi16_object(struct nouveau_object *, int (**)(struct nouveau_object *));
 drm_private void abi16_delete(struct nouveau_object *);
+drm_private int  abi16_sclass(struct nouveau_object *, struct nouveau_sclass **);
 drm_private void abi16_bo_info(struct nouveau_bo *, struct drm_nouveau_gem_info *);
 drm_private int  abi16_bo_init(struct nouveau_bo *, uint32_t alignment,
 			       union nouveau_bo_config *);
-- 
2.6.3



More information about the Nouveau mailing list