Since drm_helper_probe_single_connector_modes_merge_bits() and other places also update connector->status, the output_poll_execute() and/or drm_helper_hpd_irq_event() logic can get confused and forget to send a HPD event. There are two possible solutions: (1) keep track of state at last HPD check separately, or (2) send events in more places. The latter approach isn't so convenient to avoid per-connector HPD events (in case multiple connectors change connection state at the same time) so I went for the first option. Signed-off-by: Rob Clark <robdclark@xxxxxxxxx> --- drivers/gpu/drm/drm_crtc.c | 1 + drivers/gpu/drm/drm_probe_helper.c | 9 ++++++--- include/drm/drm_crtc.h | 9 +++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 7c1786d..615edee 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -865,6 +865,7 @@ int drm_connector_init(struct drm_device *dev, INIT_LIST_HEAD(&connector->modes); connector->edid_blob_ptr = NULL; connector->status = connector_status_unknown; + connector->hpd_status = connector_status_unknown; drm_connector_get_cmdline_mode(connector); diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 2fbdcca..c227285 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -293,14 +293,16 @@ static void output_poll_execute(struct work_struct *work) repoll = true; - old_status = connector->status; /* if we are connected and don't want to poll for disconnect skip it */ - if (old_status == connector_status_connected && + if (connector->status == connector_status_connected && !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT)) continue; + old_status = connector->hpd_status; + connector->status = connector->funcs->detect(connector, false); + connector->hpd_status = connector->status; if (old_status != connector->status) { const char *old, *new; @@ -450,9 +452,10 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) if (!(connector->polled & DRM_CONNECTOR_POLL_HPD)) continue; - old_status = connector->status; + old_status = connector->hpd_status; connector->status = connector->funcs->detect(connector, false); + connector->hpd_status = connector->status; DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", connector->base.id, connector->name, diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index f444263..cb1899b 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -619,6 +619,7 @@ struct drm_encoder { * @stereo_allowed: can this connector handle stereo modes? * @modes: modes available on this connector (from fill_modes() + user) * @status: one of the drm_connector_status enums (connected, not, or unknown) + * @hpd_status: status as of last hpd/poll * @probed_modes: list of modes derived directly from the display * @display_info: information about attached display (e.g. from EDID) * @funcs: connector control functions @@ -676,6 +677,14 @@ struct drm_connector { enum drm_connector_status status; + /* since connector->status can change in various other places + * (other than hotplug poll/irq), we need to separately keep + * track of the connection status at last should-I-send-an- + * hpd-event check, to avoid forgetting to send an hpd event + * to userspace + */ + enum drm_connector_status hpd_status; + /* these are modes added by probing with DDC or the BIOS */ struct list_head probed_modes; -- 2.1.0 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel