drm: Add an HPD poll helper to reschedule the poll work
authorImre Deak <imre.deak@intel.com>
Tue, 22 Aug 2023 11:30:14 +0000 (14:30 +0300)
committerRodrigo Vivi <rodrigo.vivi@intel.com>
Wed, 23 Aug 2023 21:14:37 +0000 (17:14 -0400)
Add a helper to reschedule drm_mode_config::output_poll_work after
polling has been enabled for a connector (and needing a reschedule,
since previously polling was disabled for all connectors and hence
output_poll_work was not running).

This is needed by the next patch fixing HPD polling on i915.

CC: stable@vger.kernel.org # 6.4+
Cc: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Cc: dri-devel@lists.freedesktop.org
Reviewed-by: Jouni Högander <jouni.hogander@intel.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230822113015.41224-1-imre.deak@intel.com
(cherry picked from commit fe2352fd64029918174de4b460dfe6df0c6911cd)
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
drivers/gpu/drm/drm_probe_helper.c
include/drm/drm_probe_helper.h

index 2fb9bf9..3f47948 100644 (file)
@@ -262,6 +262,26 @@ static bool drm_kms_helper_enable_hpd(struct drm_device *dev)
 }
 
 #define DRM_OUTPUT_POLL_PERIOD (10*HZ)
+static void reschedule_output_poll_work(struct drm_device *dev)
+{
+       unsigned long delay = DRM_OUTPUT_POLL_PERIOD;
+
+       if (dev->mode_config.delayed_event)
+               /*
+                * FIXME:
+                *
+                * Use short (1s) delay to handle the initial delayed event.
+                * This delay should not be needed, but Optimus/nouveau will
+                * fail in a mysterious way if the delayed event is handled as
+                * soon as possible like it is done in
+                * drm_helper_probe_single_connector_modes() in case the poll
+                * was enabled before.
+                */
+               delay = HZ;
+
+       schedule_delayed_work(&dev->mode_config.output_poll_work, delay);
+}
+
 /**
  * drm_kms_helper_poll_enable - re-enable output polling.
  * @dev: drm_device
@@ -279,37 +299,41 @@ static bool drm_kms_helper_enable_hpd(struct drm_device *dev)
  */
 void drm_kms_helper_poll_enable(struct drm_device *dev)
 {
-       bool poll = false;
-       unsigned long delay = DRM_OUTPUT_POLL_PERIOD;
-
        if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll ||
            dev->mode_config.poll_running)
                return;
 
-       poll = drm_kms_helper_enable_hpd(dev);
-
-       if (dev->mode_config.delayed_event) {
-               /*
-                * FIXME:
-                *
-                * Use short (1s) delay to handle the initial delayed event.
-                * This delay should not be needed, but Optimus/nouveau will
-                * fail in a mysterious way if the delayed event is handled as
-                * soon as possible like it is done in
-                * drm_helper_probe_single_connector_modes() in case the poll
-                * was enabled before.
-                */
-               poll = true;
-               delay = HZ;
-       }
-
-       if (poll)
-               schedule_delayed_work(&dev->mode_config.output_poll_work, delay);
+       if (drm_kms_helper_enable_hpd(dev) ||
+           dev->mode_config.delayed_event)
+               reschedule_output_poll_work(dev);
 
        dev->mode_config.poll_running = true;
 }
 EXPORT_SYMBOL(drm_kms_helper_poll_enable);
 
+/**
+ * drm_kms_helper_poll_reschedule - reschedule the output polling work
+ * @dev: drm_device
+ *
+ * This function reschedules the output polling work, after polling for a
+ * connector has been enabled.
+ *
+ * Drivers must call this helper after enabling polling for a connector by
+ * setting %DRM_CONNECTOR_POLL_CONNECT / %DRM_CONNECTOR_POLL_DISCONNECT flags
+ * in drm_connector::polled. Note that after disabling polling by clearing these
+ * flags for a connector will stop the output polling work automatically if
+ * the polling is disabled for all other connectors as well.
+ *
+ * The function can be called only after polling has been enabled by calling
+ * drm_kms_helper_poll_init() / drm_kms_helper_poll_enable().
+ */
+void drm_kms_helper_poll_reschedule(struct drm_device *dev)
+{
+       if (dev->mode_config.poll_running)
+               reschedule_output_poll_work(dev);
+}
+EXPORT_SYMBOL(drm_kms_helper_poll_reschedule);
+
 static enum drm_connector_status
 drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force)
 {
index 4977e0a..fad3c40 100644 (file)
@@ -25,6 +25,7 @@ void drm_kms_helper_connector_hotplug_event(struct drm_connector *connector);
 
 void drm_kms_helper_poll_disable(struct drm_device *dev);
 void drm_kms_helper_poll_enable(struct drm_device *dev);
+void drm_kms_helper_poll_reschedule(struct drm_device *dev);
 bool drm_kms_helper_is_poll_worker(void);
 
 enum drm_mode_status drm_crtc_helper_mode_valid_fixed(struct drm_crtc *crtc,