From patchwork Fri Nov 16 00:50:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lyude Paul X-Patchwork-Id: 10685355 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 31AE414E2 for ; Fri, 16 Nov 2018 00:50:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1F89D2D335 for ; Fri, 16 Nov 2018 00:50:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 139C32D440; Fri, 16 Nov 2018 00:50:30 +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=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id AA2342D335 for ; Fri, 16 Nov 2018 00:50:29 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 68D7D6E629; Fri, 16 Nov 2018 00:50:22 +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 04C6B6E11D; Fri, 16 Nov 2018 00:50:21 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 966AD3086252; Fri, 16 Nov 2018 00:50:20 +0000 (UTC) Received: from malachite.bss.redhat.com (dhcp-10-20-1-11.bss.redhat.com [10.20.1.11]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0946063767; Fri, 16 Nov 2018 00:50:19 +0000 (UTC) From: Lyude Paul To: intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org Date: Thu, 15 Nov 2018 19:50:03 -0500 Message-Id: <20181116005008.7243-2-lyude@redhat.com> In-Reply-To: <20181116005008.7243-1-lyude@redhat.com> References: <20181116005008.7243-1-lyude@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.49]); Fri, 16 Nov 2018 00:50:20 +0000 (UTC) Subject: [Intel-gfx] [PATCH v6 1/6] drm/dp_mst: Add some atomic state iterator macros X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Lyude Paul Reviewed-by: Daniel Vetter --- include/drm/drm_dp_mst_helper.h | 77 +++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 59f005b419cf..3faceb66f5cb 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -628,4 +628,81 @@ int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, bool power_up); +extern const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs; + +static inline bool +__drm_dp_mst_state_iter_get(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr **mgr, + struct drm_dp_mst_topology_state **old_state, + struct drm_dp_mst_topology_state **new_state, + int i) +{ + struct __drm_private_objs_state *objs_state = &state->private_objs[i]; + + if (objs_state->ptr->funcs != &drm_dp_mst_topology_state_funcs) + return false; + + *mgr = to_dp_mst_topology_mgr(objs_state->ptr); + if (old_state) + *old_state = to_dp_mst_topology_state(objs_state->old_state); + if (new_state) + *new_state = to_dp_mst_topology_state(objs_state->new_state); + + return true; +} + +/** + * for_each_oldnew_mst_mgr_in_state - iterate over all DP MST topology + * managers in an atomic update + * @__state: &struct drm_atomic_state pointer + * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor + * @old_state: &struct drm_dp_mst_topology_state iteration cursor for the old + * state + * @new_state: &struct drm_dp_mst_topology_state iteration cursor for the new + * state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all DRM DP MST topology managers in an atomic update, + * tracking both old and new state. This is useful in places where the state + * delta needs to be considered, for example in atomic check functions. + */ +#define for_each_oldnew_mst_mgr_in_state(__state, mgr, old_state, new_state, __i) \ + for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ + for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), &(old_state), &(new_state), (__i))) + +/** + * for_each_old_mst_mgr_in_state - iterate over all DP MST topology managers + * in an atomic update + * @__state: &struct drm_atomic_state pointer + * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor + * @old_state: &struct drm_dp_mst_topology_state iteration cursor for the old + * state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all DRM DP MST topology managers in an atomic update, + * tracking only the old state. This is useful in disable functions, where we + * need the old state the hardware is still in. + */ +#define for_each_old_mst_mgr_in_state(__state, mgr, old_state, __i) \ + for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ + for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), &(old_state), NULL, (__i))) + +/** + * for_each_new_mst_mgr_in_state - iterate over all DP MST topology managers + * in an atomic update + * @__state: &struct drm_atomic_state pointer + * @mgr: &struct drm_dp_mst_topology_mgr iteration cursor + * @new_state: &struct drm_dp_mst_topology_state iteration cursor for the new + * state + * @__i: int iteration cursor, for macro-internal use + * + * This iterates over all DRM DP MST topology managers in an atomic update, + * tracking only the new state. This is useful in enable functions, where we + * need the new state the hardware should be in when the atomic commit + * operation has completed. + */ +#define for_each_new_mst_mgr_in_state(__state, mgr, new_state, __i) \ + for ((__i) = 0; (__i) < (__state)->num_private_objs; (__i)++) \ + for_each_if(__drm_dp_mst_state_iter_get((__state), &(mgr), NULL, &(new_state), (__i))) + #endif From patchwork Fri Nov 16 00:50:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lyude Paul X-Patchwork-Id: 10685361 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 267B614E2 for ; Fri, 16 Nov 2018 00:50:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 182AB2D3E2 for ; Fri, 16 Nov 2018 00:50:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0BD6A2D446; Fri, 16 Nov 2018 00:50:37 +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=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id C42D12D3E2 for ; Fri, 16 Nov 2018 00:50:36 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id C7F576E6A9; Fri, 16 Nov 2018 00:50:23 +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 B2CC06E11D; Fri, 16 Nov 2018 00:50:21 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 518C9C058CD8; Fri, 16 Nov 2018 00:50:21 +0000 (UTC) Received: from malachite.bss.redhat.com (dhcp-10-20-1-11.bss.redhat.com [10.20.1.11]) by smtp.corp.redhat.com (Postfix) with ESMTP id AE5C617B18; Fri, 16 Nov 2018 00:50:20 +0000 (UTC) From: Lyude Paul To: intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org Date: Thu, 15 Nov 2018 19:50:04 -0500 Message-Id: <20181116005008.7243-3-lyude@redhat.com> In-Reply-To: <20181116005008.7243-1-lyude@redhat.com> References: <20181116005008.7243-1-lyude@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Fri, 16 Nov 2018 00:50:21 +0000 (UTC) Subject: [Intel-gfx] [PATCH v6 2/6] drm/dp_mst: Return kref_put() result from drm_dp_put_port() X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP This will let us warn if we end up freeing a port when we're not expecting to, which will make reporting erroneous usage of the new MST VCPI helpers a little easier. Signed-off-by: Lyude Paul Cc: Daniel Vetter --- drivers/gpu/drm/drm_dp_mst_topology.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 529414556962..00fbe7a2699d 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -45,7 +45,7 @@ static bool dump_dp_payload_table(struct drm_dp_mst_topology_mgr *mgr, char *buf); static int test_calc_pbn_mode(void); -static void drm_dp_put_port(struct drm_dp_mst_port *port); +static int drm_dp_put_port(struct drm_dp_mst_port *port); static int drm_dp_dpcd_write_payload(struct drm_dp_mst_topology_mgr *mgr, int id, @@ -969,9 +969,9 @@ static void drm_dp_destroy_port(struct kref *kref) kfree(port); } -static void drm_dp_put_port(struct drm_dp_mst_port *port) +static int drm_dp_put_port(struct drm_dp_mst_port *port) { - kref_put(&port->kref, drm_dp_destroy_port); + return kref_put(&port->kref, drm_dp_destroy_port); } static struct drm_dp_mst_branch *drm_dp_mst_get_validated_mstb_ref_locked(struct drm_dp_mst_branch *mstb, struct drm_dp_mst_branch *to_find) From patchwork Fri Nov 16 00:50:05 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lyude Paul X-Patchwork-Id: 10685363 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D719F14E2 for ; Fri, 16 Nov 2018 00:50:38 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C4E042D3E2 for ; Fri, 16 Nov 2018 00:50:38 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B8B322D446; Fri, 16 Nov 2018 00:50:38 +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=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 79D152D3E2 for ; Fri, 16 Nov 2018 00:50:37 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 20E496E6AD; Fri, 16 Nov 2018 00:50:24 +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 A09036E63D; Fri, 16 Nov 2018 00:50:22 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2738C307DAAD; Fri, 16 Nov 2018 00:50:22 +0000 (UTC) Received: from malachite.bss.redhat.com (dhcp-10-20-1-11.bss.redhat.com [10.20.1.11]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7200417B18; Fri, 16 Nov 2018 00:50:21 +0000 (UTC) From: Lyude Paul To: intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org Date: Thu, 15 Nov 2018 19:50:05 -0500 Message-Id: <20181116005008.7243-4-lyude@redhat.com> In-Reply-To: <20181116005008.7243-1-lyude@redhat.com> References: <20181116005008.7243-1-lyude@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.42]); Fri, 16 Nov 2018 00:50:22 +0000 (UTC) Subject: [Intel-gfx] [PATCH v6 3/6] drm/dp_mst: Start tracking per-port VCPI allocations X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Daniel Vetter Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP There has been a TODO waiting for quite a long time in drm_dp_mst_topology.c: /* We cannot rely on port->vcpi.num_slots to update * topology_state->avail_slots as the port may not exist if the parent * branch device was unplugged. This should be fixed by tracking * per-port slot allocation in drm_dp_mst_topology_state instead of * depending on the caller to tell us how many slots to release. */ That's not the only reason we should fix this: forcing the driver to track the VCPI allocations throughout a state's atomic check is error prone, because it means that extra care has to be taken with the order that drm_dp_atomic_find_vcpi_slots() and drm_dp_atomic_release_vcpi_slots() are called in in order to ensure idempotency. Currently the only driver actually using these helpers, i915, doesn't even do this correctly: multiple ->best_encoder() checks with i915's current implementation would not be idempotent and would over-allocate VCPI slots, something I learned trying to implement fallback retraining in MST. So: simplify this whole mess, and teach drm_dp_atomic_find_vcpi_slots() and drm_dp_atomic_release_vcpi_slots() to track the VCPI allocations for each port. This allows us to ensure idempotency without having to rely on the driver as much. Additionally: the driver doesn't need to do any kind of VCPI slot tracking anymore if it doesn't need it for it's own internal state. Additionally; this adds a new drm_dp_mst_atomic_check() helper which must be used by atomic drivers to perform validity checks for the new VCPI allocations incurred by a state. Also: update the documentation and make it more obvious that these /must/ be called by /all/ atomic drivers supporting MST. Changes since v6: - Keep a kref to all of the ports we have allocations on. This required a good bit of changing to when we call drm_dp_find_vcpi_slots(), mainly that we need to ensure that we only redo VCPI allocations on actual mode or CRTC changes, not crtc_state->active changes. Additionally, we no longer take the registration of the DRM connector for each port into account because so long as we have a kref to the port in the new or previous atomic state, the connector will stay registered. - Use the small changes to drm_dp_put_port() to add even more error checking to make misusage of the helpers more obvious. I added this after having to chase down various use-after-free conditions that started popping up from the new helpers so no one else has to troubleshoot that. - Move some accidental DRM_DEBUG_KMS() calls to DRM_DEBUG_ATOMIC() - Update documentation again, note that find/release() should both not be called on the same port in a single atomic check phase (but multiple calls to one or the other is OK) Changes since v4: - Don't skip the atomic checks for VCPI allocations if no new VCPI allocations happen in a state. This makes the next change I'm about to list here a lot easier to implement. - Don't ignore VCPI allocations on destroyed ports, instead ensure that when ports are destroyed and still have VCPI allocations in the topology state, the only state changes allowed are releasing said ports' VCPI. This prevents a state with a mix of VCPI allocations from destroyed ports, and allocations from valid ports. Changes since v3: - Don't release VCPI allocations in the topology state immediately in drm_dp_atomic_release_vcpi_slots(), instead mark them as 0 and skip over them in drm_dp_mst_duplicate_state(). This makes it so drm_dp_atomic_release_vcpi_slots() is still idempotent while also throwing warnings if the driver messes up it's book keeping and tries to release VCPI slots on a port that doesn't have any pre-existing VCPI allocation - danvet - Change mst_state/state in some debugging messages to "mst state" Changes since v2: - Use kmemdup() for duplicating MST state - danvet - Move port validation out of duplicate state callback - danvet - Handle looping through MST topology states in drm_dp_mst_atomic_check() so the driver doesn't have to do it - Fix documentation in drm_dp_atomic_find_vcpi_slots() - Move the atomic check for each individual topology state into it's own function, reduces indenting - Don't consider "stale" MST ports when calculating the bandwidth requirements. This is needed because originally we relied on the state duplication functions to prune any stale ports from the new state, which would prevent us from incorrectly considering their bandwidth requirements alongside legitimate new payloads. - Add function references in drm_dp_atomic_release_vcpi_slots() - danvet - Annotate atomic VCPI and atomic check functions with __must_check - danvet Changes since v1: - Don't use the now-removed ->atomic_check() for private objects hook, just give drivers a function to call themselves Signed-off-by: Lyude Paul Cc: Daniel Vetter --- drivers/gpu/drm/drm_dp_mst_topology.c | 294 +++++++++++++++++++++++--- drivers/gpu/drm/i915/intel_display.c | 4 + drivers/gpu/drm/i915/intel_dp_mst.c | 64 +++--- include/drm/drm_dp_mst_helper.h | 24 ++- 4 files changed, 319 insertions(+), 67 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 00fbe7a2699d..183d0e832ced 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -2617,21 +2617,42 @@ static int drm_dp_init_vcpi(struct drm_dp_mst_topology_mgr *mgr, } /** - * drm_dp_atomic_find_vcpi_slots() - Find and add vcpi slots to the state + * drm_dp_atomic_find_vcpi_slots() - Find and add VCPI slots to the state * @state: global atomic state * @mgr: MST topology manager for the port * @port: port to find vcpi slots for * @pbn: bandwidth required for the mode in PBN * - * RETURNS: - * Total slots in the atomic state assigned for this port or error + * Allocates VCPI slots to @port, replacing any previous VCPI allocations it + * may have had. Any atomic drivers which support MST must call this function + * in their &drm_encoder_helper_funcs.atomic_check() callback to change the + * current VCPI allocation for the new state, but only when + * &drm_crtc_state.mode_changed or &drm_crtc_state.connectors_changed is set + * to ensure compatibility with userspace applications that still use the + * legacy modesetting UAPI. + * + * Allocations set by this function are not checked against the bandwidth + * restraints of @mgr until the driver calls drm_dp_mst_atomic_check(). + * + * Additionally, it is OK to call this function multiple times on the same + * @port as needed. It is not OK however, to call this function and + * drm_dp_atomic_release_vcpi_slots() in the same atomic check phase. + * + * See also: + * drm_dp_atomic_release_vcpi_slots() + * drm_dp_mst_atomic_check() + * + * Returns: + * Total slots in the atomic state assigned for this port, or a negative error + * code if the port no longer exists */ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, int pbn) { struct drm_dp_mst_topology_state *topology_state; - int req_slots; + struct drm_dp_vcpi_allocation *pos, *vcpi = NULL; + int prev_slots, req_slots, ret; topology_state = drm_atomic_get_mst_topology_state(state, mgr); if (IS_ERR(topology_state)) @@ -2640,20 +2661,60 @@ int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, port = drm_dp_get_validated_port_ref(mgr, port); if (port == NULL) return -EINVAL; - req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); - DRM_DEBUG_KMS("vcpi slots req=%d, avail=%d\n", - req_slots, topology_state->avail_slots); - if (req_slots > topology_state->avail_slots) { - drm_dp_put_port(port); - return -ENOSPC; + topology_state->vcpi_allocated = true; + + /* Find the current allocation for this port, if any */ + list_for_each_entry(pos, &topology_state->vcpis, next) { + if (pos->port == port) { + vcpi = pos; + prev_slots = vcpi->vcpi; + + /* + * This should never happen, unless the driver tries + * releasing and allocating the same VCPI allocation, + * which is an error + */ + if (WARN_ON(!prev_slots)) { + DRM_ERROR("cannot allocate and release VCPI on [MST PORT:%p] in the same state\n", + port); + return -EINVAL; + } + + break; + } } + if (!vcpi) + prev_slots = 0; - topology_state->avail_slots -= req_slots; - DRM_DEBUG_KMS("vcpi slots avail=%d", topology_state->avail_slots); + req_slots = DIV_ROUND_UP(pbn, mgr->pbn_div); + + DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] [MST PORT:%p] VCPI %d -> %d\n", + port->connector->base.id, port->connector->name, + port, prev_slots, req_slots); + + /* Add the new allocation to the state */ + if (!vcpi) { + vcpi = kzalloc(sizeof(*vcpi), GFP_KERNEL); + if (!vcpi) { + ret = -ENOMEM; + goto out; + } + vcpi->port = drm_dp_get_validated_port_ref(mgr, port); + if (!vcpi->port) { + ret = -EINVAL; + kfree(vcpi); + goto out; + } + list_add(&vcpi->next, &topology_state->vcpis); + } + vcpi->vcpi = req_slots; + + ret = req_slots; +out: drm_dp_put_port(port); - return req_slots; + return ret; } EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); @@ -2661,31 +2722,66 @@ EXPORT_SYMBOL(drm_dp_atomic_find_vcpi_slots); * drm_dp_atomic_release_vcpi_slots() - Release allocated vcpi slots * @state: global atomic state * @mgr: MST topology manager for the port - * @slots: number of vcpi slots to release + * @port: The port to release the VCPI slots from * - * RETURNS: - * 0 if @slots were added back to &drm_dp_mst_topology_state->avail_slots or - * negative error code + * Releases any VCPI slots that have been allocated to a port in the atomic + * state. Any atomic drivers which support MST must call this function in + * their &drm_connector_helper_funcs.atomic_check() callback when the + * connector will no longer have VCPI allocated (e.g. because it's CRTC was + * removed) when it had VCPI allocated in the previous atomic state. + * + * It is OK to call this even if @port has been removed from the system. + * Additionally, it is OK to call this function multiple times on the same + * @port as needed. It is not OK however, to call this function and + * drm_dp_atomic_find_vcpi_slots() on the same @port in a single atomic check + * phase. + * + * See also: + * drm_dp_atomic_find_vcpi_slots() + * drm_dp_mst_atomic_check() + * + * Returns: + * 0 if all slots for this port were added back to + * &drm_dp_mst_topology_state.avail_slots or negative error code */ int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr, - int slots) + struct drm_dp_mst_port *port) { struct drm_dp_mst_topology_state *topology_state; + struct drm_dp_vcpi_allocation *pos; + bool found = false; topology_state = drm_atomic_get_mst_topology_state(state, mgr); if (IS_ERR(topology_state)) return PTR_ERR(topology_state); - /* We cannot rely on port->vcpi.num_slots to update - * topology_state->avail_slots as the port may not exist if the parent - * branch device was unplugged. This should be fixed by tracking - * per-port slot allocation in drm_dp_mst_topology_state instead of - * depending on the caller to tell us how many slots to release. - */ - topology_state->avail_slots += slots; - DRM_DEBUG_KMS("vcpi slots released=%d, avail=%d\n", - slots, topology_state->avail_slots); + list_for_each_entry(pos, &topology_state->vcpis, next) { + if (pos->port == port) { + found = true; + break; + } + } + if (WARN_ON(!found)) { + DRM_ERROR("no VCPI for [MST PORT:%p] found in mst state %p\n", + port, &topology_state->base); + return -EINVAL; + } + + DRM_DEBUG_ATOMIC("[MST PORT:%p] VCPI %d -> 0\n", port, pos->vcpi); + if (pos->vcpi) { + /* + * This should be safe-as the previous state will still hold a + * reference to this port until we swap states. If it's not, + * the driver has a bookkeeping error + */ + if (WARN_ON(drm_dp_put_port(port))) { + DRM_ERROR("cannot allocate and release VCPI on [MST PORT:%p] in the same state\n", + port); + return -EINVAL; + } + pos->vcpi = 0; + } return 0; } @@ -3115,15 +3211,45 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) static struct drm_private_state * drm_dp_mst_duplicate_state(struct drm_private_obj *obj) { - struct drm_dp_mst_topology_state *state; + struct drm_dp_mst_topology_state *state, *old_state = + to_dp_mst_topology_state(obj->state); + struct drm_dp_vcpi_allocation *pos, *vcpi; - state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); + state = kmemdup(old_state, sizeof(*state), GFP_KERNEL); if (!state) return NULL; __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); + INIT_LIST_HEAD(&state->vcpis); + state->vcpi_allocated = false; + + list_for_each_entry(pos, &old_state->vcpis, next) { + /* Prune leftover freed VCPI allocations */ + if (!pos->vcpi) + continue; + + vcpi = kmemdup(pos, sizeof(*vcpi), GFP_KERNEL); + if (!vcpi) + goto fail; + + /* Take a plain old kref here and don't validate the port, as + * it's topology might not even exist anymore + */ + kref_get(&vcpi->port->kref); + list_add(&vcpi->next, &state->vcpis); + } + return &state->base; + +fail: + list_for_each_entry_safe(pos, vcpi, &state->vcpis, next) { + drm_dp_put_port(pos->port); + kfree(pos); + } + kfree(state); + + return NULL; } static void drm_dp_mst_destroy_state(struct drm_private_obj *obj, @@ -3131,14 +3257,116 @@ static void drm_dp_mst_destroy_state(struct drm_private_obj *obj, { struct drm_dp_mst_topology_state *mst_state = to_dp_mst_topology_state(state); + struct drm_dp_vcpi_allocation *pos, *tmp; + + list_for_each_entry_safe(pos, tmp, &mst_state->vcpis, next) { + /* We only keep references to ports with non-zero VCPIs */ + if (pos->vcpi) + drm_dp_put_port(pos->port); + kfree(pos); + } kfree(mst_state); } -static const struct drm_private_state_funcs mst_state_funcs = { +static inline int +drm_dp_mst_atomic_check_topology_state(struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_topology_state *mst_state) +{ + struct drm_dp_vcpi_allocation *vcpi; + struct drm_dp_mst_port *port; + int avail_slots = 63, ret; + + /* There's no possible scenario where releasing VCPI or keeping it the + * same would make the state invalid + */ + if (!mst_state->vcpi_allocated) { + DRM_DEBUG_ATOMIC("[MST MGR:%p] state %p allocates no VCPI, check skipped\n", + mgr, &mst_state->base); + return 0; + } + + list_for_each_entry(vcpi, &mst_state->vcpis, next) { + /* Releasing VCPI is always OK-even if the port is gone */ + if (!vcpi->vcpi) { + DRM_DEBUG_ATOMIC("[MST PORT:%p] releases all VCPI slots\n", + vcpi->port); + continue; + } + + port = drm_dp_get_validated_port_ref(mgr, vcpi->port); + if (!port) { + DRM_DEBUG_ATOMIC("[MST PORT:%p] is gone but still has VCPI, cannot add new VCPI\n", + vcpi->port); + return -EINVAL; + } + + DRM_DEBUG_ATOMIC("[MST PORT:%p] requires %d vcpi slots\n", + vcpi->port, vcpi->vcpi); + + avail_slots -= vcpi->vcpi; + if (avail_slots < 0) { + DRM_DEBUG_ATOMIC("[MST PORT:%p] not enough VCPI slots in mst state %p (avail=%d)\n", + vcpi->port, mst_state, + avail_slots + vcpi->vcpi); + ret = -ENOSPC; + goto port_fail; + } + + drm_dp_put_port(port); + } + DRM_DEBUG_ATOMIC("[MST MGR:%p] mst state %p VCPI avail=%d used=%d\n", + mgr, mst_state, avail_slots, + 63 - avail_slots); + + return 0; +port_fail: + drm_dp_put_port(port); + return ret; +} + +/** + * drm_dp_mst_atomic_check - Check that the new state of an MST topology in an + * atomic update is valid + * @state: Pointer to the new &struct drm_dp_mst_topology_state + * + * Checks the given topology state for an atomic update to ensure that it's + * valid. This includes checking whether there's enough bandwidth to support + * the new VCPI allocations in the atomic update. + * + * Any atomic drivers supporting DP MST must make sure to call this after + * checking the rest of their state in their + * &drm_mode_config_funcs.atomic_check() callback. + * + * See also: + * drm_dp_atomic_find_vcpi_slots() + * drm_dp_atomic_release_vcpi_slots() + * + * Returns: + * + * 0 if the new state is valid, negative error code otherwise. + */ +int drm_dp_mst_atomic_check(struct drm_atomic_state *state) +{ + struct drm_dp_mst_topology_mgr *mgr; + struct drm_dp_mst_topology_state *mst_state; + int i, ret = 0; + + for_each_new_mst_mgr_in_state(state, mgr, mst_state, i) { + ret = drm_dp_mst_atomic_check_topology_state(mgr, mst_state); + if (ret) + break; + } + + return ret; +} +EXPORT_SYMBOL(drm_dp_mst_atomic_check); + +const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs = { .atomic_duplicate_state = drm_dp_mst_duplicate_state, .atomic_destroy_state = drm_dp_mst_destroy_state, }; +EXPORT_SYMBOL(drm_dp_mst_topology_state_funcs); /** * drm_atomic_get_mst_topology_state: get MST topology state @@ -3216,13 +3444,11 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, return -ENOMEM; mst_state->mgr = mgr; - - /* max. time slots - one slot for MTP header */ - mst_state->avail_slots = 63; + INIT_LIST_HEAD(&mst_state->vcpis); drm_atomic_private_obj_init(&mgr->base, &mst_state->base, - &mst_state_funcs); + &drm_dp_mst_topology_state_funcs); return 0; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 132e978227fb..8e85e04a5948 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12592,6 +12592,10 @@ static int intel_atomic_check(struct drm_device *dev, "[modeset]" : "[fastset]"); } + ret = drm_dp_mst_atomic_check(state); + if (ret) + return ret; + if (any_ms) { ret = intel_modeset_checks(state); diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 4de247ddf05f..be2d1ac7d87d 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -41,8 +41,13 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, struct drm_connector *connector = conn_state->connector; void *port = to_intel_connector(connector)->port; struct drm_atomic_state *state = pipe_config->base.state; + struct drm_crtc *crtc = pipe_config->base.crtc; + struct drm_crtc_state *old_crtc_state = + drm_atomic_get_old_crtc_state(state, crtc); + struct drm_crtc_state *new_crtc_state = &pipe_config->base; int bpp; - int lane_count, slots = 0; + int lane_count, slots = + to_intel_crtc_state(old_crtc_state)->dp_m_n.tu; const struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; int mst_pbn; bool constant_n = drm_dp_has_quirk(&intel_dp->desc, @@ -77,8 +82,12 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, mst_pbn = drm_dp_calc_pbn_mode(adjusted_mode->crtc_clock, bpp); pipe_config->pbn = mst_pbn; - /* Zombie connectors can't have VCPI slots */ - if (!drm_connector_is_unregistered(connector)) { + /* Only change VCPI allocation on actual mode changes, to prevent us + * from trying to allocate VCPI to ports that no longer exist when we + * may just be trying to disable DPMS on them + */ + if (new_crtc_state->mode_changed || + new_crtc_state->connectors_changed) { slots = drm_dp_atomic_find_vcpi_slots(state, &intel_dp->mst_mgr, port, @@ -107,36 +116,39 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, return true; } -static int intel_dp_mst_atomic_check(struct drm_connector *connector, - struct drm_connector_state *new_conn_state) +static int +intel_dp_mst_atomic_check(struct drm_connector *connector, + struct drm_connector_state *new_conn_state) { + struct intel_connector *intel_connector = + to_intel_connector(connector); + struct drm_dp_mst_topology_mgr *mgr = + &intel_connector->mst_port->mst_mgr; + struct drm_dp_mst_port *port = intel_connector->port; struct drm_atomic_state *state = new_conn_state->state; - struct drm_connector_state *old_conn_state; - struct drm_crtc *old_crtc; - struct drm_crtc_state *crtc_state; - int slots, ret = 0; + struct drm_connector_state *old_conn_state = + drm_atomic_get_old_connector_state(state, connector); + struct drm_crtc *old_crtc = old_conn_state->crtc, + *new_crtc = new_conn_state->crtc; + struct drm_crtc_state *old_crtc_state, *new_crtc_state; - old_conn_state = drm_atomic_get_old_connector_state(state, connector); - old_crtc = old_conn_state->crtc; if (!old_crtc) - return ret; + return 0; - crtc_state = drm_atomic_get_new_crtc_state(state, old_crtc); - slots = to_intel_crtc_state(crtc_state)->dp_m_n.tu; - if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) { - struct drm_dp_mst_topology_mgr *mgr; - struct drm_encoder *old_encoder; + old_crtc_state = drm_atomic_get_old_crtc_state(state, old_crtc); + if (!old_crtc_state || + !to_intel_crtc_state(old_crtc_state)->dp_m_n.tu) + return 0; - old_encoder = old_conn_state->best_encoder; - mgr = &enc_to_mst(old_encoder)->primary->dp.mst_mgr; + /* If we switched CRTCs, clear the previous one's allocation */ + new_crtc_state = drm_atomic_get_new_crtc_state(state, old_crtc); + if (new_crtc_state->connectors_changed && !new_crtc_state->enable) + to_intel_crtc_state(new_crtc_state)->dp_m_n.tu = 0; - ret = drm_dp_atomic_release_vcpi_slots(state, mgr, slots); - if (ret) - DRM_DEBUG_KMS("failed releasing %d vcpi slots:%d\n", slots, ret); - else - to_intel_crtc_state(crtc_state)->dp_m_n.tu = 0; - } - return ret; + if (new_crtc) + return 0; + + return drm_dp_atomic_release_vcpi_slots(state, mgr, port); } static void intel_mst_disable_dp(struct intel_encoder *encoder, diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h index 3faceb66f5cb..2392e12b6bce 100644 --- a/include/drm/drm_dp_mst_helper.h +++ b/include/drm/drm_dp_mst_helper.h @@ -406,9 +406,16 @@ struct drm_dp_payload { #define to_dp_mst_topology_state(x) container_of(x, struct drm_dp_mst_topology_state, base) +struct drm_dp_vcpi_allocation { + struct drm_dp_mst_port *port; + int vcpi; + struct list_head next; +}; + struct drm_dp_mst_topology_state { struct drm_private_state base; - int avail_slots; + struct list_head vcpis; + u8 vcpi_allocated; struct drm_dp_mst_topology_mgr *mgr; }; @@ -619,14 +626,17 @@ void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr); int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr); struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state, struct drm_dp_mst_topology_mgr *mgr); -int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, - struct drm_dp_mst_topology_mgr *mgr, - struct drm_dp_mst_port *port, int pbn); -int drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, - struct drm_dp_mst_topology_mgr *mgr, - int slots); +int __must_check +drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port, int pbn); +int __must_check +drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state, + struct drm_dp_mst_topology_mgr *mgr, + struct drm_dp_mst_port *port); int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port, bool power_up); +int __must_check drm_dp_mst_atomic_check(struct drm_atomic_state *state); extern const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs; From patchwork Fri Nov 16 00:50:06 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lyude Paul X-Patchwork-Id: 10685365 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4F03114D6 for ; Fri, 16 Nov 2018 00:50:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4139B2D3E2 for ; Fri, 16 Nov 2018 00:50:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 359292D446; Fri, 16 Nov 2018 00:50:39 +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=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id EE2A72D3E2 for ; Fri, 16 Nov 2018 00:50:38 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id A374F6E63D; Fri, 16 Nov 2018 00:50:24 +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 3637F6E63D; Fri, 16 Nov 2018 00:50:23 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C853A81129; Fri, 16 Nov 2018 00:50:22 +0000 (UTC) Received: from malachite.bss.redhat.com (dhcp-10-20-1-11.bss.redhat.com [10.20.1.11]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4809B17B18; Fri, 16 Nov 2018 00:50:22 +0000 (UTC) From: Lyude Paul To: intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org Date: Thu, 15 Nov 2018 19:50:06 -0500 Message-Id: <20181116005008.7243-5-lyude@redhat.com> In-Reply-To: <20181116005008.7243-1-lyude@redhat.com> References: <20181116005008.7243-1-lyude@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Fri, 16 Nov 2018 00:50:22 +0000 (UTC) Subject: [Intel-gfx] [PATCH v6 4/6] drm/dp_mst: Check payload count in drm_dp_mst_atomic_check() X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP It occurred to me that we never actually check this! So let's start doing that. Signed-off-by: Lyude Paul Reviewed-by: Daniel Vetter --- drivers/gpu/drm/drm_dp_mst_topology.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 183d0e832ced..38654a449b82 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -3275,7 +3275,7 @@ drm_dp_mst_atomic_check_topology_state(struct drm_dp_mst_topology_mgr *mgr, { struct drm_dp_vcpi_allocation *vcpi; struct drm_dp_mst_port *port; - int avail_slots = 63, ret; + int avail_slots = 63, payload_count = 0, ret; /* There's no possible scenario where releasing VCPI or keeping it the * same would make the state invalid @@ -3313,6 +3313,13 @@ drm_dp_mst_atomic_check_topology_state(struct drm_dp_mst_topology_mgr *mgr, goto port_fail; } + if (++payload_count > mgr->max_payloads) { + DRM_DEBUG_ATOMIC("[MST MGR:%p] state %p has too many payloads (max=%d)\n", + mgr, mst_state, mgr->max_payloads); + ret = -EINVAL; + goto port_fail; + } + drm_dp_put_port(port); } DRM_DEBUG_ATOMIC("[MST MGR:%p] mst state %p VCPI avail=%d used=%d\n", From patchwork Fri Nov 16 00:50:07 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lyude Paul X-Patchwork-Id: 10685377 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4E25614D6 for ; Fri, 16 Nov 2018 00:50:47 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 406E22D3E2 for ; Fri, 16 Nov 2018 00:50:47 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 34FDC2D446; Fri, 16 Nov 2018 00:50:47 +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=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=unavailable version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id E402B2D3E2 for ; Fri, 16 Nov 2018 00:50:46 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id A2D676E6B4; Fri, 16 Nov 2018 00:50:28 +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 008396E63D; Fri, 16 Nov 2018 00:50:23 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8EE015D697; Fri, 16 Nov 2018 00:50:23 +0000 (UTC) Received: from malachite.bss.redhat.com (dhcp-10-20-1-11.bss.redhat.com [10.20.1.11]) by smtp.corp.redhat.com (Postfix) with ESMTP id EAA1017B18; Fri, 16 Nov 2018 00:50:22 +0000 (UTC) From: Lyude Paul To: intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org Date: Thu, 15 Nov 2018 19:50:07 -0500 Message-Id: <20181116005008.7243-6-lyude@redhat.com> In-Reply-To: <20181116005008.7243-1-lyude@redhat.com> References: <20181116005008.7243-1-lyude@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Fri, 16 Nov 2018 00:50:23 +0000 (UTC) Subject: [Intel-gfx] [PATCH v6 5/6] drm/nouveau: Stop unsetting mstc->port, check connector registration X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP Same thing we did in i915, but for nouveau now. Signed-off-by: Lyude Paul Cc: Daniel Vetter --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 6cbbae3f438b..f216fd4207c9 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -698,8 +698,10 @@ nv50_msto_cleanup(struct nv50_msto *msto) struct nv50_mstm *mstm = mstc->mstm; NV_ATOMIC(drm, "%s: msto cleanup\n", msto->encoder.name); - if (mstc->port && mstc->port->vcpi.vcpi > 0 && !nv50_msto_payload(msto)) + if (!drm_connector_is_unregistered(&mstc->connector) && + mstc->port->vcpi.vcpi > 0 && !nv50_msto_payload(msto)) drm_dp_mst_deallocate_vcpi(&mstm->mgr, mstc->port); + if (msto->disabled) { msto->mstc = NULL; msto->head = NULL; @@ -725,7 +727,8 @@ nv50_msto_prepare(struct nv50_msto *msto) }; NV_ATOMIC(drm, "%s: msto prepare\n", msto->encoder.name); - if (mstc->port && mstc->port->vcpi.vcpi > 0) { + if (!drm_connector_is_unregistered(&mstc->connector) && + mstc->port->vcpi.vcpi > 0) { struct drm_dp_payload *payload = nv50_msto_payload(msto); if (payload) { args.vcpi.start_slot = payload->start_slot; @@ -822,7 +825,7 @@ nv50_msto_disable(struct drm_encoder *encoder) struct nv50_mstc *mstc = msto->mstc; struct nv50_mstm *mstm = mstc->mstm; - if (mstc->port) + if (!drm_connector_is_unregistered(&mstc->connector)) drm_dp_mst_reset_vcpi_slots(&mstm->mgr, mstc->port); mstm->outp->update(mstm->outp, msto->head->base.index, NULL, 0, 0); @@ -935,7 +938,7 @@ nv50_mstc_detect(struct drm_connector *connector, bool force) enum drm_connector_status conn_status; int ret; - if (!mstc->port) + if (drm_connector_is_unregistered(&mstc->connector)) return connector_status_disconnected; ret = pm_runtime_get_sync(connector->dev->dev); @@ -1073,10 +1076,6 @@ nv50_mstm_destroy_connector(struct drm_dp_mst_topology_mgr *mgr, drm_fb_helper_remove_one_connector(&drm->fbcon->helper, &mstc->connector); - drm_modeset_lock(&drm->dev->mode_config.connection_mutex, NULL); - mstc->port = NULL; - drm_modeset_unlock(&drm->dev->mode_config.connection_mutex); - drm_connector_put(&mstc->connector); } From patchwork Fri Nov 16 00:50:08 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lyude Paul X-Patchwork-Id: 10685367 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id E9E0217F3 for ; Fri, 16 Nov 2018 00:50:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DC0152D3E2 for ; Fri, 16 Nov 2018 00:50:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D01B32D446; Fri, 16 Nov 2018 00:50:39 +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=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 78A242D3E2 for ; Fri, 16 Nov 2018 00:50:39 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 1FE556E6AE; Fri, 16 Nov 2018 00:50:25 +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 B89966E6A8; Fri, 16 Nov 2018 00:50:24 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 53082C049DC1; Fri, 16 Nov 2018 00:50:24 +0000 (UTC) Received: from malachite.bss.redhat.com (dhcp-10-20-1-11.bss.redhat.com [10.20.1.11]) by smtp.corp.redhat.com (Postfix) with ESMTP id AE99F17B18; Fri, 16 Nov 2018 00:50:23 +0000 (UTC) From: Lyude Paul To: intel-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org, nouveau@lists.freedesktop.org Date: Thu, 15 Nov 2018 19:50:08 -0500 Message-Id: <20181116005008.7243-7-lyude@redhat.com> In-Reply-To: <20181116005008.7243-1-lyude@redhat.com> References: <20181116005008.7243-1-lyude@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Fri, 16 Nov 2018 00:50:24 +0000 (UTC) Subject: [Intel-gfx] [PATCH v6 6/6] drm/nouveau: Use atomic VCPI helpers for MST X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Daniel Vetter Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Virus-Scanned: ClamAV using ClamSMTP Currently, nouveau uses the yolo method of setting up MST displays: it uses the old VCPI helpers (drm_dp_find_vcpi_slots()) for computing the display configuration. These helpers don't take care to make sure they take a reference to the mstb port that they're checking, and additionally don't actually check whether or not the topology still has enough bandwidth to provide the VCPI tokens required. So, drop usage of the old helpers and move entirely over to the atomic helpers. Changes since v5: - Update nv50_msto_atomic_check() and nv50_mstc_atomic_check() to the new requirements for drm_dp_atomic_find_vcpi_slots() and drm_dp_atomic_release_vcpi_slots() Signed-off-by: Lyude Paul Cc: Daniel Vetter --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 52 ++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index f216fd4207c9..83cb1afb94ed 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -750,16 +750,22 @@ nv50_msto_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, struct drm_connector_state *conn_state) { - struct nv50_mstc *mstc = nv50_mstc(conn_state->connector); + struct drm_atomic_state *state = crtc_state->state; + struct drm_connector *connector = conn_state->connector; + struct nv50_mstc *mstc = nv50_mstc(connector); struct nv50_mstm *mstm = mstc->mstm; - int bpp = conn_state->connector->display_info.bpc * 3; + int bpp = connector->display_info.bpc * 3; int slots; - mstc->pbn = drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock, bpp); + mstc->pbn = drm_dp_calc_pbn_mode(crtc_state->adjusted_mode.clock, + bpp); - slots = drm_dp_find_vcpi_slots(&mstm->mgr, mstc->pbn); - if (slots < 0) - return slots; + if (crtc_state->connectors_changed || crtc_state->mode_changed) { + slots = drm_dp_atomic_find_vcpi_slots(state, &mstm->mgr, + mstc->port, mstc->pbn); + if (slots < 0) + return slots; + } return nv50_outp_atomic_check_view(encoder, crtc_state, conn_state, mstc->native); @@ -923,12 +929,42 @@ nv50_mstc_get_modes(struct drm_connector *connector) return ret; } +static int +nv50_mstc_atomic_check(struct drm_connector *connector, + struct drm_connector_state *new_conn_state) +{ + struct drm_atomic_state *state = new_conn_state->state; + struct nv50_mstc *mstc = nv50_mstc(connector); + struct drm_dp_mst_topology_mgr *mgr = &mstc->mstm->mgr; + struct drm_connector_state *old_conn_state = + drm_atomic_get_old_connector_state(state, connector); + struct drm_crtc_state *old_crtc_state; + struct drm_crtc *new_crtc = new_conn_state->crtc, + *old_crtc = old_conn_state->crtc; + + if (!old_crtc) + return 0; + + old_crtc_state = drm_atomic_get_old_crtc_state(state, old_crtc); + if (!old_crtc_state || !old_crtc_state->enable) + return 0; + + if (new_crtc) + return 0; + + /* This connector will be left without an enabled CRTC, so its VCPI + * must be released here + */ + return drm_dp_atomic_release_vcpi_slots(state, mgr, mstc->port); +} + static const struct drm_connector_helper_funcs nv50_mstc_help = { .get_modes = nv50_mstc_get_modes, .mode_valid = nv50_mstc_mode_valid, .best_encoder = nv50_mstc_best_encoder, .atomic_best_encoder = nv50_mstc_atomic_best_encoder, + .atomic_check = nv50_mstc_atomic_check, }; static enum drm_connector_status @@ -2108,6 +2144,10 @@ nv50_disp_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) return ret; } + ret = drm_dp_mst_atomic_check(state); + if (ret) + return ret; + return 0; }