diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2013-04-25 05:43:54 +0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2013-04-26 09:38:14 +0400 |
commit | 10caad339c458df47e5a9e16e148087fcde98fec (patch) | |
tree | c704ebc81bd3f904eeda8a281d3c0c7efea072be | |
parent | 066a5d0938c64bec665866b145d8538d9f96bcda (diff) | |
download | linux-10caad339c458df47e5a9e16e148087fcde98fec.tar.xz |
drm/nouveau/device: tweak the device/subdev relationship a little
Fixes not-in-use engines not having their reset() method called on
resume.
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/device/base.c | 155 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/include/core/parent.h | 4 |
2 files changed, 71 insertions, 88 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/base.c b/drivers/gpu/drm/nouveau/core/engine/device/base.c index 497d5f60a195..86d24904e9d3 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/base.c @@ -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 diff --git a/drivers/gpu/drm/nouveau/core/include/core/parent.h b/drivers/gpu/drm/nouveau/core/include/core/parent.h index 31cd852c96df..9f5ea900ff00 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/parent.h +++ b/drivers/gpu/drm/nouveau/core/include/core/parent.h @@ -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, |