From patchwork Thu May 19 14:19:55 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: cpaul@redhat.com X-Patchwork-Id: 9127721 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id DC79E60467 for ; Thu, 19 May 2016 14:20:13 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 464B82808F for ; Thu, 19 May 2016 14:20:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 37845281C5; Thu, 19 May 2016 14:20:12 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1FACA2808F for ; Thu, 19 May 2016 14:20:10 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 21E7B6E948; Thu, 19 May 2016 14:20:10 +0000 (UTC) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by gabe.freedesktop.org (Postfix) with ESMTPS id 39B816E948; Thu, 19 May 2016 14:20:08 +0000 (UTC) Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id BA39A3B758; Thu, 19 May 2016 14:20:07 +0000 (UTC) Received: from ecstaticemu.bos.redhat.com (dhcp-25-142.bos.redhat.com [10.18.25.142]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u4JEK6iu009688; Thu, 19 May 2016 10:20:06 -0400 From: Lyude To: intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, Dave Airlie Date: Thu, 19 May 2016 10:19:55 -0400 Message-Id: <1463667596-25236-1-git-send-email-cpaul@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.24 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Thu, 19 May 2016 14:20:07 +0000 (UTC) Cc: open list , stable@vger.kernel.org Subject: [Intel-gfx] [PATCH 1/2] drm/dp/mst: Reprobe EDID for MST ports on resume X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP As observed with the latest ThinkPad docks, we unfortunately can't rely on docks keeping us updated with hotplug events that happened while we were suspended. On top of that, even if the number of connectors remains the same between suspend and resume it's still not safe to assume that there were no hotplugs, since a different monitor might have been plugged into a port another monitor previously occupied. As such, we need to go through all of the MST ports and check whether or not their EDIDs have changed. In addition to that, we also now return -EINVAL from drm_dp_mst_topology_mgr_resume to indicate to callers that they need to reset the MST connection, and that they can't rely on any other method of reprobing. Cc: stable@vger.kernel.org Signed-off-by: Lyude --- drivers/gpu/drm/drm_dp_mst_topology.c | 92 ++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 71ea052..cc68c74 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -2118,6 +2119,62 @@ void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr) } EXPORT_SYMBOL(drm_dp_mst_topology_mgr_suspend); +static bool drm_dp_mst_edids_changed(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port) +{ + struct drm_device *dev; + struct drm_connector *connector; + struct drm_dp_mst_port *dport; + struct drm_dp_mst_branch *mstb; + struct edid *current_edid, *cached_edid; + bool ret = false; + + port = drm_dp_get_validated_port_ref(mgr, port); + if (!port) + return false; + + mstb = drm_dp_get_validated_mstb_ref(mgr, port->mstb); + if (mstb) { + list_for_each_entry(dport, &port->mstb->ports, next) { + ret = drm_dp_mst_edids_changed(mgr, dport); + if (ret) + break; + } + + drm_dp_put_mst_branch_device(mstb); + if (ret) + goto out; + } + + connector = port->connector; + if (!connector || !port->aux.ddc.algo) + goto out; + + dev = connector->dev; + mutex_lock(&dev->mode_config.mutex); + + current_edid = drm_get_edid(connector, &port->aux.ddc); + cached_edid = (void*)connector->edid_blob_ptr->data; + + if ((current_edid && cached_edid && memcmp(current_edid, cached_edid, + sizeof(struct edid)) != 0) || + (!current_edid && cached_edid) || (current_edid && !cached_edid)) { + ret = true; + DRM_DEBUG_KMS("EDID on %s changed, reprobing connectors\n", + connector->name); + } + + mutex_unlock(&dev->mode_config.mutex); + + if (current_edid) + kfree(current_edid); + +out: + drm_dp_put_port(port); + + return ret; +} + /** * drm_dp_mst_topology_mgr_resume() - resume the MST manager * @mgr: manager to resume @@ -2127,9 +2184,15 @@ EXPORT_SYMBOL(drm_dp_mst_topology_mgr_suspend); * * if the device fails this returns -1, and the driver should do * a full MST reprobe, in case we were undocked. + * + * if the device can no longer be trusted, this returns -EINVAL + * and the driver should unconditionally disconnect and reconnect + * the dock. */ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr) { + struct drm_dp_mst_branch *mstb; + struct drm_dp_mst_port *port; int ret = 0; mutex_lock(&mgr->lock); @@ -2163,8 +2226,35 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr) drm_dp_check_mstb_guid(mgr->mst_primary, guid); ret = 0; - } else + + /* + * Some hubs also forget to notify us of hotplugs that happened + * while we were in suspend, so we need to verify that the edid + * hasn't changed for any of the connectors. If it has been, + * we unfortunately can't rely on the dock updating us with + * hotplug events, so indicate we need a full reconnect. + */ + + /* MST's I2C helpers can't be used while holding this lock */ + mutex_unlock(&mgr->lock); + + mstb = drm_dp_get_validated_mstb_ref(mgr, mgr->mst_primary); + if (mstb) { + list_for_each_entry(port, &mstb->ports, next) { + if (drm_dp_mst_edids_changed(mgr, port)) { + ret = -EINVAL; + break; + } + } + + drm_dp_put_mst_branch_device(mstb); + } + } else { ret = -1; + mutex_unlock(&mgr->lock); + } + + return ret; out_unlock: mutex_unlock(&mgr->lock);