From: Ben Skeggs <bske...@redhat.com>

Signed-off-by: Ben Skeggs <bske...@redhat.com>
---
 nouveau/nouveau-symbol-check |   1 +
 nouveau/nouveau.c            | 133 ++++++++++++++++++++++++++++---------------
 nouveau/nouveau.h            |   2 +
 3 files changed, 89 insertions(+), 47 deletions(-)

diff --git a/nouveau/nouveau-symbol-check b/nouveau/nouveau-symbol-check
index 275b6e7..b265cea 100755
--- a/nouveau/nouveau-symbol-check
+++ b/nouveau/nouveau-symbol-check
@@ -27,6 +27,7 @@ nouveau_bufctx_reset
 nouveau_client_del
 nouveau_client_new
 nouveau_device_del
+nouveau_device_new
 nouveau_device_open
 nouveau_device_open_existing
 nouveau_device_wrap
diff --git a/nouveau/nouveau.c b/nouveau/nouveau.c
index 56e00ac..fef338b 100644
--- a/nouveau/nouveau.c
+++ b/nouveau/nouveau.c
@@ -45,6 +45,10 @@
 #include "nouveau.h"
 #include "private.h"
 
+#include "nvif/class.h"
+#include "nvif/cl0080.h"
+#include "nvif/unpack.h"
+
 #ifdef DEBUG
 drm_private uint32_t nouveau_debug = 0;
 
@@ -231,75 +235,107 @@ nouveau_device_open_existing(struct nouveau_device 
**pdev, int close, int fd,
 }
 
 int
-nouveau_device_wrap(int fd, int close, struct nouveau_device **pdev)
+nouveau_device_new(struct nouveau_object *parent, int32_t oclass,
+                  void *data, uint32_t size, struct nouveau_device **pdev)
 {
-       struct nouveau_drm *drm;
+       union {
+               struct nv_device_v0 v0;
+       } *args = data;
+       struct nouveau_drm *drm = nouveau_drm(parent);
        struct nouveau_device_priv *nvdev;
        struct nouveau_device *dev;
-       uint64_t chipset, vram, gart, bousage;
-       int ret;
+       uint64_t v;
        char *tmp;
+       int ret = -ENOSYS;
+
+       if (oclass != NV_DEVICE ||
+           nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))
+               return ret;
 
        if (!(nvdev = calloc(1, sizeof(*nvdev))))
                return -ENOMEM;
-       dev = &nvdev->base;
+       dev = *pdev = &nvdev->base;
+       dev->fd = -1;
 
-       ret = pthread_mutex_init(&nvdev->lock, NULL);
-       if (ret) {
-               free(nvdev);
-               return ret;
-       }
-
-       ret = nouveau_drm_new(fd, &drm);
-       if (ret) {
-               nouveau_device_del(&dev);
-               return ret;
-       }
-       drm->nvif = false;
+       if (args->v0.device == ~0ULL) {
+               nvdev->base.object.parent = &drm->client;
+               nvdev->base.object.handle = ~0ULL;
+               nvdev->base.object.oclass = NOUVEAU_DEVICE_CLASS;
+               nvdev->base.object.length = ~0;
 
-       nvdev->base.object.parent = &drm->client;
-       nvdev->base.object.oclass = NOUVEAU_DEVICE_CLASS;
-       nvdev->base.object.length = ~0;
-       nvdev->base.fd = drm->fd;
-       nvdev->base.drm_version = drm->drm_version;
-       nvdev->base.lib_version = drm->lib_version;
+               ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_CHIPSET_ID, &v);
+               if (ret)
+                       goto done;
+               nvdev->base.chipset = v;
 
-       ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_CHIPSET_ID, &chipset);
-       if (ret == 0)
-       ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_FB_SIZE, &vram);
-       if (ret == 0)
-       ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_AGP_SIZE, &gart);
-       if (ret) {
-               nouveau_device_del(&dev);
-               return ret;
-       }
+               ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_HAS_BO_USAGE, &v);
+               if (ret == 0)
+                       nvdev->have_bo_usage = (v != 0);
+       } else
+               return -ENOSYS;
 
