The typical procedure after a hotplug event is then to enumerate all the
new modes. In the existing code, this is achieved by performing a forced
detection cycle over all connectors. Ideally, we should just be able to
use the current detection status and only enumerate the modes on the
connectors that changed. This is a step in that direction by teaching
the hotplug path to only use the known detection status rather than
performing a second *forced* detection on every connector. As it
currently stands, the first thing userspace does upon receipt of a
hotplug uevent is call DRM_IOCTL_MODE_GETCONNECTOR on each connector,
which of course, performs another full detection cycle.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
Cc: dri-devel at lists.freedesktop.org
Cc: Jakob Bornecrantz <jakob at vmware.com>
Cc: Inki Dae <inki.dae at samsung.com>
Cc: Adam Jackson <ajax at redhat.com>
---
 drivers/gpu/drm/drm_crtc.c                    |    3 ++-
 drivers/gpu/drm/drm_crtc_helper.c             |    8 ++++++--
 drivers/gpu/drm/drm_fb_helper.c               |   14 ++++++++------
 drivers/gpu/drm/exynos/exynos_drm_connector.c |    7 ++++---
 drivers/gpu/drm/i2c/ch7006_drv.c              |    2 +-
 drivers/gpu/drm/nouveau/dispnv04/tvnv17.c     |    2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c           |    3 ++-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.h           |    3 ++-
 include/drm/drm_crtc.h                        |    2 +-
 include/drm/drm_crtc_helper.h                 |    2 +-
 10 files changed, 28 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index e7e9242..635276c 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1537,7 +1537,8 @@ int drm_mode_getconnector(struct drm_device *dev, void 
*data,
        if (out_resp->count_modes == 0) {
                connector->funcs->fill_modes(connector,
                                             dev->mode_config.max_width,
-                                            dev->mode_config.max_height);
+                                            dev->mode_config.max_height,
+                                            true);
        }

        /* delayed so we get modes regardless of pre-fill_modes state */
diff --git a/drivers/gpu/drm/drm_crtc_helper.c 
b/drivers/gpu/drm/drm_crtc_helper.c
index ed1334e..7f2128c 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -96,6 +96,9 @@ static void drm_mode_validate_flag(struct drm_connector 
*connector,
  * @connector: connector to probe
  * @maxX: max width for modes
  * @maxY: max height for modes
+ * @force: whether to use the cached connector status or to force a
+ *         fresh detection cycle, for instance after a hotplug event, we
+ *         want to simply use the known status.
  *
  * LOCKING:
  * Caller must hold mode config lock.
@@ -113,7 +116,8 @@ static void drm_mode_validate_flag(struct drm_connector 
*connector,
  * Number of modes found on @connector.
  */
 int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
-                                           uint32_t maxX, uint32_t maxY)
+                                           uint32_t maxX, uint32_t maxY,
+                                           bool force)
 {
        struct drm_device *dev = connector->dev;
        struct drm_display_mode *mode;
@@ -136,7 +140,7 @@ int drm_helper_probe_single_connector_modes(struct 
drm_connector *connector,
                        connector->status = connector_status_disconnected;
                if (connector->funcs->force)
                        connector->funcs->force(connector);
-       } else {
+       } else if (force) {
                connector->status = connector->funcs->detect(connector, true);
        }

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index b78cbe7..3e0802d 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -1087,8 +1087,8 @@ void drm_fb_helper_fill_var(struct fb_info *info, struct 
drm_fb_helper *fb_helpe
 EXPORT_SYMBOL(drm_fb_helper_fill_var);

 static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
-                                              uint32_t maxX,
-                                              uint32_t maxY)
+                                              uint32_t maxX, uint32_t maxY,
+                                              bool force)
 {
        struct drm_connector *connector;
        int count = 0;
@@ -1096,7 +1096,7 @@ static int drm_fb_helper_probe_connector_modes(struct 
drm_fb_helper *fb_helper,

        for (i = 0; i < fb_helper->connector_count; i++) {
                connector = fb_helper->connector_info[i]->connector;
-               count += connector->funcs->fill_modes(connector, maxX, maxY);
+               count += connector->funcs->fill_modes(connector, maxX, maxY, 
force);
        }

        return count;
@@ -1510,7 +1510,8 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper 
*fb_helper, int bpp_sel)

        count = drm_fb_helper_probe_connector_modes(fb_helper,
                                                    dev->mode_config.max_width,
-                                                   
dev->mode_config.max_height);
+                                                   dev->mode_config.max_height,
+                                                   true);
        /*
         * we shouldn't end up with no modes here.
         */
