--- a/sys/dev/drm/drm_crtc_helper.c +++ b/sys/dev/drm/drm_crtc_helper.c @@ -522,6 +522,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set, struct drm_connector *connector; struct drm_connector_list_iter conn_iter; int count = 0, ro, fail = 0; + int n_connectors; const struct drm_crtc_helper_funcs *crtc_funcs; struct drm_mode_set save_set; int ret; @@ -562,10 +563,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set, /* * Allocate space for the backup of all (non-pointer) encoder and * connector data. + * DF-4469: the connector list can grow concurrently (DP MST hotplug + * registers connectors under connector_list_lock only), so every walk + * below must be bounded by the snapshot taken here. */ + n_connectors = dev->mode_config.num_connector; save_encoder_crtcs = kcalloc(dev->mode_config.num_encoder, sizeof(struct drm_crtc *), GFP_KERNEL); @@ -587,7 +590,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set, count = 0; drm_connector_list_iter_begin(dev, &conn_iter); drm_for_each_connector_iter(connector, &conn_iter) - save_connector_encoders[count++] = connector->encoder; + if (count < n_connectors) + save_connector_encoders[count++] = connector->encoder; drm_connector_list_iter_end(&conn_iter); @@ -765,7 +769,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set, count = 0; drm_connector_list_iter_begin(dev, &conn_iter); drm_for_each_connector_iter(connector, &conn_iter) - connector->encoder = save_connector_encoders[count++]; + if (count < n_connectors) + connector->encoder = save_connector_encoders[count++]; drm_connector_list_iter_end(&conn_iter); /* after fail drop reference on all unbound connectors in set, let