summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/core/subdev/device/base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/core/subdev/device/base.c')
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/base.c38
1 files changed, 23 insertions, 15 deletions
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/base.c b/drivers/gpu/drm/nouveau/core/subdev/device/base.c
index 7bf6f3760b99..ca9a4648bd8a 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/device/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/device/base.c
@@ -96,14 +96,13 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
struct nouveau_object **pobject)
{
struct nouveau_client *client = nv_client(parent);
- struct nouveau_object *subdev = NULL;
struct nouveau_device *device;
struct nouveau_devobj *devobj;
struct nv_device_class *args = data;
u64 disable, boot0, strap;
u64 mmio_base, mmio_size;
void __iomem *map;
- int ret, i;
+ int ret, i, c;
if (size < sizeof(struct nv_device_class))
return -EINVAL;
@@ -234,34 +233,43 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
}
/* ensure requested subsystems are available for use */
- for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
+ for (i = 0, c = 0; 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, &subdev);
+ oclass, NULL, i,
+ &devobj->subdev[i]);
if (ret == -ENODEV)
continue;
if (ret)
return ret;
- if (nv_iclass(subdev, NV_ENGINE_CLASS))
- nouveau_subdev_reset(subdev);
+ if (nv_iclass(devobj->subdev[i], NV_ENGINE_CLASS))
+ nouveau_subdev_reset(devobj->subdev[i]);
} else {
- nouveau_object_ref(device->subdev[i], &subdev);
+ nouveau_object_ref(device->subdev[i],
+ &devobj->subdev[i]);
}
- if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
- ret = nouveau_object_inc(subdev);
- if (ret) {
- nouveau_object_ref(NULL, &subdev);
- 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
+ * dependencies have been created.
+ *
+ * this code delays init of any subdev until all of devinit's
+ * dependencies have been created, and then initialises each
+ * subdev in turn as they're created.
+ */
+ while (i >= NVDEV_SUBDEV_DEVINIT_LAST && c <= i) {
+ struct nouveau_object *subdev = devobj->subdev[c++];
+ if (subdev && !nv_iclass(subdev, NV_ENGINE_CLASS)) {
+ ret = nouveau_object_inc(subdev);
+ if (ret)
+ return ret;
}
}
-
- nouveau_object_ref(subdev, &devobj->subdev[i]);
- nouveau_object_ref(NULL, &subdev);
}
return 0;