From patchwork Wed Jun 5 15:50:14 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chris Wilson X-Patchwork-Id: 2670831 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork1.kernel.org (Postfix) with ESMTP id E861A3FD4F for ; Wed, 5 Jun 2013 15:50:57 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C1E4AE61C5 for ; Wed, 5 Jun 2013 08:50:57 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from fireflyinternet.com (s16502780.onlinehome-server.info [87.106.93.118]) by gabe.freedesktop.org (Postfix) with ESMTP id C84DDE6189 for ; Wed, 5 Jun 2013 08:50:45 -0700 (PDT) X-Default-Received-SPF: pass (skip=forwardok (res=PASS)) x-ip-name=78.156.73.22; Received: from arrandale.alporthouse.com (unverified [78.156.73.22]) by fireflyinternet.com (Firefly Internet (M2)) with ESMTP id 7494778-1500048 for multiple; Wed, 05 Jun 2013 16:51:09 +0100 From: Chris Wilson To: dri-devel@lists.freedesktop.org Subject: [PATCH] drm: Avoid forcing a detection cycle following a hotplug event Date: Wed, 5 Jun 2013 16:50:14 +0100 Message-Id: <1370447414-30844-1-git-send-email-chris@chris-wilson.co.uk> X-Mailer: git-send-email 1.7.10.4 X-Originating-IP: 78.156.73.22 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org Errors-To: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org 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 Cc: dri-devel@lists.freedesktop.org Cc: Jakob Bornecrantz Cc: Inki Dae Cc: Adam Jackson --- 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,