Commit 22b76bbe authored by Lyude Paul's avatar Lyude Paul Committed by Ben Skeggs

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: default avatarLyude Paul <lyude@redhat.com>
Cc: stable@vger.kernel.org
Cc: Karol Herbst <karolherbst@gmail.com>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 7f073d01
...@@ -267,6 +267,7 @@ nouveau_backlight_init(struct drm_device *dev) ...@@ -267,6 +267,7 @@ nouveau_backlight_init(struct drm_device *dev)
struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_drm *drm = nouveau_drm(dev);
struct nvif_device *device = &drm->client.device; struct nvif_device *device = &drm->client.device;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
INIT_LIST_HEAD(&drm->bl_connectors); INIT_LIST_HEAD(&drm->bl_connectors);
...@@ -275,7 +276,8 @@ nouveau_backlight_init(struct drm_device *dev) ...@@ -275,7 +276,8 @@ nouveau_backlight_init(struct drm_device *dev)
return 0; return 0;
} }
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS &&
connector->connector_type != DRM_MODE_CONNECTOR_eDP) connector->connector_type != DRM_MODE_CONNECTOR_eDP)
continue; continue;
...@@ -292,7 +294,7 @@ nouveau_backlight_init(struct drm_device *dev) ...@@ -292,7 +294,7 @@ nouveau_backlight_init(struct drm_device *dev)
break; break;
} }
} }
drm_connector_list_iter_end(&conn_iter);
return 0; return 0;
} }
......
...@@ -1208,14 +1208,19 @@ nouveau_connector_create(struct drm_device *dev, int index) ...@@ -1208,14 +1208,19 @@ nouveau_connector_create(struct drm_device *dev, int index)
struct nouveau_display *disp = nouveau_display(dev); struct nouveau_display *disp = nouveau_display(dev);
struct nouveau_connector *nv_connector = NULL; struct nouveau_connector *nv_connector = NULL;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
int type, ret = 0; int type, ret = 0;
bool dummy; bool dummy;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
nv_connector = nouveau_connector(connector); nv_connector = nouveau_connector(connector);
if (nv_connector->index == index) if (nv_connector->index == index) {
drm_connector_list_iter_end(&conn_iter);
return connector; return connector;
}
} }
drm_connector_list_iter_end(&conn_iter);
nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL); nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);
if (!nv_connector) if (!nv_connector)
......
...@@ -65,14 +65,20 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc) ...@@ -65,14 +65,20 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc)
{ {
struct drm_device *dev = nv_crtc->base.dev; struct drm_device *dev = nv_crtc->base.dev;
struct drm_connector *connector; struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
struct nouveau_connector *nv_connector = NULL;
struct drm_crtc *crtc = to_drm_crtc(nv_crtc); struct drm_crtc *crtc = to_drm_crtc(nv_crtc);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_connector_list_iter_begin(dev, &conn_iter);
if (connector->encoder && connector->encoder->crtc == crtc) drm_for_each_connector_iter(connector, &conn_iter) {
return nouveau_connector(connector); if (connector->encoder && connector->encoder->crtc == crtc) {
nv_connector = nouveau_connector(connector);
break;
}
} }
drm_connector_list_iter_end(&conn_iter);
return NULL; return nv_connector;
} }
struct drm_connector * struct drm_connector *
......
...@@ -404,6 +404,7 @@ nouveau_display_init(struct drm_device *dev) ...@@ -404,6 +404,7 @@ nouveau_display_init(struct drm_device *dev)
struct nouveau_display *disp = nouveau_display(dev); struct nouveau_display *disp = nouveau_display(dev);
struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_drm *drm = nouveau_drm(dev);
struct drm_connector *connector; struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
int ret; int ret;
ret = disp->init(dev); ret = disp->init(dev);
...@@ -411,10 +412,12 @@ nouveau_display_init(struct drm_device *dev) ...@@ -411,10 +412,12 @@ nouveau_display_init(struct drm_device *dev)
return ret; return ret;
/* enable hotplug interrupts */ /* enable hotplug interrupts */
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
struct nouveau_connector *conn = nouveau_connector(connector); struct nouveau_connector *conn = nouveau_connector(connector);
nvif_notify_get(&conn->hpd); nvif_notify_get(&conn->hpd);
} }
drm_connector_list_iter_end(&conn_iter);
/* enable flip completion events */ /* enable flip completion events */
nvif_notify_get(&drm->flip); nvif_notify_get(&drm->flip);
...@@ -427,6 +430,7 @@ nouveau_display_fini(struct drm_device *dev, bool suspend) ...@@ -427,6 +430,7 @@ nouveau_display_fini(struct drm_device *dev, bool suspend)
struct nouveau_display *disp = nouveau_display(dev); struct nouveau_display *disp = nouveau_display(dev);
struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_drm *drm = nouveau_drm(dev);
struct drm_connector *connector; struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
if (!suspend) { if (!suspend) {
if (drm_drv_uses_atomic_modeset(dev)) if (drm_drv_uses_atomic_modeset(dev))
...@@ -439,10 +443,12 @@ nouveau_display_fini(struct drm_device *dev, bool suspend) ...@@ -439,10 +443,12 @@ nouveau_display_fini(struct drm_device *dev, bool suspend)
nvif_notify_put(&drm->flip); nvif_notify_put(&drm->flip);
/* disable hotplug interrupts */ /* disable hotplug interrupts */
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
struct nouveau_connector *conn = nouveau_connector(connector); struct nouveau_connector *conn = nouveau_connector(connector);
nvif_notify_put(&conn->hpd); nvif_notify_put(&conn->hpd);
} }
drm_connector_list_iter_end(&conn_iter);
drm_kms_helper_poll_disable(dev); drm_kms_helper_poll_disable(dev);
disp->fini(dev); disp->fini(dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment