diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2013-04-24 21:43:54 -0400 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2013-04-26 01:38:14 -0400 |
commit | 10caad339c458df47e5a9e16e148087fcde98fec (patch) | |
tree | c704ebc81bd3f904eeda8a281d3c0c7efea072be | |
parent | 066a5d0938c64bec665866b145d8538d9f96bcda (diff) |
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>
-rw-r--r-- | drivers/gpu/drm/nouveau/core/engine/device/base.c | 155 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/include/core/parent.h | 4 |
2 files changed, 71 insertions, 88 deletions
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/base.c b/drivers/gpu/drm/nouveau/core/engine/device/base.c index 497d5f60a195..86d24904e9d3 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/base.c | |||
@@ -55,7 +55,6 @@ nouveau_device_find(u64 name) | |||
55 | struct nouveau_devobj { | 55 | struct nouveau_devobj { |
56 | struct nouveau_parent base; | 56 | struct nouveau_parent base; |
57 | struct nouveau_object *subdev[NVDEV_SUBDEV_NR]; | 57 | struct nouveau_object *subdev[NVDEV_SUBDEV_NR]; |
58 | bool created; | ||
59 | }; | 58 | }; |
60 | 59 | ||
61 | static const u64 disable_map[] = { | 60 | static const u64 disable_map[] = { |
@@ -238,26 +237,24 @@ nouveau_devobj_ctor(struct nouveau_object *parent, | |||
238 | } | 237 | } |
239 | 238 | ||
240 | /* ensure requested subsystems are available for use */ | 239 | /* ensure requested subsystems are available for use */ |
241 | for (i = 0, c = 0; i < NVDEV_SUBDEV_NR; i++) { | 240 | for (i = 1, c = 1; i < NVDEV_SUBDEV_NR; i++) { |
242 | if (!(oclass = device->oclass[i]) || (disable & (1ULL << i))) | 241 | if (!(oclass = device->oclass[i]) || (disable & (1ULL << i))) |
243 | continue; | 242 | continue; |
244 | 243 | ||
245 | if (!device->subdev[i]) { | 244 | if (device->subdev[i]) { |
246 | ret = nouveau_object_ctor(nv_object(device), NULL, | ||
247 | oclass, NULL, i, | ||
248 | &devobj->subdev[i]); | ||
249 | if (ret == -ENODEV) | ||
250 | continue; | ||
251 | if (ret) | ||
252 | return ret; | ||
253 | |||
254 | if (nv_iclass(devobj->subdev[i], NV_ENGINE_CLASS)) | ||
255 | nouveau_subdev_reset(devobj->subdev[i]); | ||
256 | } else { | ||
257 | nouveau_object_ref(device->subdev[i], | 245 | nouveau_object_ref(device->subdev[i], |
258 | &devobj->subdev[i]); | 246 | &devobj->subdev[i]); |
247 | continue; | ||
259 | } | 248 | } |
260 | 249 | ||
250 | ret = nouveau_object_ctor(nv_object(device), NULL, | ||
251 | oclass, NULL, i, | ||
252 | &devobj->subdev[i]); | ||
253 | if (ret == -ENODEV) | ||
254 | continue; | ||
255 | if (ret) | ||
256 | return ret; | ||
257 | |||
261 | /* note: can't init *any* subdevs until devinit has been run | 258 | /* note: can't init *any* subdevs until devinit has been run |
262 | * due to not knowing exactly what the vbios init tables will | 259 | * due to not knowing exactly what the vbios init tables will |
263 | * mess with. devinit also can't be run until all of its | 260 | * mess with. devinit also can't be run until all of its |
@@ -273,6 +270,10 @@ nouveau_devobj_ctor(struct nouveau_object *parent, | |||
273 | ret = nouveau_object_inc(subdev); | 270 | ret = nouveau_object_inc(subdev); |
274 | if (ret) | 271 | if (ret) |
275 | return ret; | 272 | return ret; |
273 | atomic_dec(&nv_object(device)->usecount); | ||
274 | } else | ||
275 | if (subdev) { | ||
276 | nouveau_subdev_reset(subdev); | ||
276 | } | 277 | } |
277 | } | 278 | } |
278 | } | 279 | } |
@@ -292,74 +293,6 @@ nouveau_devobj_dtor(struct nouveau_object *object) | |||
292 | nouveau_parent_destroy(&devobj->base); | 293 | nouveau_parent_destroy(&devobj->base); |
293 | } | 294 | } |
294 | 295 | ||
295 | static int | ||
296 | nouveau_devobj_init(struct nouveau_object *object) | ||
297 | { | ||
298 | struct nouveau_devobj *devobj = (void *)object; | ||
299 | struct nouveau_object *subdev; | ||
300 | int ret, i; | ||
301 | |||
302 | ret = nouveau_parent_init(&devobj->base); | ||
303 | if (ret) | ||
304 | return ret; | ||
305 | |||
306 | for (i = 0; devobj->created && i < NVDEV_SUBDEV_NR; i++) { | ||
307 | if ((subdev = devobj->subdev[i])) { | ||
308 | if (!nv_iclass(subdev, NV_ENGINE_CLASS)) { | ||
309 | ret = nouveau_object_inc(subdev); | ||
310 | if (ret) | ||
311 | goto fail; | ||
312 | } | ||
313 | } | ||
314 | } | ||
315 | |||
316 | devobj->created = true; | ||
317 | return 0; | ||
318 | |||
319 | fail: | ||
320 | for (--i; i >= 0; i--) { | ||
321 | if ((subdev = devobj->subdev[i])) { | ||
322 | if (!nv_iclass(subdev, NV_ENGINE_CLASS)) | ||
323 | nouveau_object_dec(subdev, false); | ||
324 | } | ||
325 | } | ||
326 | |||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | static int | ||
331 | nouveau_devobj_fini(struct nouveau_object *object, bool suspend) | ||
332 | { | ||
333 | struct nouveau_devobj *devobj = (void *)object; | ||
334 | struct nouveau_object *subdev; | ||
335 | int ret, i; | ||
336 | |||
337 | for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) { | ||
338 | if ((subdev = devobj->subdev[i])) { | ||
339 | if (!nv_iclass(subdev, NV_ENGINE_CLASS)) { | ||
340 | ret = nouveau_object_dec(subdev, suspend); | ||
341 | if (ret && suspend) | ||
342 | goto fail; | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | |||
347 | ret = nouveau_parent_fini(&devobj->base, suspend); | ||
348 | fail: | ||
349 | for (; ret && suspend && i < NVDEV_SUBDEV_NR; i++) { | ||
350 | if ((subdev = devobj->subdev[i])) { | ||
351 | if (!nv_iclass(subdev, NV_ENGINE_CLASS)) { | ||
352 | ret = nouveau_object_inc(subdev); | ||
353 | if (ret) { | ||
354 | /* XXX */ | ||
355 | } | ||
356 | } | ||
357 | } | ||
358 | } | ||
359 | |||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | static u8 | 296 | static u8 |
364 | nouveau_devobj_rd08(struct nouveau_object *object, u64 addr) | 297 | nouveau_devobj_rd08(struct nouveau_object *object, u64 addr) |
365 | { | 298 | { |
@@ -400,8 +333,8 @@ static struct nouveau_ofuncs | |||
400 | nouveau_devobj_ofuncs = { | 333 | nouveau_devobj_ofuncs = { |
401 | .ctor = nouveau_devobj_ctor, | 334 | .ctor = nouveau_devobj_ctor, |
402 | .dtor = nouveau_devobj_dtor, | 335 | .dtor = nouveau_devobj_dtor, |
403 | .init = nouveau_devobj_init, | 336 | .init = _nouveau_parent_init, |
404 | .fini = nouveau_devobj_fini, | 337 | .fini = _nouveau_parent_fini, |
405 | .rd08 = nouveau_devobj_rd08, | 338 | .rd08 = nouveau_devobj_rd08, |
406 | .rd16 = nouveau_devobj_rd16, | 339 | .rd16 = nouveau_devobj_rd16, |
407 | .rd32 = nouveau_devobj_rd32, | 340 | .rd32 = nouveau_devobj_rd32, |
@@ -423,14 +356,64 @@ static int | |||
423 | nouveau_device_fini(struct nouveau_object *object, bool suspend) | 356 | nouveau_device_fini(struct nouveau_object *object, bool suspend) |
424 | { | 357 | { |
425 | struct nouveau_device *device = (void *)object; | 358 | struct nouveau_device *device = (void *)object; |
426 | return nouveau_subdev_fini(&device->base, suspend); | 359 | struct nouveau_object *subdev; |
360 | int ret, i; | ||
361 | |||
362 | for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) { | ||
363 | if ((subdev = device->subdev[i])) { | ||
364 | if (!nv_iclass(subdev, NV_ENGINE_CLASS)) { | ||
365 | ret = nouveau_object_dec(subdev, suspend); | ||
366 | if (ret && suspend) | ||
367 | goto fail; | ||
368 | } | ||
369 | } | ||
370 | } | ||
371 | |||
372 | ret = 0; | ||
373 | fail: | ||
374 | for (; ret && i < NVDEV_SUBDEV_NR; i++) { | ||
375 | if ((subdev = device->subdev[i])) { | ||
376 | if (!nv_iclass(subdev, NV_ENGINE_CLASS)) { | ||
377 | ret = nouveau_object_inc(subdev); | ||
378 | if (ret) { | ||
379 | /* XXX */ | ||
380 | } | ||
381 | } | ||
382 | } | ||
383 | } | ||
384 | |||
385 | return ret; | ||
427 | } | 386 | } |
428 | 387 | ||
429 | static int | 388 | static int |
430 | nouveau_device_init(struct nouveau_object *object) | 389 | nouveau_device_init(struct nouveau_object *object) |
431 | { | 390 | { |
432 | struct nouveau_device *device = (void *)object; | 391 | struct nouveau_device *device = (void *)object; |
433 | return nouveau_subdev_init(&device->base); | 392 | struct nouveau_object *subdev; |
393 | int ret, i; | ||
394 | |||
395 | for (i = 0; i < NVDEV_SUBDEV_NR; i++) { | ||
396 | if ((subdev = device->subdev[i])) { | ||
397 | if (!nv_iclass(subdev, NV_ENGINE_CLASS)) { | ||
398 | ret = nouveau_object_inc(subdev); | ||
399 | if (ret) | ||
400 | goto fail; | ||
401 | } else { | ||
402 | nouveau_subdev_reset(subdev); | ||
403 | } | ||
404 | } | ||
405 | } | ||
406 | |||
407 | ret = 0; | ||
408 | fail: | ||
409 | for (--i; ret && i >= 0; i--) { | ||
410 | if ((subdev = device->subdev[i])) { | ||
411 | if (!nv_iclass(subdev, NV_ENGINE_CLASS)) | ||
412 | nouveau_object_dec(subdev, false); | ||
413 | } | ||
414 | } | ||
415 | |||
416 | return ret; | ||
434 | } | 417 | } |
435 | 418 | ||
436 | static void | 419 | static void |
diff --git a/drivers/gpu/drm/nouveau/core/include/core/parent.h b/drivers/gpu/drm/nouveau/core/include/core/parent.h index 31cd852c96df..9f5ea900ff00 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/parent.h +++ b/drivers/gpu/drm/nouveau/core/include/core/parent.h | |||
@@ -51,8 +51,8 @@ int nouveau_parent_create_(struct nouveau_object *, struct nouveau_object *, | |||
51 | void nouveau_parent_destroy(struct nouveau_parent *); | 51 | void nouveau_parent_destroy(struct nouveau_parent *); |
52 | 52 | ||
53 | void _nouveau_parent_dtor(struct nouveau_object *); | 53 | void _nouveau_parent_dtor(struct nouveau_object *); |
54 | #define _nouveau_parent_init _nouveau_object_init | 54 | #define _nouveau_parent_init nouveau_object_init |
55 | #define _nouveau_parent_fini _nouveau_object_fini | 55 | #define _nouveau_parent_fini nouveau_object_fini |
56 | 56 | ||
57 | int nouveau_parent_sclass(struct nouveau_object *, u16 handle, | 57 | int nouveau_parent_sclass(struct nouveau_object *, u16 handle, |
58 | struct nouveau_object **pengine, | 58 | struct nouveau_object **pengine, |