aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorBen Skeggs <bskeggs@redhat.com>2012-10-01 20:30:34 -0400
committerBen Skeggs <bskeggs@redhat.com>2012-10-02 23:13:17 -0400
commit7234d0230e5a371a0cd1969c46eec802c1d6c4ed (patch)
treed03c5498449000f1e809025828c28603914bc253 /drivers/gpu
parent002d0c735c1bd8bffd3786ad5aadb205a76878fa (diff)
drm/nouveau/devinit: fixup various issues with subdev ctor/init ordering
Details of the problem, and solution, are in comments in the commit proper. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/device.h16
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/device/base.c38
2 files changed, 38 insertions, 16 deletions
diff --git a/drivers/gpu/drm/nouveau/core/include/core/device.h b/drivers/gpu/drm/nouveau/core/include/core/device.h
index 57899fc3b87..e58b6f0984c 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/device.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/device.h
@@ -8,11 +8,23 @@
8enum nv_subdev_type { 8enum nv_subdev_type {
9 NVDEV_SUBDEV_DEVICE, 9 NVDEV_SUBDEV_DEVICE,
10 NVDEV_SUBDEV_VBIOS, 10 NVDEV_SUBDEV_VBIOS,
11
12 /* All subdevs from DEVINIT to DEVINIT_LAST will be created before
13 * *any* of them are initialised. This subdev category is used
14 * for any subdevs that the VBIOS init table parsing may call out
15 * to during POST.
16 */
17 NVDEV_SUBDEV_DEVINIT,
11 NVDEV_SUBDEV_GPIO, 18 NVDEV_SUBDEV_GPIO,
12 NVDEV_SUBDEV_I2C, 19 NVDEV_SUBDEV_I2C,
13 NVDEV_SUBDEV_CLOCK, 20 NVDEV_SUBDEV_CLOCK,
21 NVDEV_SUBDEV_DEVINIT_LAST = NVDEV_SUBDEV_CLOCK,
22
23 /* This grouping of subdevs are initialised right after they've
24 * been created, and are allowed to assume any subdevs in the
25 * list above them exist and have been initialised.
26 */
14 NVDEV_SUBDEV_MXM, 27 NVDEV_SUBDEV_MXM,
15 NVDEV_SUBDEV_DEVINIT,
16 NVDEV_SUBDEV_MC, 28 NVDEV_SUBDEV_MC,
17 NVDEV_SUBDEV_TIMER, 29 NVDEV_SUBDEV_TIMER,
18 NVDEV_SUBDEV_FB, 30 NVDEV_SUBDEV_FB,
@@ -23,6 +35,7 @@ enum nv_subdev_type {
23 NVDEV_SUBDEV_BAR, 35 NVDEV_SUBDEV_BAR,
24 NVDEV_SUBDEV_VOLT, 36 NVDEV_SUBDEV_VOLT,
25 NVDEV_SUBDEV_THERM, 37 NVDEV_SUBDEV_THERM,
38
26 NVDEV_ENGINE_DMAOBJ, 39 NVDEV_ENGINE_DMAOBJ,
27 NVDEV_ENGINE_FIFO, 40 NVDEV_ENGINE_FIFO,
28 NVDEV_ENGINE_SW, 41 NVDEV_ENGINE_SW,
@@ -38,6 +51,7 @@ enum nv_subdev_type {
38 NVDEV_ENGINE_UNK1C1, 51 NVDEV_ENGINE_UNK1C1,
39 NVDEV_ENGINE_VENC, 52 NVDEV_ENGINE_VENC,
40 NVDEV_ENGINE_DISP, 53 NVDEV_ENGINE_DISP,
54
41 NVDEV_SUBDEV_NR, 55 NVDEV_SUBDEV_NR,
42}; 56};
43 57
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/base.c b/drivers/gpu/drm/nouveau/core/subdev/device/base.c
index 7bf6f3760b9..ca9a4648bd8 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,
96 struct nouveau_object **pobject) 96 struct nouveau_object **pobject)
97{ 97{
98 struct nouveau_client *client = nv_client(parent); 98 struct nouveau_client *client = nv_client(parent);
99 struct nouveau_object *subdev = NULL;
100 struct nouveau_device *device; 99 struct nouveau_device *device;
101 struct nouveau_devobj *devobj; 100 struct nouveau_devobj *devobj;
102 struct nv_device_class *args = data; 101 struct nv_device_class *args = data;
103 u64 disable, boot0, strap; 102 u64 disable, boot0, strap;
104 u64 mmio_base, mmio_size; 103 u64 mmio_base, mmio_size;
105 void __iomem *map; 104 void __iomem *map;
106 int ret, i; 105 int ret, i, c;
107 106
108 if (size < sizeof(struct nv_device_class)) 107 if (size < sizeof(struct nv_device_class))
109 return -EINVAL; 108 return -EINVAL;
@@ -234,34 +233,43 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
234 } 233 }
235 234
236 /* ensure requested subsystems are available for use */ 235 /* ensure requested subsystems are available for use */
237 for (i = 0; i < NVDEV_SUBDEV_NR; i++) { 236 for (i = 0, c = 0; i < NVDEV_SUBDEV_NR; i++) {
238 if (!(oclass = device->oclass[i]) || (disable & (1ULL << i))) 237 if (!(oclass = device->oclass[i]) || (disable & (1ULL << i)))
239 continue; 238 continue;
240 239
241 if (!device->subdev[i]) { 240 if (!device->subdev[i]) {
242 ret = nouveau_object_ctor(nv_object(device), NULL, 241 ret = nouveau_object_ctor(nv_object(device), NULL,
243 oclass, NULL, i, &subdev); 242 oclass, NULL, i,
243 &devobj->subdev[i]);
244 if (ret == -ENODEV) 244 if (ret == -ENODEV)
245 continue; 245 continue;
246 if (ret) 246 if (ret)
247 return ret; 247 return ret;
248 248
249 if (nv_iclass(subdev, NV_ENGINE_CLASS)) 249 if (nv_iclass(devobj->subdev[i], NV_ENGINE_CLASS))
250 nouveau_subdev_reset(subdev); 250 nouveau_subdev_reset(devobj->subdev[i]);
251 } else { 251 } else {
252 nouveau_object_ref(device->subdev[i], &subdev); 252 nouveau_object_ref(device->subdev[i],
253 &devobj->subdev[i]);
253 } 254 }
254 255
255 if (!nv_iclass(subdev, NV_ENGINE_CLASS)) { 256 /* note: can't init *any* subdevs until devinit has been run
256 ret = nouveau_object_inc(subdev); 257 * due to not knowing exactly what the vbios init tables will
257 if (ret) { 258 * mess with. devinit also can't be run until all of its
258 nouveau_object_ref(NULL, &subdev); 259 * dependencies have been created.
259 return ret; 260 *
261 * this code delays init of any subdev until all of devinit's
262 * dependencies have been created, and then initialises each
263 * subdev in turn as they're created.
264 */
265 while (i >= NVDEV_SUBDEV_DEVINIT_LAST && c <= i) {
266 struct nouveau_object *subdev = devobj->subdev[c++];
267 if (subdev && !nv_iclass(subdev, NV_ENGINE_CLASS)) {
268 ret = nouveau_object_inc(subdev);
269 if (ret)
270 return ret;
260 } 271 }
261 } 272 }
262
263 nouveau_object_ref(subdev, &devobj->subdev[i]);
264 nouveau_object_ref(NULL, &subdev);
265 } 273 }
266 274
267 return 0; 275 return 0;