diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2015-11-24 09:17:52 +1000 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2015-12-22 13:21:56 +1000 |
commit | 4a3cbf5c0a38adf41d637c5d7273480336df39d0 (patch) | |
tree | bb07ba39db1d77bf2c86c1d9d76dbe0474f575d6 /nouveau | |
parent | d1ec093e4c5b08c3825fe07e287aa3d023e9c9ae (diff) | |
download | drm-4a3cbf5c0a38adf41d637c5d7273480336df39d0.tar.gz |
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>
Diffstat (limited to 'nouveau')
-rw-r--r-- | nouveau/abi16.c | 88 | ||||
-rw-r--r-- | nouveau/nouveau.c | 56 | ||||
-rw-r--r-- | nouveau/private.h | 7 |
3 files changed, 93 insertions, 58 deletions
diff --git a/nouveau/abi16.c b/nouveau/abi16.c index 59bc4360..44fda645 100644 --- a/nouveau/abi16.c +++ b/nouveau/abi16.c @@ -32,8 +32,10 @@ #include "private.h" +#include "nvif/class.h" -drm_private int + +static int abi16_chan_nv04(struct nouveau_object *obj) { struct nouveau_device *dev = (struct nouveau_device *)obj->parent; @@ -57,7 +59,7 @@ abi16_chan_nv04(struct nouveau_object *obj) return 0; } -drm_private int +static int abi16_chan_nvc0(struct nouveau_object *obj) { struct nouveau_device *dev = (struct nouveau_device *)obj->parent; @@ -78,7 +80,7 @@ abi16_chan_nvc0(struct nouveau_object *obj) return 0; } -drm_private int +static int abi16_chan_nve0(struct nouveau_object *obj) { struct nouveau_device *dev = (struct nouveau_device *)obj->parent; @@ -104,7 +106,7 @@ abi16_chan_nve0(struct nouveau_object *obj) return 0; } -drm_private int +static int abi16_engobj(struct nouveau_object *obj) { struct drm_nouveau_grobj_alloc req = { @@ -115,6 +117,27 @@ abi16_engobj(struct nouveau_object *obj) struct nouveau_device *dev; 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); ret = drmCommandWrite(dev->fd, DRM_NOUVEAU_GROBJ_ALLOC, &req, sizeof(req)); @@ -125,7 +148,7 @@ abi16_engobj(struct nouveau_object *obj) return 0; } -drm_private int +static int abi16_ntfy(struct nouveau_object *obj) { struct nv04_notify *ntfy = obj->data; @@ -149,6 +172,61 @@ abi16_ntfy(struct nouveau_object *obj) } 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 abi16_bo_info(struct nouveau_bo *bo, struct drm_nouveau_gem_info *info) { struct nouveau_bo_priv *nvbo = nouveau_bo(bo); diff --git a/nouveau/nouveau.c b/nouveau/nouveau.c index 97fd77b9..8a0be2fa 100644 --- a/nouveau/nouveau.c +++ b/nouveau/nouveau.c @@ -135,6 +135,7 @@ nouveau_device_wrap(int fd, int close, struct nouveau_device **pdev) nvdev->gart_limit_percent = 80; DRMINITLISTHEAD(&nvdev->bo_list); nvdev->base.object.oclass = NOUVEAU_DEVICE_CLASS; + nvdev->base.object.length = ~0; nvdev->base.lib_version = 0x01000000; nvdev->base.chipset = chipset; 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, struct nouveau_object **pobj) { - struct nouveau_device *dev; struct nouveau_object *obj; + int (*func)(struct nouveau_object *); int ret = -EINVAL; if (length == 0) @@ -267,37 +268,9 @@ nouveau_object_new(struct nouveau_object *parent, uint64_t handle, memcpy(obj->data, data, length); *(struct nouveau_object **)obj->data = obj; - dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS); - switch (parent->oclass) { - case NOUVEAU_DEVICE_CLASS: - 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; - } + abi16_object(obj, &func); + if (func) + ret = func(obj); if (ret) { free(obj); @@ -312,24 +285,11 @@ void nouveau_object_del(struct nouveau_object **pobj) { struct nouveau_object *obj = *pobj; - struct nouveau_device *dev; if (obj) { - 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)); - } + abi16_delete(obj); + free(obj); + *pobj = NULL; } - free(obj); - *pobj = NULL; } void * diff --git a/nouveau/private.h b/nouveau/private.h index e9439f30..5f352a49 100644 --- a/nouveau/private.h +++ b/nouveau/private.h @@ -114,11 +114,8 @@ int nouveau_device_open_existing(struct nouveau_device **, int, int, drm_context_t); /* abi16.c */ -drm_private int abi16_chan_nv04(struct nouveau_object *); -drm_private int abi16_chan_nvc0(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 bool abi16_object(struct nouveau_object *, int (**)(struct nouveau_object *)); +drm_private void abi16_delete(struct nouveau_object *); 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 *); |