nouveau: add interfaces to query information about supported classes
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. v2. - add description of abi16/vdec workaround - add description of sclass/mclass - leave client-provided pointer unmodified on abi16_sclass() failure Signed-off-by: Ben Skeggs <bskeggs@redhat.com> Tested-by: Samuel Pitoiset <samuel.pitoiset@gmail.com> Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com>main
parent
c00e1a92a2
commit
f6b1b5b7c9
|
@ -29,12 +29,12 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
|
|
||||||
#include "nvif/class.h"
|
#include "nvif/class.h"
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
abi16_chan_nv04(struct nouveau_object *obj)
|
abi16_chan_nv04(struct nouveau_object *obj)
|
||||||
{
|
{
|
||||||
|
@ -171,6 +171,55 @@ abi16_ntfy(struct nouveau_object *obj)
|
||||||
return 0;
|
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
|
drm_private void
|
||||||
abi16_delete(struct nouveau_object *obj)
|
abi16_delete(struct nouveau_object *obj)
|
||||||
{
|
{
|
||||||
|
|
|
@ -33,8 +33,11 @@ nouveau_device_wrap
|
||||||
nouveau_getparam
|
nouveau_getparam
|
||||||
nouveau_object_del
|
nouveau_object_del
|
||||||
nouveau_object_find
|
nouveau_object_find
|
||||||
|
nouveau_object_mclass
|
||||||
nouveau_object_mthd
|
nouveau_object_mthd
|
||||||
nouveau_object_new
|
nouveau_object_new
|
||||||
|
nouveau_object_sclass_get
|
||||||
|
nouveau_object_sclass_put
|
||||||
nouveau_pushbuf_bufctx
|
nouveau_pushbuf_bufctx
|
||||||
nouveau_pushbuf_data
|
nouveau_pushbuf_data
|
||||||
nouveau_pushbuf_del
|
nouveau_pushbuf_del
|
||||||
|
|
|
@ -66,6 +66,47 @@ nouveau_object_mthd(struct nouveau_object *obj,
|
||||||
return -ENODEV;
|
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
|
static void
|
||||||
nouveau_object_fini(struct nouveau_object *obj)
|
nouveau_object_fini(struct nouveau_object *obj)
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,12 +63,34 @@ struct nv04_notify {
|
||||||
uint32_t length;
|
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,
|
int nouveau_object_new(struct nouveau_object *parent, uint64_t handle,
|
||||||
uint32_t oclass, void *data, uint32_t length,
|
uint32_t oclass, void *data, uint32_t length,
|
||||||
struct nouveau_object **);
|
struct nouveau_object **);
|
||||||
void nouveau_object_del(struct nouveau_object **);
|
void nouveau_object_del(struct nouveau_object **);
|
||||||
int nouveau_object_mthd(struct nouveau_object *, uint32_t mthd,
|
int nouveau_object_mthd(struct nouveau_object *, uint32_t mthd,
|
||||||
void *data, uint32_t size);
|
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);
|
void *nouveau_object_find(struct nouveau_object *, uint32_t parent_class);
|
||||||
|
|
||||||
struct nouveau_device {
|
struct nouveau_device {
|
||||||
|
|
|
@ -116,6 +116,7 @@ nouveau_device_open_existing(struct nouveau_device **, int, int, drm_context_t);
|
||||||
/* abi16.c */
|
/* abi16.c */
|
||||||
drm_private bool abi16_object(struct nouveau_object *, int (**)(struct nouveau_object *));
|
drm_private bool abi16_object(struct nouveau_object *, int (**)(struct nouveau_object *));
|
||||||
drm_private void abi16_delete(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 void abi16_bo_info(struct nouveau_bo *, struct drm_nouveau_gem_info *);
|
||||||
drm_private int abi16_bo_init(struct nouveau_bo *, uint32_t alignment,
|
drm_private int abi16_bo_init(struct nouveau_bo *, uint32_t alignment,
|
||||||
union nouveau_bo_config *);
|
union nouveau_bo_config *);
|
||||||
|
|
Loading…
Reference in New Issue