Received: by 10.223.185.111 with SMTP id b44csp777643wrg; Fri, 9 Mar 2018 13:34:19 -0800 (PST) X-Google-Smtp-Source: AG47ELsOnE/M9l3WpBhMgLYRFnXRGlsY57l/CNvvAWZgkfpm8ZfxO3fd0m5J3jRIO+dqTmWJxJMV X-Received: by 2002:a17:902:9a4a:: with SMTP id x10-v6mr21551964plv.256.1520631259736; Fri, 09 Mar 2018 13:34:19 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1520631259; cv=none; d=google.com; s=arc-20160816; b=bDQuS14uuRy5MavT6eF0KjueQEssl7KegQyx624aYw/OFKv4m0HLcvjdM/O3AuSK8w zcQkBuihIOduFeCGBkoYl8yRWBg5FHqUOK+r1XllK05gzFGs6yrb9gsiTkHkDau4xKrG DssMxQLnXFYg11VQbqBdc1sAlFO0q6MflnJF3Pnj+Un9r7HIZM51UkXSKWTMvPlRicqO zSW2Joi2hzVbBwZDoB/tRVNoPSn9cy0ntgXSic43SHDgDA7wXjWi49H6UhODA1IHWnWV iN62ityw45kIpDXNvDF4WZ4RvMyC7Gg0yCZGVFVd8fSkCjSnSrbmSkVpXTLU4PMkIpjg BDIg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :arc-authentication-results; bh=390p5GMABiIjmIC4eR+1HVrbkjRdipM3IPfeDFkoMVU=; b=c/b+0SYCUi5QWckokTnRoFOfUEYhvoIcftarKvpuopdexQs62NL9X61Jt4Q4ta23ir ju1PnqKeU0j7uzq6ulyBaso7eWHhS3yMct5QA1r+nZhbUXlgvoj8jWjAJfUI2WCMFiqv 9rjrENEORVwcJBnedHbcdo/E6NIG6jHXeB1TIubjUkf/ZcaueOxUPxuWUfRa72BLF1Ej MDxOkPEGDymctFY66uU776frunGlUnUGwrFWKLh+8dxw78btRtulpjURB+sXrTxU2eCF r6wtzSxisBCt/Al+lIou5ho7SuQDcVExG57SuhScS2baZ0N7k0WTI1beDVkmOeGjNJ3w oSmA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 64si1301820pgi.67.2018.03.09.13.34.04; Fri, 09 Mar 2018 13:34:19 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932633AbeCIVdK (ORCPT + 99 others); Fri, 9 Mar 2018 16:33:10 -0500 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:56672 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S932327AbeCIVdH (ORCPT ); Fri, 9 Mar 2018 16:33:07 -0500 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 0D34AEBFF3; Fri, 9 Mar 2018 21:33:07 +0000 (UTC) Received: from malachite.bss.redhat.com (dhcp-10-20-1-30.bss.redhat.com [10.20.1.30]) by smtp.corp.redhat.com (Postfix) with ESMTP id AC84494594; Fri, 9 Mar 2018 21:33:06 +0000 (UTC) From: Lyude Paul To: intel-gfx@lists.freedesktop.org Cc: dri-devel@lists.freedesktop.org, Manasi Navare , =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= , Gustavo Padovan , Maarten Lankhorst , Sean Paul , David Airlie , linux-kernel@vger.kernel.org Subject: [PATCH v3 4/5] drm/dp_mst: Add drm_atomic_dp_mst_retrain_topology() Date: Fri, 9 Mar 2018 16:32:30 -0500 Message-Id: <20180309213232.19855-4-lyude@redhat.com> In-Reply-To: <20180309213232.19855-1-lyude@redhat.com> References: <20180308232421.14049-1-lyude@redhat.com> <20180309213232.19855-1-lyude@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Fri, 09 Mar 2018 21:33:07 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Fri, 09 Mar 2018 21:33:07 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lyude@redhat.com' RCPT:'' Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Retraining MST is rather difficult. In order to do it properly while guaranteeing that we'll never run into a spot where we commit a physically impossible configuration, we have to do a lot of checks on atomic commits which affect MST topologies. All of this work is going to need to be repeated for every driver at some point, so let's save ourselves some trouble and just implement these atomic checks as a single helper. Signed-off-by: Lyude Paul Cc: Manasi Navare Cc: Ville Syrjälä --- drivers/gpu/drm/drm_dp_mst_topology.c | 223 ++++++++++++++++++++++++++++++++++ include/drm/drm_dp_mst_helper.h | 2 + 2 files changed, 225 insertions(+) diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 0d6604500b29..c4a91b1ba61b 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2167,6 +2167,229 @@ int drm_dp_mst_topology_mgr_lower_link_rate(struct drm_dp_mst_topology_mgr *mgr, } EXPORT_SYMBOL(drm_dp_mst_topology_mgr_lower_link_rate); +static bool drm_atomic_dp_mst_state_only_disables_mstbs(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_branch *mstb) +{ + struct drm_dp_mst_branch *rmstb; + struct drm_dp_mst_port *port; + struct drm_connector *connector; + struct drm_connector_state *conn_state; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int ret; + + list_for_each_entry(port, &mstb->ports, next) { + rmstb = drm_dp_get_validated_mstb_ref(mstb->mgr, port->mstb); + if (rmstb) { + ret = drm_atomic_dp_mst_state_only_disables_mstbs( + state, mgr, rmstb); + drm_dp_put_mst_branch_device(rmstb); + if (!ret) + return false; + } + + connector = port->connector; + if (!connector) + continue; + + conn_state = drm_atomic_get_new_connector_state( + state, connector); + if (!conn_state) + continue; + + crtc = conn_state->crtc; + if (!crtc) + continue; + + crtc_state = drm_atomic_get_new_crtc_state(state, crtc); + if (!crtc_state) + continue; + + if (drm_atomic_crtc_needs_modeset(crtc_state)) + return false; + } + + return true; +} + +static int drm_atomic_dp_mst_all_mstbs_disabled(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_branch *mstb) +{ + struct drm_dp_mst_branch *rmstb; + struct drm_dp_mst_port *port; + struct drm_connector *connector; + struct drm_connector_state *conn_state; + int ret; + + list_for_each_entry(port, &mstb->ports, next) { + rmstb = drm_dp_get_validated_mstb_ref(mstb->mgr, port->mstb); + if (rmstb) { + ret = drm_atomic_dp_mst_all_mstbs_disabled( + state, mgr, rmstb); + drm_dp_put_mst_branch_device(rmstb); + if (ret <= 0) + return ret; + } + + connector = port->connector; + if (!connector) + continue; + + conn_state = drm_atomic_get_connector_state( + state, connector); + if (IS_ERR(conn_state)) + return PTR_ERR(conn_state); + + if (conn_state->crtc) + return false; + } + + /* No enabled CRTCs found */ + return true; +} + +static int drm_atomic_dp_mst_retrain_mstb(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_branch *mstb, + bool full_modeset) +{ + struct drm_dp_mst_branch *rmstb; + struct drm_dp_mst_port *port; + struct drm_connector *connector; + struct drm_connector_state *conn_state; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int ret; + + list_for_each_entry(port, &mstb->ports, next) { + rmstb = drm_dp_get_validated_mstb_ref(mstb->mgr, port->mstb); + if (rmstb) { + ret = drm_atomic_dp_mst_retrain_mstb( + state, mgr, rmstb, full_modeset); + drm_dp_put_mst_branch_device(rmstb); + if (ret) + return ret; + } + + connector = port->connector; + if (!connector) + continue; + + conn_state = drm_atomic_get_connector_state(state, connector); + if (IS_ERR(conn_state)) + return PTR_ERR(conn_state); + + if (conn_state->link_status != DRM_MODE_LINK_STATUS_GOOD) { + DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] link status bad -> good\n", + connector->base.id, connector->name); + conn_state->link_status = DRM_MODE_LINK_STATUS_GOOD; + } + + if (!full_modeset) + continue; + + crtc = conn_state->crtc; + if (!crtc) + continue; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (!crtc_state->mode_changed) { + DRM_DEBUG_ATOMIC("[CRTC:%d:%s] needs full modeset\n", + crtc->base.id, crtc->name); + crtc_state->mode_changed = true; + } + } + + return 0; +} + +/** + * drm_atomic_dp_mst_retrain_topology() - prepare a modeset that will retrain + * an MST topology + * @state: The new state that would retrain the topology link + * @mgr: The topology manager to use + * + * After userspace has been signaled that connectors are in need of + * retraining, it's expected that a modeset will be performed for any CRTCs on + * said connectors. Since all of the branch devices in an MST topology share a + * single link, they also share the same link status, lane count, and link + * rate. + * + * Since all of these characteristics are shared, there's only two valid + * solutions when fallback link training parameters need to be applied. The + * first is simply unassigning each mstb connector's CRTC. Since this action + * can only free slots on the VCPI table and not allocate them, this can be + * done without pulling in additional CRTCs on the MST topology. Additionally + * if this action would result in there no longer being any CRTCs assigned to + * mstb connectors, this would be enough to bring the topology back into a + * trained state since there would be nothing left requiring VCPI + * reallocations. + * + * The second solution is to commit new modes to all of the connectors on the + * topology. Since this action would result in VCPI reallocations with a new + * link rate and lane count, a modeset must also be performed on every other + * CRTC driving a branch device on the given topology at the same time. This + * is to ensure that all VCPI allocations are properly recalculated in + * response to the new link rate and lane count, that the new modes will fit + * into the recalculated VCPI table, and that the new atomic state could never + * result in an otherwise physically impossible configuration (e.g. different + * mstbs with CRTCs trained to different link rates/lane counts). + * + * Finally, any atomic commit which would result in going from an + * unrecoverable link state to a properly trained link state must also take + * care of appropriately updating the link status properties of all connectors + * on the topology from bad to good. This function takes care of all of these + * checks in @state for the topology manager @mgr including possibly pulling + * in additional CRTCs into the modeset, and possibly updating the link status + * of each mstb's DRM connector. + * + * This function should be called within the driver's atomic check callbacks + * whenever a modeset happens on an MST connector with it's link status set to + * DRM_MODE_LINK_STATUS_BAD. + * + * RETURNS: + * + * Returns 0 for success, or negative error code for failure. + */ +int drm_atomic_dp_mst_retrain_topology(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr) +{ + struct drm_dp_mst_branch *mstb = + drm_dp_get_validated_mstb_ref(mgr, mgr->mst_primary); + int ret = 0; + bool need_modeset = false; + + if (!mstb) + return 0; + + if (drm_atomic_dp_mst_state_only_disables_mstbs(state, mgr, mstb)) { + ret = drm_atomic_dp_mst_all_mstbs_disabled(state, mgr, mstb); + if (ret < 0) + goto out; + + if (ret) + DRM_DEBUG_ATOMIC("state %p disables all CRTCs on mst mgr %p\n", + state, mgr); + else + goto out; /* valid, but doesn't retrain link */ + } else { + DRM_DEBUG_ATOMIC("state %p requires full modeset for CRTCs on mst mgr %p\n", + state, mgr); + need_modeset = true; + } + + ret = drm_atomic_dp_mst_retrain_mstb(state, mgr, mstb, need_modeset); +out: + drm_dp_put_mst_branch_device(mgr->mst_primary); + return ret; +} +EXPORT_SYMBOL(drm_atomic_dp_mst_retrain_topology); + /** * drm_dp_mst_topology_mgr_set_mst() - Set the MST state for a topology manager * @mgr: manager to set state for diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 6261ec43a2c0..24075eb2dd1b 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -636,5 +636,7 @@ int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, int drm_dp_mst_topology_mgr_lower_link_rate(struct drm_dp_mst_topology_mgr *mgr, int dp_link_bw, int dp_link_count); +int drm_atomic_dp_mst_retrain_topology(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr); #endif -- 2.14.3