@@ -817,31 +817,38 @@ static void output_poll_execute(struct slow_work *work)
struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_slow_work);
struct drm_connector *connector;
enum drm_connector_status old_status, status;
- bool repoll = false, changed = false;
+ bool repoll = false, changed = false, need_poll, hpd_detected;
int ret;
+ hpd_detected = ACCESS_ONCE(dev->mode_config.hpd_detected);
+ ACCESS_ONCE(dev->mode_config.hpd_detected) = 0;
+
mutex_lock(&dev->mode_config.mutex);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- /* if this is HPD or polled don't check it -
- TV out for instance */
+ /* don't poll unless the drivers asked us to. */
if (!connector->polled)
continue;
- else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT))
- repoll = true;
+ /* poll if we got an HPD request... */
+ need_poll = hpd_detected;
+ /* ...or if we're supposed to poll all the time */
old_status = connector->status;
- /* if we are connected and don't want to poll for disconnect
- skip it */
- if (old_status == connector_status_connected &&
- !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) &&
- !(connector->polled & DRM_CONNECTOR_POLL_HPD))
- continue;
+ if (old_status == connector_status_connected ?
+ (connector->polled & DRM_CONNECTOR_POLL_CONNECT) :
+ (connector->polled & DRM_CONNECTOR_POLL_DISCONNECT))
+ need_poll = true;
- status = connector->funcs->detect(connector);
- if (old_status != status)
- changed = true;
+ /* Do we re-queue? */
+ if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT))
+ repoll = true;
+
+ if (need_poll) {
+ status = connector->funcs->detect(connector);
+ if (old_status != status)
+ changed = true;
+ }
}
mutex_unlock(&dev->mode_config.mutex);
@@ -911,6 +918,7 @@ void drm_helper_hpd_irq_event(struct drm_device *dev)
return;
delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
/* schedule a slow work asap */
+ ACCESS_ONCE(dev->mode_config.hpd_detected) = true;
delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, 0);
}
EXPORT_SYMBOL(drm_helper_hpd_irq_event);
@@ -596,6 +596,7 @@ struct drm_mode_config {
/* output poll support */
bool poll_enabled;
struct delayed_slow_work output_poll_slow_work;
+ bool hpd_detected;
/* pointers to standard properties */
struct list_head property_blob_list;