Commit 10caad33 authored by Ben Skeggs's avatar Ben Skeggs

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: default avatarBen Skeggs <bskeggs@redhat.com>
parent 066a5d09
......@@ -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
......
......@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment