drm/nouveau/device: tweak the device/subdev relationship a little
authorBen Skeggs <bskeggs@redhat.com>
Thu, 25 Apr 2013 01:43:54 +0000 (11:43 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Fri, 26 Apr 2013 05:38:14 +0000 (15:38 +1000)
Fixes not-in-use engines not having their reset() method called on
resume.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/core/engine/device/base.c
drivers/gpu/drm/nouveau/core/include/core/parent.h

index 497d5f6..86d2490 100644 (file)
@@ -55,7 +55,6 @@ nouveau_device_find(u64 name)
 struct nouveau_devobj {
        struct nouveau_parent base;
        struct nouveau_object *subdev[NVDEV_SUBDEV_NR];
-       bool created;
 };
 
 static const u64 disable_map[] = {
@@ -238,26 +237,24 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
        }
 
        /* ensure requested subsystems are available for use */
-       for (i = 0, c = 0; i < NVDEV_SUBDEV_NR; i++) {
+       for (i = 1, c = 1; i < NVDEV_SUBDEV_NR; i++) {
                if (!(oclass = device->oclass[i]) || (disable & (1ULL << i)))
                        continue;
 
-               if (!device->subdev[i]) {
-                       ret = nouveau_object_ctor(nv_object(device), NULL,
-                                                 oclass, NULL, i,
-                                                 &devobj->subdev[i]);
-                       if (ret == -ENODEV)
-                               continue;
-                       if (ret)
-                               return ret;
-
-                       if (nv_iclass(devobj->subdev[i], NV_ENGINE_CLASS))
-                               nouveau_subdev_reset(devobj->subdev[i]);
-               } else {
+               if (device->subdev[i]) {
                        nouveau_object_ref(device->subdev[i],
                                          &devobj->subdev[i]);
+                       continue;
                }
 
+               ret = nouveau_object_ctor(nv_object(device), NULL,
+                                         oclass, NULL, i,
+                                         &devobj->subdev[i]);
+               if (ret == -ENODEV)
+                       continue;
+               if (ret)
+                       return ret;
+
                /* note: can't init *any* subdevs until devinit has been run
                 * due to not knowing exactly what the vbios init tables will
                 * mess with.  devinit also can't be run until all of its
@@ -273,6 +270,10 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
                                ret = nouveau_object_inc(subdev);
                                if (ret)
                                        return ret;
+                               atomic_dec(&nv_object(device)->usecount);
+                       } else
+                       if (subdev) {
+                               nouveau_subdev_reset(subdev);
                        }
                }
        }
@@ -292,74 +293,6 @@ nouveau_devobj_dtor(struct nouveau_object *object)
        nouveau_parent_destroy(&devobj->base);
 }
 
-static int
-nouveau_devobj_init(struct nouveau_object *object)
-{
-       struct nouveau_devobj *devobj = (void *)object;
-       struct nouveau_object *subdev;
-       int ret, i;
-
-       ret = nouveau_parent_init(&devobj->base);
-       if (ret)
-               return ret;
-
-       for (i = 0; devobj->created && i < NVDEV_SUBDEV_NR; i++) {
-               if ((subdev = devobj->subdev[i])) {
-                       if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
-                               ret = nouveau_object_inc(subdev);
-                               if (ret)
-                                       goto fail;
-                       }
-               }
-       }
-
-       devobj->created = true;
-       return 0;
-
-fail:
-       for (--i; i >= 0; i--) {
-               if ((subdev = devobj->subdev[i])) {
-                       if (!nv_iclass(subdev, NV_ENGINE_CLASS))
-                               nouveau_object_dec(subdev, false);
-               }
-       }
-
-       return ret;
-}
-
-static int
-nouveau_devobj_fini(struct nouveau_object *object, bool suspend)
-{
-       struct nouveau_devobj *devobj = (void *)object;
-       struct nouveau_object *subdev;
-       int ret, i;
-
-       for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) {
-               if ((subdev = devobj->subdev[i])) {
-                       if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
-                               ret = nouveau_object_dec(subdev, suspend);
-                               if (ret && suspend)
-                                       goto fail;
-                       }
-               }
-       }
-
-       ret = nouveau_parent_fini(&devobj->base, suspend);
-fail:
-       for (; ret && suspend && i < NVDEV_SUBDEV_NR; i++) {
-               if ((subdev = devobj->subdev[i])) {
-                       if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
-                               ret = nouveau_object_inc(subdev);
-                               if (ret) {
-                                       /* XXX */
-                               }
-                       }
-               }
-       }
-
-       return ret;
-}
-
 static u8
 nouveau_devobj_rd08(struct nouveau_object *object, u64 addr)
 {
@@ -400,8 +333,8 @@ static struct nouveau_ofuncs
 nouveau_devobj_ofuncs = {
        .ctor = nouveau_devobj_ctor,
        .dtor = nouveau_devobj_dtor,
-       .init = nouveau_devobj_init,
-       .fini = nouveau_devobj_fini,
+       .init = _nouveau_parent_init,
+       .fini = _nouveau_parent_fini,
        .rd08 = nouveau_devobj_rd08,
        .rd16 = nouveau_devobj_rd16,
        .rd32 = nouveau_devobj_rd32,
@@ -423,14 +356,64 @@ static int
 nouveau_device_fini(struct nouveau_object *object, bool suspend)
 {
        struct nouveau_device *device = (void *)object;
-       return nouveau_subdev_fini(&device->base, suspend);
+       struct nouveau_object *subdev;
+       int ret, i;
+
+       for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) {
+               if ((subdev = device->subdev[i])) {
+                       if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
+                               ret = nouveau_object_dec(subdev, suspend);
+                               if (ret && suspend)
+                                       goto fail;
+                       }
+               }
+       }
+
+       ret = 0;
+fail:
+       for (; ret && i < NVDEV_SUBDEV_NR; i++) {
+               if ((subdev = device->subdev[i])) {
+                       if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
+                               ret = nouveau_object_inc(subdev);
+                               if (ret) {
+                                       /* XXX */
+                               }
+                       }
+               }
+       }
+
+       return ret;
 }
 
 static int
 nouveau_device_init(struct nouveau_object *object)
 {
        struct nouveau_device *device = (void *)object;
-       return nouveau_subdev_init(&device->base);
+       struct nouveau_object *subdev;
+       int ret, i;
+
+       for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
+               if ((subdev = device->subdev[i])) {
+                       if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
+                               ret = nouveau_object_inc(subdev);
+                               if (ret)
+                                       goto fail;
+                       } else {
+                               nouveau_subdev_reset(subdev);
+                       }
+               }
+       }
+
+       ret = 0;
+fail:
+       for (--i; ret && i >= 0; i--) {
+               if ((subdev = device->subdev[i])) {
+                       if (!nv_iclass(subdev, NV_ENGINE_CLASS))
+                               nouveau_object_dec(subdev, false);
+               }
+       }
+
+       return ret;
 }
 
 static void
index 31cd852..9f5ea90 100644 (file)
@@ -51,8 +51,8 @@ int  nouveau_parent_create_(struct nouveau_object *, struct nouveau_object *,
 void nouveau_parent_destroy(struct nouveau_parent *);
 
 void _nouveau_parent_dtor(struct nouveau_object *);
-#define _nouveau_parent_init _nouveau_object_init
-#define _nouveau_parent_fini _nouveau_object_fini
+#define _nouveau_parent_init nouveau_object_init
+#define _nouveau_parent_fini nouveau_object_fini
 
 int nouveau_parent_sclass(struct nouveau_object *, u16 handle,
                          struct nouveau_object **pengine,