OSDN Git Service

nouveau: move more abi16-specific logic into abi16.c
authorBen Skeggs <bskeggs@redhat.com>
Mon, 23 Nov 2015 23:17:52 +0000 (09:17 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 22 Dec 2015 03:21:56 +0000 (13:21 +1000)
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>
nouveau/abi16.c
nouveau/nouveau.c
nouveau/private.h

index 59bc436..44fda64 100644 (file)
 
 #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);
index 97fd77b..8a0be2f 100644 (file)
@@ -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 *
index e9439f3..5f352a4 100644 (file)
@@ -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 *);