nouveau: move more abi16-specific logic into abi16.c
v2. - add a comment about the (ab)use of nouveau_object::length - add a comment about abi16_object() return values v3. - handle new client + old kernel for sw classes 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
d1ec093e4c
commit
4a3cbf5c0a
|
@ -32,8 +32,10 @@
|
||||||
|
|
||||||
#include "private.h"
|
#include "private.h"
|
||||||
|
|
||||||
|
#include "nvif/class.h"
|
||||||
|
|
||||||
drm_private int
|
|
||||||
|
static int
|
||||||
abi16_chan_nv04(struct nouveau_object *obj)
|
abi16_chan_nv04(struct nouveau_object *obj)
|
||||||
{
|
{
|
||||||
struct nouveau_device *dev = (struct nouveau_device *)obj->parent;
|
struct nouveau_device *dev = (struct nouveau_device *)obj->parent;
|
||||||
|
@ -57,7 +59,7 @@ abi16_chan_nv04(struct nouveau_object *obj)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
drm_private int
|
static int
|
||||||
abi16_chan_nvc0(struct nouveau_object *obj)
|
abi16_chan_nvc0(struct nouveau_object *obj)
|
||||||
{
|
{
|
||||||
struct nouveau_device *dev = (struct nouveau_device *)obj->parent;
|
struct nouveau_device *dev = (struct nouveau_device *)obj->parent;
|
||||||
|
@ -78,7 +80,7 @@ abi16_chan_nvc0(struct nouveau_object *obj)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
drm_private int
|
static int
|
||||||
abi16_chan_nve0(struct nouveau_object *obj)
|
abi16_chan_nve0(struct nouveau_object *obj)
|
||||||
{
|
{
|
||||||
struct nouveau_device *dev = (struct nouveau_device *)obj->parent;
|
struct nouveau_device *dev = (struct nouveau_device *)obj->parent;
|
||||||
|
@ -104,7 +106,7 @@ abi16_chan_nve0(struct nouveau_object *obj)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
drm_private int
|
static int
|
||||||
abi16_engobj(struct nouveau_object *obj)
|
abi16_engobj(struct nouveau_object *obj)
|
||||||
{
|
{
|
||||||
struct drm_nouveau_grobj_alloc req = {
|
struct drm_nouveau_grobj_alloc req = {
|
||||||
|
@ -115,6 +117,27 @@ abi16_engobj(struct nouveau_object *obj)
|
||||||
struct nouveau_device *dev;
|
struct nouveau_device *dev;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* Older kernel versions did not have the concept of nouveau-
|
||||||
|
* specific classes and abused some NVIDIA-assigned ones for
|
||||||
|
* a SW class. The ABI16 layer has compatibility in place to
|
||||||
|
* translate these older identifiers to the newer ones.
|
||||||
|
*
|
||||||
|
* Clients that have been updated to use NVIF are required to
|
||||||
|
* use the newer class identifiers, which means that they'll
|
||||||
|
* break if running on an older kernel.
|
||||||
|
*
|
||||||
|
* To handle this case, when using ABI16, we translate to the
|
||||||
|
* older values which work on any kernel.
|
||||||
|
*/
|
||||||
|
switch (req.class) {
|
||||||
|
case NVIF_CLASS_SW_NV04 : req.class = 0x006e; break;
|
||||||
|
case NVIF_CLASS_SW_NV10 : req.class = 0x016e; break;
|
||||||
|
case NVIF_CLASS_SW_NV50 : req.class = 0x506e; break;
|
||||||
|
case NVIF_CLASS_SW_GF100: req.class = 0x906e; break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS);
|
dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS);
|
||||||
ret = drmCommandWrite(dev->fd, DRM_NOUVEAU_GROBJ_ALLOC,
|
ret = drmCommandWrite(dev->fd, DRM_NOUVEAU_GROBJ_ALLOC,
|
||||||
&req, sizeof(req));
|
&req, sizeof(req));
|
||||||
|
@ -125,7 +148,7 @@ abi16_engobj(struct nouveau_object *obj)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
drm_private int
|
static int
|
||||||
abi16_ntfy(struct nouveau_object *obj)
|
abi16_ntfy(struct nouveau_object *obj)
|
||||||
{
|
{
|
||||||
struct nv04_notify *ntfy = obj->data;
|
struct nv04_notify *ntfy = obj->data;
|
||||||
|
@ -148,6 +171,61 @@ abi16_ntfy(struct nouveau_object *obj)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
drm_private void
|
||||||
|
abi16_delete(struct nouveau_object *obj)
|
||||||
|
{
|
||||||
|
struct nouveau_device *dev =
|
||||||
|
nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS);
|
||||||
|
if (obj->oclass == NOUVEAU_FIFO_CHANNEL_CLASS) {
|
||||||
|
struct drm_nouveau_channel_free req;
|
||||||
|
req.channel = obj->handle;
|
||||||
|
drmCommandWrite(dev->fd, DRM_NOUVEAU_CHANNEL_FREE,
|
||||||
|
&req, sizeof(req));
|
||||||
|
} else {
|
||||||
|
struct drm_nouveau_gpuobj_free req;
|
||||||
|
req.channel = obj->parent->handle;
|
||||||
|
req.handle = obj->handle;
|
||||||
|
drmCommandWrite(dev->fd, DRM_NOUVEAU_GPUOBJ_FREE,
|
||||||
|
&req, sizeof(req));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_private bool
|
||||||
|
abi16_object(struct nouveau_object *obj, int (**func)(struct nouveau_object *))
|
||||||
|
{
|
||||||
|
struct nouveau_object *parent = obj->parent;
|
||||||
|
|
||||||
|
/* nouveau_object::length is (ab)used to determine whether the
|
||||||
|
* object is a legacy object (!=0), or a real NVIF object.
|
||||||
|
*/
|
||||||
|
if ((parent->length != 0 && parent->oclass == NOUVEAU_DEVICE_CLASS)) {
|
||||||
|
if (obj->oclass == NOUVEAU_FIFO_CHANNEL_CLASS) {
|
||||||
|
struct nouveau_device *dev = (void *)parent;
|
||||||
|
if (dev->chipset < 0xc0)
|
||||||
|
*func = abi16_chan_nv04;
|
||||||
|
else
|
||||||
|
if (dev->chipset < 0xe0)
|
||||||
|
*func = abi16_chan_nvc0;
|
||||||
|
else
|
||||||
|
*func = abi16_chan_nve0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
if ((parent->length != 0 &&
|
||||||
|
parent->oclass == NOUVEAU_FIFO_CHANNEL_CLASS)) {
|
||||||
|
if (obj->oclass == NOUVEAU_NOTIFIER_CLASS) {
|
||||||
|
*func = abi16_ntfy;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
*func = abi16_engobj;
|
||||||
|
return false; /* try NVIF, if supported, before calling func */
|
||||||
|
}
|
||||||
|
|
||||||
|
*func = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
drm_private void
|
drm_private void
|
||||||
abi16_bo_info(struct nouveau_bo *bo, struct drm_nouveau_gem_info *info)
|
abi16_bo_info(struct nouveau_bo *bo, struct drm_nouveau_gem_info *info)
|
||||||
{
|
{
|
||||||
|
|
|
@ -135,6 +135,7 @@ nouveau_device_wrap(int fd, int close, struct nouveau_device **pdev)
|
||||||
nvdev->gart_limit_percent = 80;
|
nvdev->gart_limit_percent = 80;
|
||||||
DRMINITLISTHEAD(&nvdev->bo_list);
|
DRMINITLISTHEAD(&nvdev->bo_list);
|
||||||
nvdev->base.object.oclass = NOUVEAU_DEVICE_CLASS;
|
nvdev->base.object.oclass = NOUVEAU_DEVICE_CLASS;
|
||||||
|
nvdev->base.object.length = ~0;
|
||||||
nvdev->base.lib_version = 0x01000000;
|
nvdev->base.lib_version = 0x01000000;
|
||||||
nvdev->base.chipset = chipset;
|
nvdev->base.chipset = chipset;
|
||||||
nvdev->base.vram_size = vram;
|
nvdev->base.vram_size = vram;
|
||||||
|
@ -251,8 +252,8 @@ 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 **pobj)
|
struct nouveau_object **pobj)
|
||||||
{
|
{
|
||||||
struct nouveau_device *dev;
|
|
||||||
struct nouveau_object *obj;
|
struct nouveau_object *obj;
|
||||||
|
int (*func)(struct nouveau_object *);
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
|
@ -267,37 +268,9 @@ nouveau_object_new(struct nouveau_object *parent, uint64_t handle,
|
||||||
memcpy(obj->data, data, length);
|
memcpy(obj->data, data, length);
|
||||||
*(struct nouveau_object **)obj->data = obj;
|
*(struct nouveau_object **)obj->data = obj;
|
||||||
|
|
||||||
dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS);
|
abi16_object(obj, &func);
|
||||||
switch (parent->oclass) {
|
if (func)
|
||||||
case NOUVEAU_DEVICE_CLASS:
|
ret = func(obj);
|
||||||
switch (obj->oclass) {
|
|
||||||
case NOUVEAU_FIFO_CHANNEL_CLASS:
|
|
||||||
{
|
|
||||||
if (dev->chipset < 0xc0)
|
|
||||||
ret = abi16_chan_nv04(obj);
|
|
||||||
else
|
|
||||||
if (dev->chipset < 0xe0)
|
|
||||||
ret = abi16_chan_nvc0(obj);
|
|
||||||
else
|
|
||||||
ret = abi16_chan_nve0(obj);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NOUVEAU_FIFO_CHANNEL_CLASS:
|
|
||||||
switch (obj->oclass) {
|
|
||||||
case NOUVEAU_NOTIFIER_CLASS:
|
|
||||||
ret = abi16_ntfy(obj);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = abi16_engobj(obj);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
free(obj);
|
free(obj);
|
||||||
|
@ -312,24 +285,11 @@ void
|
||||||
nouveau_object_del(struct nouveau_object **pobj)
|
nouveau_object_del(struct nouveau_object **pobj)
|
||||||
{
|
{
|
||||||
struct nouveau_object *obj = *pobj;
|
struct nouveau_object *obj = *pobj;
|
||||||
struct nouveau_device *dev;
|
|
||||||
if (obj) {
|
if (obj) {
|
||||||
dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS);
|
abi16_delete(obj);
|
||||||
if (obj->oclass == NOUVEAU_FIFO_CHANNEL_CLASS) {
|
free(obj);
|
||||||
struct drm_nouveau_channel_free req;
|
*pobj = NULL;
|
||||||
req.channel = obj->handle;
|
|
||||||
drmCommandWrite(dev->fd, DRM_NOUVEAU_CHANNEL_FREE,
|
|
||||||
&req, sizeof(req));
|
|
||||||
} else {
|
|
||||||
struct drm_nouveau_gpuobj_free req;
|
|
||||||
req.channel = obj->parent->handle;
|
|
||||||
req.handle = obj->handle;
|
|
||||||
drmCommandWrite(dev->fd, DRM_NOUVEAU_GPUOBJ_FREE,
|
|
||||||
&req, sizeof(req));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
free(obj);
|
|
||||||
*pobj = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
|
|
|
@ -114,11 +114,8 @@ int
|
||||||
nouveau_device_open_existing(struct nouveau_device **, int, int, drm_context_t);
|
nouveau_device_open_existing(struct nouveau_device **, int, int, drm_context_t);
|
||||||
|
|
||||||
/* abi16.c */
|
/* abi16.c */
|
||||||
drm_private int abi16_chan_nv04(struct nouveau_object *);
|
drm_private bool abi16_object(struct nouveau_object *, int (**)(struct nouveau_object *));
|
||||||
drm_private int abi16_chan_nvc0(struct nouveau_object *);
|
drm_private void abi16_delete(struct nouveau_object *);
|
||||||
drm_private int abi16_chan_nve0(struct nouveau_object *);
|
|
||||||
drm_private int abi16_engobj(struct nouveau_object *);
|
|
||||||
drm_private int abi16_ntfy(struct nouveau_object *);
|
|
||||||
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