@@ -1563,8 +1564,9 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper 
*fb_helper)
        max_height = fb_helper->fb->height;
        bpp_sel = fb_helper->fb->bits_per_pixel;

-       count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
-                                                   max_height);
+       count = drm_fb_helper_probe_connector_modes(fb_helper,
+                                                   max_width, max_height,
+                                                   false);
        mutex_unlock(&fb_helper->dev->mode_config.mutex);

        drm_modeset_lock_all(dev);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c 
b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index 8bcc13a..48ef16f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -249,7 +249,8 @@ static void exynos_drm_connector_dpms(struct drm_connector 
*connector,
 }

 static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
-                               unsigned int max_width, unsigned int max_height)
+                               unsigned int max_width, unsigned int max_height,
+                               bool force)
 {
        struct exynos_drm_connector *exynos_connector =
                                        to_exynos_connector(connector);
@@ -267,8 +268,8 @@ static int exynos_drm_connector_fill_modes(struct 
drm_connector *connector,
        if (ops && ops->get_max_resol)
                ops->get_max_resol(manager->dev, &width, &height);

-       return drm_helper_probe_single_connector_modes(connector, width,
-                                                       height);
+       return drm_helper_probe_single_connector_modes(connector,
+                                                      width, height, force);
 }

 /* get detection status of display device. */
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c
index 51fa323..d18237d 100644
--- a/drivers/gpu/drm/i2c/ch7006_drv.c
+++ b/drivers/gpu/drm/i2c/ch7006_drv.c
@@ -355,7 +355,7 @@ static int ch7006_encoder_set_property(struct drm_encoder 
*encoder,
        }

        if (modes_changed) {
-               drm_helper_probe_single_connector_modes(connector, 0, 0);
+               drm_helper_probe_single_connector_modes(connector, 0, 0, false);

                /* Disable the crtc to ensure a full modeset is
                 * performed whenever it's turned on again. */
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c 
b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
index acef48f..535dd14 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
@@ -759,7 +759,7 @@ static int nv17_tv_set_property(struct drm_encoder *encoder,
        }

        if (modes_changed) {
-               drm_helper_probe_single_connector_modes(connector, 0, 0);
+               drm_helper_probe_single_connector_modes(connector, 0, 0, false);

                /* Disable the crtc to ensure a full modeset is
                 * performed whenever it's turned on again. */
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c 
b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 3e3c7ab..d9a0768 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -1924,7 +1924,8 @@ static void vmw_guess_mode_timing(struct drm_display_mode 
*mode)


 int vmw_du_connector_fill_modes(struct drm_connector *connector,
-                               uint32_t max_width, uint32_t max_height)
+                               uint32_t max_width, uint32_t max_height,
+                               bool force)
 {
        struct vmw_display_unit *du = vmw_connector_to_du(connector);
        struct drm_device *dev = connector->dev;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h 
b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index 6fa89c9..19fc306 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -138,7 +138,8 @@ void vmw_du_connector_restore(struct drm_connector 
*connector);
 enum drm_connector_status
 vmw_du_connector_detect(struct drm_connector *connector, bool force);
 int vmw_du_connector_fill_modes(struct drm_connector *connector,
-                               uint32_t max_width, uint32_t max_height);
+                               uint32_t max_width, uint32_t max_height,
+                               bool force);
 int vmw_du_connector_set_property(struct drm_connector *connector,
                                  struct drm_property *property,
                                  uint64_t val);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index adb3f9b..373e774 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -468,7 +468,7 @@ struct drm_connector_funcs {
         */
        enum drm_connector_status (*detect)(struct drm_connector *connector,
                                            bool force);
-       int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, 
uint32_t max_height);
+       int (*fill_modes)(struct drm_connector *connector, uint32_t max_width, 
uint32_t max_height, bool force);
        int (*set_property)(struct drm_connector *connector, struct 
drm_property *property,
                             uint64_t val);
        void (*destroy)(struct drm_connector *connector);
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index f43d556..cce7221 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -125,7 +125,7 @@ struct drm_connector_helper_funcs {
        struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
 };

-extern int drm_helper_probe_single_connector_modes(struct drm_connector 
*connector, uint32_t maxX, uint32_t maxY);
+extern int drm_helper_probe_single_connector_modes(struct drm_connector 
*connector, uint32_t maxX, uint32_t maxY, bool force);
 extern void drm_helper_disable_unused_functions(struct drm_device *dev);
 extern int drm_crtc_helper_set_config(struct drm_mode_set *set);
 extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
-- 
1.7.10.4

Reply via email to