From 490d595f321d16f34040836c494d7875eb8f66a4 Mon Sep 17 00:00:00 2001
From: Ben Skeggs <bskeggs@redhat.com>
Date: Fri, 5 Dec 2014 11:26:23 +1000
Subject: [PATCH] drm/nouveau/core: fix subdev/engine/device lookup to not
 require engine pointer

It's about to not be valid for objects that aren't in the client
object tree.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
---
 drivers/gpu/drm/nouveau/core/core/engine.c    |  8 +++----
 drivers/gpu/drm/nouveau/core/core/subdev.c    | 11 ++++++----
 .../gpu/drm/nouveau/core/engine/device/base.c | 22 ++++++++-----------
 3 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/core/core/engine.c b/drivers/gpu/drm/nouveau/core/core/engine.c
index 4835056b06896..85bf4b3d1fe4e 100644
--- a/drivers/gpu/drm/nouveau/core/core/engine.c
+++ b/drivers/gpu/drm/nouveau/core/core/engine.c
@@ -27,11 +27,11 @@
 #include <core/option.h>
 
 struct nouveau_engine *
-nouveau_engine(void *obj, int sub)
+nouveau_engine(void *obj, int idx)
 {
-	struct nouveau_subdev *subdev = nouveau_subdev(obj, sub);
-	if (subdev && nv_iclass(subdev, NV_ENGINE_CLASS))
-		return nv_engine(subdev);
+	obj = nouveau_subdev(obj, idx);
+	if (obj && nv_iclass(obj, NV_ENGINE_CLASS))
+		return nv_engine(obj);
 	return NULL;
 }
 
diff --git a/drivers/gpu/drm/nouveau/core/core/subdev.c b/drivers/gpu/drm/nouveau/core/core/subdev.c
index edae535406e57..69ba1482c3f50 100644
--- a/drivers/gpu/drm/nouveau/core/core/subdev.c
+++ b/drivers/gpu/drm/nouveau/core/core/subdev.c
@@ -28,11 +28,14 @@
 #include <core/option.h>
 
 struct nouveau_subdev *
-nouveau_subdev(void *obj, int sub)
+nouveau_subdev(void *obj, int idx)
 {
-	if (nv_device(obj)->subdev[sub])
-		return nv_subdev(nv_device(obj)->subdev[sub]);
-	return NULL;
+	struct nouveau_object *object = nv_object(obj);
+	while (object && !nv_iclass(object, NV_SUBDEV_CLASS))
+		object = object->parent;
+	if (object == NULL || nv_subidx(object) != idx)
+		object = nv_device(obj)->subdev[idx];
+	return object ? nv_subdev(object) : NULL;
 }
 
 void
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/base.c b/drivers/gpu/drm/nouveau/core/engine/device/base.c
index e2da1d4029cd6..7c0cbcde7b2f3 100644
--- a/drivers/gpu/drm/nouveau/core/engine/device/base.c
+++ b/drivers/gpu/drm/nouveau/core/engine/device/base.c
@@ -511,22 +511,18 @@ nouveau_devobj_ofuncs = {
 struct nouveau_device *
 nv_device(void *obj)
 {
-	struct nouveau_object *object = nv_object(obj);
-	struct nouveau_object *device = object;
-
-	if (device->engine)
-		device = device->engine;
-	if (device->parent)
+	struct nouveau_object *device = nv_object(obj);
+	while (device && device->parent)
 		device = device->parent;
-
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
-	if (unlikely(!nv_iclass(device, NV_SUBDEV_CLASS) ||
-		     (nv_hclass(device) & 0xff) != NVDEV_ENGINE_DEVICE)) {
-		nv_assert("BAD CAST -> NvDevice, 0x%08x 0x%08x",
-			  nv_hclass(object), nv_hclass(device));
+	if (!nv_iclass(device, NV_ENGINE_CLASS)) {
+		device = nv_object(obj)->engine;
+		if (device && device->parent)
+			device = device->parent;
 	}
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+	if (unlikely(!device))
+		nv_assert("BAD CAST -> NvDevice, 0x%08x\n", nv_hclass(obj));
 #endif
-
 	return (void *)device;
 }
 
-- 
GitLab