-       ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_HAS_BO_USAGE, &bousage);
-       if (ret == 0)
-               nvdev->have_bo_usage = (bousage != 0);
+       ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_FB_SIZE, &v);
+       if (ret)
+               goto done;
+       nvdev->base.vram_size = v;
 
-       nvdev->close = close;
+       ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_AGP_SIZE, &v);
+       if (ret)
+               goto done;
+       nvdev->base.gart_size = v;
 
        tmp = getenv("NOUVEAU_LIBDRM_VRAM_LIMIT_PERCENT");
        if (tmp)
                nvdev->vram_limit_percent = atoi(tmp);
        else
                nvdev->vram_limit_percent = 80;
+
+       nvdev->base.vram_limit =
+               (nvdev->base.vram_size * nvdev->vram_limit_percent) / 100;
+
        tmp = getenv("NOUVEAU_LIBDRM_GART_LIMIT_PERCENT");
        if (tmp)
                nvdev->gart_limit_percent = atoi(tmp);
        else
                nvdev->gart_limit_percent = 80;
-       DRMINITLISTHEAD(&nvdev->bo_list);
-       nvdev->base.chipset = chipset;
-       nvdev->base.vram_size = vram;
-       nvdev->base.gart_size = gart;
-       nvdev->base.vram_limit =
-               (nvdev->base.vram_size * nvdev->vram_limit_percent) / 100;
+
        nvdev->base.gart_limit =
                (nvdev->base.gart_size * nvdev->gart_limit_percent) / 100;
 
-       *pdev = &nvdev->base;
+       ret = pthread_mutex_init(&nvdev->lock, NULL);
+       DRMINITLISTHEAD(&nvdev->bo_list);
+done:
+       if (ret)
+               nouveau_device_del(pdev);
+       return ret;
+}
+
+int
+nouveau_device_wrap(int fd, int close, struct nouveau_device **pdev)
+{
+       struct nouveau_drm *drm;
+       struct nouveau_device_priv *nvdev;
+       int ret;
+
+       ret = nouveau_drm_new(fd, &drm);
+       if (ret)
+               return ret;
+       drm->nvif = false;
+
+       ret = nouveau_device_new(&drm->client, NV_DEVICE,
+                                &(struct nv_device_v0) {
+                                       .device = ~0ULL,
+                                }, sizeof(struct nv_device_v0), pdev);
+       if (ret) {
+               nouveau_drm_del(&drm);
+               return ret;
+       }
+
+       nvdev = nouveau_device(*pdev);
+       nvdev->base.fd = drm->fd;
+       nvdev->base.drm_version = drm->drm_version;
+       nvdev->base.lib_version = drm->lib_version;
+       nvdev->close = close;
        return 0;
 }
 
@@ -320,12 +356,15 @@ nouveau_device_del(struct nouveau_device **pdev)
 {
        struct nouveau_device_priv *nvdev = nouveau_device(*pdev);
        if (nvdev) {
-               struct nouveau_drm *drm = nouveau_drm(&nvdev->base.object);
                free(nvdev->client);
-               nouveau_drm_del(&drm);
                pthread_mutex_destroy(&nvdev->lock);
-               if (nvdev->close)
-                       drmClose(nvdev->base.fd);
+               if (nvdev->base.fd >= 0) {
+                       struct nouveau_drm *drm =
+                               nouveau_drm(&nvdev->base.object);
+                       nouveau_drm_del(&drm);
+                       if (nvdev->close)
+                               drmClose(nvdev->base.fd);
+               }
                free(nvdev);
                *pdev = NULL;
        }
diff --git a/nouveau/nouveau.h b/nouveau/nouveau.h
index a693acf..f3cf8f5 100644
--- a/nouveau/nouveau.h
+++ b/nouveau/nouveau.h
@@ -122,6 +122,8 @@ struct nouveau_device {
        uint64_t gart_limit;
 };
 
+int  nouveau_device_new(struct nouveau_object *parent, int32_t oclass,
+                       void *data, uint32_t size, struct nouveau_device **);
 int  nouveau_device_wrap(int fd, int close, struct nouveau_device **);
 int  nouveau_device_open(const char *busid, struct nouveau_device **);
 void nouveau_device_del(struct nouveau_device **);
-- 
2.6.4

_______________________________________________
Nouveau mailing list
Nouveau@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/nouveau

Reply via email to