diff options
| author | Ben Skeggs <bskeggs@redhat.com> | 2012-10-01 20:30:34 -0400 |
|---|---|---|
| committer | Ben Skeggs <bskeggs@redhat.com> | 2012-10-02 23:13:17 -0400 |
| commit | 7234d0230e5a371a0cd1969c46eec802c1d6c4ed (patch) | |
| tree | d03c5498449000f1e809025828c28603914bc253 | |
| parent | 002d0c735c1bd8bffd3786ad5aadb205a76878fa (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>
| -rw-r--r-- | drivers/gpu/drm/nouveau/core/include/core/device.h | 16 | ||||
| -rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/device/base.c | 38 |
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 57899fc3b877..e58b6f0984c1 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 @@ | |||
| 8 | enum nv_subdev_type { | 8 | enum 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 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, | |||
| 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; |
