summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nouveau/abi16.c51
-rwxr-xr-xnouveau/nouveau-symbol-check3
-rw-r--r--nouveau/nouveau.c41
-rw-r--r--nouveau/nouveau.h22
-rw-r--r--nouveau/private.h1
5 files changed, 117 insertions, 1 deletions
diff --git a/nouveau/abi16.c b/nouveau/abi16.c
index 44fda645..f260bf95 100644
--- a/nouveau/abi16.c
+++ b/nouveau/abi16.c
@@ -29,12 +29,12 @@
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
+#include <errno.h>
#include "private.h"
#include "nvif/class.h"
-
static int
abi16_chan_nv04(struct nouveau_object *obj)
{
@@ -171,6 +171,55 @@ 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 = calloc(8, sizeof(*sclass))))
+ return -ENOMEM;
+ *psclass = sclass;
+
+ switch (obj->oclass) {
+ case NOUVEAU_FIFO_CHANNEL_CLASS:
+ /* Older kernel versions were exposing the wrong video engine
+ * classes on certain G98:GF100 boards. This has since been
+ * corrected, but ABI16 has compatibility in place to avoid
+ * breaking older userspace.
+ *
+ * Clients that have been updated to use NVIF are required to
+ * use the correct classes, which means that they'll break if
+ * running on an older kernel.
+ *
+ * To handle this issue, if using the older kernel interfaces,
+ * we'll magic up a list containing the vdec classes that the
+ * kernel will accept for these boards. Clients should make
+ * use of this information instead of hardcoding classes for
+ * specific chipsets.
+ */
+ dev = (struct nouveau_device *)obj->parent;
+ if (dev->chipset >= 0x98 &&
+ dev->chipset != 0xa0 &&
+ dev->chipset < 0xc0) {
+ *sclass++ = (struct nouveau_sclass){
+ GT212_MSVLD, -1, -1
+ };
+ *sclass++ = (struct nouveau_sclass){
+ GT212_MSPDEC, -1, -1
+ };
+ *sclass++ = (struct nouveau_sclass){
+ GT212_MSPPP, -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 73301702..38b6ec52 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 1871e8cd..00173034 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 4c95409e..24cda6f1 100644
--- a/nouveau/nouveau.h
+++ b/nouveau/nouveau.h
@@ -63,12 +63,34 @@ struct nv04_notify {
uint32_t length;
};
+/* Supported class information, provided by the kernel */
+struct nouveau_sclass {
+ int32_t oclass;
+ int minver;
+ int maxver;
+};
+
+/* Client-provided array describing class versions that are desired.
+ *
+ * These are used to match against the kernel's list of supported classes.
+ */
+struct nouveau_mclass {
+ int32_t oclass; /* 0 == EOL */
+ 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 5f352a49..83060f96 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 *);