Received: by 2002:ac0:a582:0:0:0:0:0 with SMTP id m2-v6csp297897imm; Tue, 16 Oct 2018 23:41:31 -0700 (PDT) X-Google-Smtp-Source: ACcGV61491/Xc9kWOmjWMF5PIRwYnXceGdqqrwJu3oauapYZh9phMlyjFzC02hgV0VIHq+IPwRxR X-Received: by 2002:a63:4658:: with SMTP id v24-v6mr23727294pgk.425.1539758491486; Tue, 16 Oct 2018 23:41:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1539758491; cv=none; d=google.com; s=arc-20160816; b=CLJj9zZUYNmH8MoWvlKUz/s00iQEigLlMtJeF8OTeGHBt1oiE1lNElsEDfmXKS5+Rj dY39YdaVaDkhR8dFDOXpMtR8OW0DX3x3a8kAAah1JhEMThhqjgdoL85pyqrbN0ZPYuVx NZeol1LPmjhejpNw8FWTwnBjnkT68/4PXhG5blh5kxA9SpwLUh/shO0EE9kLRwNo1iHv d4cCMNy2cbcbbnyL3kdFenV27pAP4LJz54WoGS/iDPUfrNGkxA7GpMktNGepnpQNTji+ 0R7Mqhul6rLdOqJf5kvK2eKl/HADPWrtSHB7c28Aeu1b/IvCU4O8dbx+3buVbeAuWWwk 3azQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:user-agent:in-reply-to :content-transfer-encoding:content-disposition:mime-version :references:mail-followup-to:message-id:subject:cc:to:from:date :dkim-signature; bh=ZE44Vs2Xsv1UiXPUv9XNOF3fcKeVMqV/Ggk3CQFOANQ=; b=XY3eR59dxD4BGqEBHVCSNeAZRfZx7PifoiiEoDVaLnzeBQiEr3A5s2ZTaa1e0TV4AG cEkdeGQPuX3C9rtsXsdz0QOXZBKw+eb348KBkkq3muNbpvMBil75cNc+08jPF0gc764+ aTT4fUSCrFZnlauuz8S37XYduSY/RF9fmXe140vv7deL7yqGXLy1TkNFt7CIrTq6QO/T iDloQ5q7LKiI8SHIa794LPVNmuLSphfs6+/OasLS46Ee90bGXNDplNHCeCL+Z3/sEA3p MHMf1ZsQ1v1u87xT7ur5f/hGJ5HEH1d1bYnZfjeFWNLS7+QiAxZiMf2yF8rxFEWVsoEL 49Eg== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@ffwll.ch header.s=google header.b=liEqHgd+; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j16-v6si15995744pgg.350.2018.10.16.23.41.14; Tue, 16 Oct 2018 23:41:31 -0700 (PDT) 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; dkim=fail header.i=@ffwll.ch header.s=google header.b=liEqHgd+; 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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727409AbeJQOdO (ORCPT + 99 others); Wed, 17 Oct 2018 10:33:14 -0400 Received: from mail-ed1-f67.google.com ([209.85.208.67]:39135 "EHLO mail-ed1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727368AbeJQOdO (ORCPT ); Wed, 17 Oct 2018 10:33:14 -0400 Received: by mail-ed1-f67.google.com with SMTP id d15-v6so23727522edq.6 for ; Tue, 16 Oct 2018 23:39:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ffwll.ch; s=google; h=sender:date:from:to:cc:subject:message-id:mail-followup-to :references:mime-version:content-disposition :content-transfer-encoding:in-reply-to:user-agent; bh=ZE44Vs2Xsv1UiXPUv9XNOF3fcKeVMqV/Ggk3CQFOANQ=; b=liEqHgd+nB9v2zq8nQcIrTcVYA31Nwl3gEZ5RMBzDuBQzAEJJ+FUn6K1yBLLc2aqF8 WviC+9DrnnNIZUIUQu+Jh/9DjX7U93h577uJtiPHScO1WS77EA3gOhciELd3vWVv386Z celaDNHTr11fuEMo8cFkwBWQmF4HKPbv+T2m4= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:from:to:cc:subject:message-id :mail-followup-to:references:mime-version:content-disposition :content-transfer-encoding:in-reply-to:user-agent; bh=ZE44Vs2Xsv1UiXPUv9XNOF3fcKeVMqV/Ggk3CQFOANQ=; b=PutuNoBIwWNDkbmxScQxdY1dEmqC2FxxiH7YbsluFkzrlkLbzxDLuF78YUAcQux/YE YWY6FOs56XSt4XhZAbtZSJbTOjYiAK6NXP0ai90mJqOf7EL4fKsDCv+4mGLc1NppZGv5 znx5ErBTn1eDsLV6q7dDYn/JJcVVcTP0ZFhLWigo0gsYXL508Qzbr5jpvk8XjvhUEhMX n+OoW+dyH+gQ62n1keK0mIxanNZ/BG4vqmuczqArWlOeMDFhl1YkX6+HtONi0UXWBGrp oGxZrS3AiXJEk54MjXzMHLOSLl1TZ0gwsomzQYKwbFcEs49vxJI1/mOij1/RUfoc1IXP IBQQ== X-Gm-Message-State: ABuFfoiJN2+mchJUE/a9dIlCqqZbt0NUQqKwb4wMAWoW81tN5QsPp+6U OhDWEqd5Beuk/kSbaajp/k0tDA== X-Received: by 2002:a50:b4eb:: with SMTP id x40-v6mr35342813edd.12.1539758343350; Tue, 16 Oct 2018 23:39:03 -0700 (PDT) Received: from phenom.ffwll.local ([2a02:168:569e:0:3106:d637:d723:e855]) by smtp.gmail.com with ESMTPSA id a27-v6sm6863490edc.46.2018.10.16.23.39.02 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 16 Oct 2018 23:39:02 -0700 (PDT) Date: Wed, 17 Oct 2018 08:39:00 +0200 From: Daniel Vetter To: Lyude Paul Cc: intel-gfx@lists.freedesktop.org, Ville =?iso-8859-1?Q?Syrj=E4l=E4?= , Daniel Vetter , Rodrigo Vivi , stable@vger.kernel.org, David Airlie , Maarten Lankhorst , Maxime Ripard , Sean Paul , Jani Nikula , Joonas Lahtinen , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org Subject: Re: [PATCH v2] drm/atomic_helper: Stop modesets on unregistered connectors harder Message-ID: <20181017063900.GF31561@phenom.ffwll.local> Mail-Followup-To: Lyude Paul , intel-gfx@lists.freedesktop.org, Ville =?iso-8859-1?Q?Syrj=E4l=E4?= , Rodrigo Vivi , stable@vger.kernel.org, David Airlie , Maarten Lankhorst , Maxime Ripard , Sean Paul , Jani Nikula , Joonas Lahtinen , dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org References: <20181016203946.9601-1-lyude@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <20181016203946.9601-1-lyude@redhat.com> X-Operating-System: Linux phenom 4.14.0-1-amd64 User-Agent: Mutt/1.10.1 (2018-07-13) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Tue, Oct 16, 2018 at 04:39:46PM -0400, Lyude Paul wrote: > Unfortunately, it appears our fix in: > commit b5d29843d8ef ("drm/atomic_helper: Allow DPMS On<->Off changes > for unregistered connectors") > > Which attempted to work around the problems introduced by: > commit 4d80273976bf ("drm/atomic_helper: Disallow new modesets on > unregistered connectors") > > Is still not the right solution, as modesets can still be triggered > outside of drm_atomic_set_crtc_for_connector(). > > So in order to fix this, while still being careful that we don't break > modesets that a driver may perform before being registered with > userspace, we replace connector->registered with a tristate member, > connector->registration_state. This allows us to keep track of whether > or not a connector is still initializing and hasn't been exposed to > userspace, is currently registered and exposed to userspace, or has been > legitimately removed from the system after having once been present. > > Using this info, we can prevent userspace from performing new modesets > on unregistered connectors while still allowing the driver to perform > modesets on unregistered connectors before the driver has finished being > registered. > > Changes since v1: > - Fix WARN_ON() in drm_connector_cleanup() that CI caught with this > patchset in igt@drv_module_reload@basic-reload-inject and > igt@drv_module_reload@basic-reload by checking if the connector is > registered instead of unregistered, as calling drm_connector_cleanup() > on a connector that hasn't been registered with userspace yet should > stay valid. > - Remove unregistered_connector_check(), and just go back to what we > were doing before in commit 4d80273976bf ("drm/atomic_helper: Disallow > new modesets on unregistered connectors") except replacing > READ_ONCE(connector->registered) with drm_connector_is_unregistered(). > This gets rid of the behavior of allowing DPMS On<->Off, but that should > be fine as it's more consistent with the UAPI we had before - danvet > - s/drm_connector_unregistered/drm_connector_is_unregistered/ - danvet > - Update documentation, fix some typos. > > Fixes: b5d29843d8ef ("drm/atomic_helper: Allow DPMS On<->Off changes for unregistered connectors") > Cc: Ville Syrj?l? > Cc: Daniel Vetter > Cc: Rodrigo Vivi > Cc: stable@vger.kernel.org > Cc: David Airlie > Signed-off-by: Lyude Paul Reviewed-by: Daniel Vetter > --- > drivers/gpu/drm/drm_atomic_helper.c | 21 ++++++++- > drivers/gpu/drm/drm_atomic_uapi.c | 21 --------- > drivers/gpu/drm/drm_connector.c | 11 +++-- > drivers/gpu/drm/i915/intel_dp_mst.c | 8 ++-- > include/drm/drm_connector.h | 71 ++++++++++++++++++++++++++++- > 5 files changed, 99 insertions(+), 33 deletions(-) > > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c > index 6f66777dca4b..ee6b2987a3c7 100644 > --- a/drivers/gpu/drm/drm_atomic_helper.c > +++ b/drivers/gpu/drm/drm_atomic_helper.c > @@ -319,6 +319,26 @@ update_connector_routing(struct drm_atomic_state *state, > return 0; > } > > + crtc_state = drm_atomic_get_new_crtc_state(state, > + new_connector_state->crtc); > + /* > + * For compatibility with legacy users, we want to make sure that > + * we allow DPMS On->Off modesets on unregistered connectors. Modesets > + * which would result in anything else must be considered invalid, to > + * avoid turning on new displays on dead connectors. > + * > + * Since the connector can be unregistered at any point during an > + * atomic check or commit, this is racy. But that's OK: all we care > + * about is ensuring that userspace can't do anything but shut off the > + * display on a connector that was destroyed after its been notified, > + * not before. > + */ > + if (drm_connector_is_unregistered(connector) && crtc_state->active) { > + DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] is not registered\n", > + connector->base.id, connector->name); > + return -EINVAL; > + } > + > funcs = connector->helper_private; > > if (funcs->atomic_best_encoder) > @@ -363,7 +383,6 @@ update_connector_routing(struct drm_atomic_state *state, > > set_best_encoder(state, new_connector_state, new_encoder); > > - crtc_state = drm_atomic_get_new_crtc_state(state, new_connector_state->crtc); > crtc_state->connectors_changed = true; > > DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d:%s]\n", > diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c > index a22d6f269b07..d5b7f315098c 100644 > --- a/drivers/gpu/drm/drm_atomic_uapi.c > +++ b/drivers/gpu/drm/drm_atomic_uapi.c > @@ -299,27 +299,6 @@ drm_atomic_set_crtc_for_connector(struct drm_connector_state *conn_state, > struct drm_connector *connector = conn_state->connector; > struct drm_crtc_state *crtc_state; > > - /* > - * For compatibility with legacy users, we want to make sure that > - * we allow DPMS On<->Off modesets on unregistered connectors, since > - * legacy modesetting users will not be expecting these to fail. We do > - * not however, want to allow legacy users to assign a connector > - * that's been unregistered from sysfs to another CRTC, since doing > - * this with a now non-existent connector could potentially leave us > - * in an invalid state. > - * > - * Since the connector can be unregistered at any point during an > - * atomic check or commit, this is racy. But that's OK: all we care > - * about is ensuring that userspace can't use this connector for new > - * configurations after it's been notified that the connector is no > - * longer present. > - */ > - if (!READ_ONCE(connector->registered) && crtc) { > - DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] is not registered\n", > - connector->base.id, connector->name); > - return -EINVAL; > - } > - > if (conn_state->crtc == crtc) > return 0; > > diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c > index 5d01414ec9f7..891f9458d29e 100644 > --- a/drivers/gpu/drm/drm_connector.c > +++ b/drivers/gpu/drm/drm_connector.c > @@ -396,7 +396,8 @@ void drm_connector_cleanup(struct drm_connector *connector) > /* The connector should have been removed from userspace long before > * it is finally destroyed. > */ > - if (WARN_ON(connector->registered)) > + if (WARN_ON(connector->registration_state == > + DRM_CONNECTOR_REGISTERED)) > drm_connector_unregister(connector); > > if (connector->tile_group) { > @@ -453,7 +454,7 @@ int drm_connector_register(struct drm_connector *connector) > return 0; > > mutex_lock(&connector->mutex); > - if (connector->registered) > + if (connector->registration_state != DRM_CONNECTOR_INITIALIZING) > goto unlock; > > ret = drm_sysfs_connector_add(connector); > @@ -473,7 +474,7 @@ int drm_connector_register(struct drm_connector *connector) > > drm_mode_object_register(connector->dev, &connector->base); > > - connector->registered = true; > + connector->registration_state = DRM_CONNECTOR_REGISTERED; > goto unlock; > > err_debugfs: > @@ -495,7 +496,7 @@ EXPORT_SYMBOL(drm_connector_register); > void drm_connector_unregister(struct drm_connector *connector) > { > mutex_lock(&connector->mutex); > - if (!connector->registered) { > + if (connector->registration_state != DRM_CONNECTOR_REGISTERED) { > mutex_unlock(&connector->mutex); > return; > } > @@ -506,7 +507,7 @@ void drm_connector_unregister(struct drm_connector *connector) > drm_sysfs_connector_remove(connector); > drm_debugfs_connector_remove(connector); > > - connector->registered = false; > + connector->registration_state = DRM_CONNECTOR_UNREGISTERED; > mutex_unlock(&connector->mutex); > } > EXPORT_SYMBOL(drm_connector_unregister); > diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c > index b268bdd71bd3..8b71d64ebd9d 100644 > --- a/drivers/gpu/drm/i915/intel_dp_mst.c > +++ b/drivers/gpu/drm/i915/intel_dp_mst.c > @@ -78,7 +78,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, > pipe_config->pbn = mst_pbn; > > /* Zombie connectors can't have VCPI slots */ > - if (READ_ONCE(connector->registered)) { > + if (!drm_connector_is_unregistered(connector)) { > slots = drm_dp_atomic_find_vcpi_slots(state, > &intel_dp->mst_mgr, > port, > @@ -314,7 +314,7 @@ static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector) > struct edid *edid; > int ret; > > - if (!READ_ONCE(connector->registered)) > + if (drm_connector_is_unregistered(connector)) > return intel_connector_update_modes(connector, NULL); > > edid = drm_dp_mst_get_edid(connector, &intel_dp->mst_mgr, intel_connector->port); > @@ -330,7 +330,7 @@ intel_dp_mst_detect(struct drm_connector *connector, bool force) > struct intel_connector *intel_connector = to_intel_connector(connector); > struct intel_dp *intel_dp = intel_connector->mst_port; > > - if (!READ_ONCE(connector->registered)) > + if (drm_connector_is_unregistered(connector)) > return connector_status_disconnected; > return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr, > intel_connector->port); > @@ -361,7 +361,7 @@ intel_dp_mst_mode_valid(struct drm_connector *connector, > int bpp = 24; /* MST uses fixed bpp */ > int max_rate, mode_rate, max_lanes, max_link_clock; > > - if (!READ_ONCE(connector->registered)) > + if (drm_connector_is_unregistered(connector)) > return MODE_ERROR; > > if (mode->flags & DRM_MODE_FLAG_DBLSCAN) > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h > index 5b3cf909fd5e..dd0552cb7472 100644 > --- a/include/drm/drm_connector.h > +++ b/include/drm/drm_connector.h > @@ -82,6 +82,53 @@ enum drm_connector_status { > connector_status_unknown = 3, > }; > > +/** > + * enum drm_connector_registration_status - userspace registration status for > + * a &drm_connector > + * > + * This enum is used to track the status of initializing a connector and > + * registering it with userspace, so that DRM can prevent bogus modesets on > + * connectors that no longer exist. > + */ > +enum drm_connector_registration_state { > + /** > + * @DRM_CONNECTOR_INITIALIZING: The connector has just been created, > + * but has yet to be exposed to userspace. There should be no > + * additional restrictions to how the state of this connector may be > + * modified. > + */ > + DRM_CONNECTOR_INITIALIZING = 0, > + > + /** > + * @DRM_CONNECTOR_REGISTERED: The connector has been fully initialized > + * and registered with sysfs, as such it has been exposed to > + * userspace. There should be no additional restrictions to how the > + * state of this connector may be modified. > + */ > + DRM_CONNECTOR_REGISTERED = 1, > + > + /** > + * @DRM_CONNECTOR_UNREGISTERED: The connector has either been exposed > + * to userspace and has since been unregistered and removed from > + * userspace, or the connector was unregistered before it had a chance > + * to be exposed to userspace (e.g. still in the > + * @DRM_CONNECTOR_INITIALIZING state). When a connector is > + * unregistered, there are additional restrictions to how its state > + * may be modified: > + * > + * - An unregistered connector may only have its DPMS changed from > + * On->Off. Once DPMS is changed to Off, it may not be switched back > + * to On. > + * - Modesets are not allowed on unregistered connectors, unless they > + * would result in disabling its assigned CRTCs. This means > + * disabling a CRTC on an unregistered connector is OK, but enabling > + * one is not. > + * - Removing a CRTC from an unregistered connector is OK, but new > + * CRTCs may never be assigned to an unregistered connector. > + */ > + DRM_CONNECTOR_UNREGISTERED = 2, > +}; > + > enum subpixel_order { > SubPixelUnknown = 0, > SubPixelHorizontalRGB, > @@ -853,10 +900,12 @@ struct drm_connector { > bool ycbcr_420_allowed; > > /** > - * @registered: Is this connector exposed (registered) with userspace? > + * @registration_state: Is this connector initializing, exposed > + * (registered) with userspace, or unregistered? > + * > * Protected by @mutex. > */ > - bool registered; > + enum drm_connector_registration_state registration_state; > > /** > * @modes: > @@ -1167,6 +1216,24 @@ static inline void drm_connector_unreference(struct drm_connector *connector) > drm_connector_put(connector); > } > > +/** > + * drm_connector_is_unregistered - has the connector been unregistered from > + * userspace? > + * @connector: DRM connector > + * > + * Checks whether or not @connector has been unregistered from userspace. > + * > + * Returns: > + * True if the connector was unregistered, false if the connector is > + * registered or has not yet been registered with userspace. > + */ > +static inline bool > +drm_connector_is_unregistered(struct drm_connector *connector) > +{ > + return READ_ONCE(connector->registration_state) == > + DRM_CONNECTOR_UNREGISTERED; > +} > + > const char *drm_get_connector_status_name(enum drm_connector_status status); > const char *drm_get_subpixel_order_name(enum subpixel_order order); > const char *drm_get_dpms_name(int val); > -- > 2.17.2 > -- Daniel Vetter Software Engineer, Intel Corporation http://blog.ffwll.ch