aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorLyude Paul <lyude@redhat.com>2018-07-13 13:06:32 -0400
committerBen Skeggs <bskeggs@redhat.com>2018-07-16 03:59:59 -0400
commit22b76bbe089cd901f5260ecb9a3dc41f9edb97a0 (patch)
tree46cc6c81edf814a1cff1f5c06a328e9db822d4b3 /drivers/gpu
parent7f073d011f93e92d4d225526b9ab6b8b0bbd6613 (diff)
drm/nouveau: Use drm_connector_list_iter_* for iterating connectors
Every codepath in nouveau that loops through the connector list currently does so using the old method, which is prone to race conditions from MST connectors being created and destroyed. This has been causing a multitude of problems, including memory corruption from trying to access connectors that have already been freed! Signed-off-by: Lyude Paul <lyude@redhat.com> Cc: stable@vger.kernel.org Cc: Karol Herbst <karolherbst@gmail.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_backlight.c6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c9
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.h14
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c10
4 files changed, 29 insertions, 10 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c
index debbbf0fd4bd..408b955e5c39 100644
--- a/drivers/gpu/drm/nouveau/nouveau_backlight.c
+++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c
@@ -267,6 +267,7 @@ nouveau_backlight_init(struct drm_device *dev)
267 struct nouveau_drm *drm = nouveau_drm(dev); 267 struct nouveau_drm *drm = nouveau_drm(dev);
268 struct nvif_device *device = &drm->client.device; 268 struct nvif_device *device = &drm->client.device;
269 struct drm_connector *connector; 269 struct drm_connector *connector;
270 struct drm_connector_list_iter conn_iter;
270 271
271 INIT_LIST_HEAD(&drm->bl_connectors); 272 INIT_LIST_HEAD(&drm->bl_connectors);
272 273
@@ -275,7 +276,8 @@ nouveau_backlight_init(struct drm_device *dev)
275 return 0; 276 return 0;
276 } 277 }
277 278
278 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 279 drm_connector_list_iter_begin(dev, &conn_iter);
280 drm_for_each_connector_iter(connector, &conn_iter) {
279 if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && 281 if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS &&
280 connector->connector_type != DRM_MODE_CONNECTOR_eDP) 282 connector->connector_type != DRM_MODE_CONNECTOR_eDP)
281 continue; 283 continue;
@@ -292,7 +294,7 @@ nouveau_backlight_init(struct drm_device *dev)
292 break; 294 break;
293 } 295 }
294 } 296 }
295 297 drm_connector_list_iter_end(&conn_iter);
296 298
297 return 0; 299 return 0;
298} 300}
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 7b557c354307..7dc380449232 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -1208,14 +1208,19 @@ nouveau_connector_create(struct drm_device *dev, int index)
1208 struct nouveau_display *disp = nouveau_display(dev); 1208 struct nouveau_display *disp = nouveau_display(dev);
1209 struct nouveau_connector *nv_connector = NULL; 1209 struct nouveau_connector *nv_connector = NULL;
1210 struct drm_connector *connector; 1210 struct drm_connector *connector;
1211 struct drm_connector_list_iter conn_iter;
1211 int type, ret = 0; 1212 int type, ret = 0;
1212 bool dummy; 1213 bool dummy;
1213 1214
1214 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 1215 drm_connector_list_iter_begin(dev, &conn_iter);
1216 drm_for_each_connector_iter(connector, &conn_iter) {
1215 nv_connector = nouveau_connector(connector); 1217 nv_connector = nouveau_connector(connector);
1216 if (nv_connector->index == index) 1218 if (nv_connector->index == index) {
1219 drm_connector_list_iter_end(&conn_iter);
1217 return connector; 1220 return connector;
1221 }
1218 } 1222 }
1223 drm_connector_list_iter_end(&conn_iter);
1219 1224
1220 nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL); 1225 nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
1221 if (!nv_connector) 1226 if (!nv_connector)
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
index a4d1a059bd3d..a8cbb4b56fc7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -65,14 +65,20 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc)
65{ 65{
66 struct drm_device *dev = nv_crtc->base.dev; 66 struct drm_device *dev = nv_crtc->base.dev;
67 struct drm_connector *connector; 67 struct drm_connector *connector;
68 struct drm_connector_list_iter conn_iter;
69 struct nouveau_connector *nv_connector = NULL;
68 struct drm_crtc *crtc = to_drm_crtc(nv_crtc); 70 struct drm_crtc *crtc = to_drm_crtc(nv_crtc);
69 71
70 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 72 drm_connector_list_iter_begin(dev, &conn_iter);
71 if (connector->encoder && connector->encoder->crtc == crtc) 73 drm_for_each_connector_iter(connector, &conn_iter) {
72 return nouveau_connector(connector); 74 if (connector->encoder && connector->encoder->crtc == crtc) {
75 nv_connector = nouveau_connector(connector);
76 break;
77 }
73 } 78 }
79 drm_connector_list_iter_end(&conn_iter);
74 80
75 return NULL; 81 return nv_connector;
76} 82}
77 83
78struct drm_connector * 84struct drm_connector *
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index 774b429142bc..46b8430ef4aa 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -404,6 +404,7 @@ nouveau_display_init(struct drm_device *dev)
404 struct nouveau_display *disp = nouveau_display(dev); 404 struct nouveau_display *disp = nouveau_display(dev);
405 struct nouveau_drm *drm = nouveau_drm(dev); 405 struct nouveau_drm *drm = nouveau_drm(dev);
406 struct drm_connector *connector; 406 struct drm_connector *connector;
407 struct drm_connector_list_iter conn_iter;
407 int ret; 408 int ret;
408 409
409 ret = disp->init(dev); 410 ret = disp->init(dev);
@@ -411,10 +412,12 @@ nouveau_display_init(struct drm_device *dev)
411 return ret; 412 return ret;
412 413
413 /* enable hotplug interrupts */ 414 /* enable hotplug interrupts */
414 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 415 drm_connector_list_iter_begin(dev, &conn_iter);
416 drm_for_each_connector_iter(connector, &conn_iter) {
415 struct nouveau_connector *conn = nouveau_connector(connector); 417 struct nouveau_connector *conn = nouveau_connector(connector);
416 nvif_notify_get(&conn->hpd); 418 nvif_notify_get(&conn->hpd);
417 } 419 }
420 drm_connector_list_iter_end(&conn_iter);
418 421
419 /* enable flip completion events */ 422 /* enable flip completion events */
420 nvif_notify_get(&drm->flip); 423 nvif_notify_get(&drm->flip);
@@ -427,6 +430,7 @@ nouveau_display_fini(struct drm_device *dev, bool suspend)
427 struct nouveau_display *disp = nouveau_display(dev); 430 struct nouveau_display *disp = nouveau_display(dev);
428 struct nouveau_drm *drm = nouveau_drm(dev); 431 struct nouveau_drm *drm = nouveau_drm(dev);
429 struct drm_connector *connector; 432 struct drm_connector *connector;
433 struct drm_connector_list_iter conn_iter;
430 434
431 if (!suspend) { 435 if (!suspend) {
432 if (drm_drv_uses_atomic_modeset(dev)) 436 if (drm_drv_uses_atomic_modeset(dev))
@@ -439,10 +443,12 @@ nouveau_display_fini(struct drm_device *dev, bool suspend)
439 nvif_notify_put(&drm->flip); 443 nvif_notify_put(&drm->flip);
440 444
441 /* disable hotplug interrupts */ 445 /* disable hotplug interrupts */
442 list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 446 drm_connector_list_iter_begin(dev, &conn_iter);
447 drm_for_each_connector_iter(connector, &conn_iter) {
443 struct nouveau_connector *conn = nouveau_connector(connector); 448 struct nouveau_connector *conn = nouveau_connector(connector);
444 nvif_notify_put(&conn->hpd); 449 nvif_notify_put(&conn->hpd);
445 } 450 }
451 drm_connector_list_iter_end(&conn_iter);
446 452
447 drm_kms_helper_poll_disable(dev); 453 drm_kms_helper_poll_disable(dev);
448 disp->fini(dev); 454 disp->fini(dev);