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>
This commit is contained in:
parent
066a5d0938
commit
10caad339c
2 changed files with 71 additions and 88 deletions
|
@ -55,7 +55,6 @@ nouveau_device_find(u64 name)
|
||||||
struct nouveau_devobj {
|
struct nouveau_devobj {
|
||||||
struct nouveau_parent base;
|
struct nouveau_parent base;
|
||||||
struct nouveau_object *subdev[NVDEV_SUBDEV_NR];
|
struct nouveau_object *subdev[NVDEV_SUBDEV_NR];
|
||||||
bool created;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const u64 disable_map[] = {
|
static const u64 disable_map[] = {
|
||||||
|
@ -238,26 +237,24 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ensure requested subsystems are available for use */
|
/* 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)))
|
if (!(oclass = device->oclass[i]) || (disable & (1ULL << i)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!device->subdev[i]) {
|
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 {
|
|
||||||
nouveau_object_ref(device->subdev[i],
|
nouveau_object_ref(device->subdev[i],
|
||||||
&devobj->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
|
/* note: can't init *any* subdevs until devinit has been run
|
||||||
* due to not knowing exactly what the vbios init tables will
|
* due to not knowing exactly what the vbios init tables will
|
||||||
* mess with. devinit also can't be run until all of its
|
* 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);
|
ret = nouveau_object_inc(subdev);
|
||||||
if (ret)
|
if (ret)
|
||||||
return 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);
|
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
|
static u8
|
||||||
nouveau_devobj_rd08(struct nouveau_object *object, u64 addr)
|
nouveau_devobj_rd08(struct nouveau_object *object, u64 addr)
|
||||||
{
|
{
|
||||||
|
@ -400,8 +333,8 @@ static struct nouveau_ofuncs
|
||||||
nouveau_devobj_ofuncs = {
|
nouveau_devobj_ofuncs = {
|
||||||
.ctor = nouveau_devobj_ctor,
|
.ctor = nouveau_devobj_ctor,
|
||||||
.dtor = nouveau_devobj_dtor,
|
.dtor = nouveau_devobj_dtor,
|
||||||
.init = nouveau_devobj_init,
|
.init = _nouveau_parent_init,
|
||||||
.fini = nouveau_devobj_fini,
|
.fini = _nouveau_parent_fini,
|
||||||
.rd08 = nouveau_devobj_rd08,
|
.rd08 = nouveau_devobj_rd08,
|
||||||
.rd16 = nouveau_devobj_rd16,
|
.rd16 = nouveau_devobj_rd16,
|
||||||
.rd32 = nouveau_devobj_rd32,
|
.rd32 = nouveau_devobj_rd32,
|
||||||
|
@ -423,14 +356,64 @@ static int
|
||||||
nouveau_device_fini(struct nouveau_object *object, bool suspend)
|
nouveau_device_fini(struct nouveau_object *object, bool suspend)
|
||||||
{
|
{
|
||||||
struct nouveau_device *device = (void *)object;
|
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
|
static int
|
||||||
nouveau_device_init(struct nouveau_object *object)
|
nouveau_device_init(struct nouveau_object *object)
|
||||||
{
|
{
|
||||||
struct nouveau_device *device = (void *)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
|
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_destroy(struct nouveau_parent *);
|
||||||
|
|
||||||
void _nouveau_parent_dtor(struct nouveau_object *);
|
void _nouveau_parent_dtor(struct nouveau_object *);
|
||||||
#define _nouveau_parent_init _nouveau_object_init
|
#define _nouveau_parent_init nouveau_object_init
|
||||||
#define _nouveau_parent_fini _nouveau_object_fini
|
#define _nouveau_parent_fini nouveau_object_fini
|
||||||
|
|
||||||
int nouveau_parent_sclass(struct nouveau_object *, u16 handle,
|
int nouveau_parent_sclass(struct nouveau_object *, u16 handle,
|
||||||
struct nouveau_object **pengine,
|
struct nouveau_object **pengine,
|
||||||
|
|
Loading…
Add table
Reference in a new issue