Hi All, At 2025-03-07 09:08:48, "Andy Yan" <andys...@163.com> wrote: >Hi All, > >At 2025-03-06 23:41:24, "Simona Vetter" <simona.vet...@ffwll.ch> wrote: >>On Thu, Mar 06, 2025 at 08:10:16AM +0100, Maxime Ripard wrote: >>> On Thu, Mar 06, 2025 at 09:16:24AM +0800, Andy Yan wrote: >>> > >>> > Hi Maxime and Dmitry: >>> > >>> > At 2025-03-06 04:13:53, "Dmitry Baryshkov" <dmitry.barysh...@linaro.org> >>> > wrote: >>> > >On Wed, Mar 05, 2025 at 02:19:36PM +0100, Maxime Ripard wrote: >>> > >> Hi Andy, >>> > >> >>> > >> On Wed, Mar 05, 2025 at 07:55:19PM +0800, Andy Yan wrote: >>> > >> > At 2025-03-04 19:10:47, "Maxime Ripard" <mrip...@kernel.org> wrote: >>> > >> > >With the bridges switching over to drm_bridge_connector, the direct >>> > >> > >association between a bridge driver and its connector was lost. >>> > >> > > >>> > >> > >This is mitigated for atomic bridge drivers by the fact you can >>> > >> > >access >>> > >> > >the encoder, and then call >>> > >> > >drm_atomic_get_old_connector_for_encoder() or >>> > >> > >drm_atomic_get_new_connector_for_encoder() with drm_atomic_state. >>> > >> > > >>> > >> > >This was also made easier by providing drm_atomic_state directly to >>> > >> > >all >>> > >> > >atomic hooks bridges can implement. >>> > >> > > >>> > >> > >However, bridge drivers don't have a way to access drm_atomic_state >>> > >> > >outside of the modeset path, like from the hotplug interrupt path >>> > >> > >or any >>> > >> > >interrupt handler. >>> > >> > > >>> > >> > >Let's introduce a function to retrieve the connector currently >>> > >> > >assigned >>> > >> > >to an encoder, without using drm_atomic_state, to make these >>> > >> > >drivers' >>> > >> > >life easier. >>> > >> > > >>> > >> > >Reviewed-by: Dmitry Baryshkov <dmitry.barysh...@linaro.org> >>> > >> > >Co-developed-by: Simona Vetter <simona.vet...@ffwll.ch> >>> > >> > >Signed-off-by: Maxime Ripard <mrip...@kernel.org> >>> > >> > >--- >>> > >> > > drivers/gpu/drm/drm_atomic.c | 45 >>> > >> > > ++++++++++++++++++++++++++++++++++++++++++++ >>> > >> > > include/drm/drm_atomic.h | 3 +++ >>> > >> > > 2 files changed, 48 insertions(+) >>> > >> > > >>> > >> > >diff --git a/drivers/gpu/drm/drm_atomic.c >>> > >> > >b/drivers/gpu/drm/drm_atomic.c >>> > >> > >index >>> > >> > >9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 >>> > >> > > 100644 >>> > >> > >--- a/drivers/gpu/drm/drm_atomic.c >>> > >> > >+++ b/drivers/gpu/drm/drm_atomic.c >>> > >> > >@@ -985,10 +985,55 @@ >>> > >> > >drm_atomic_get_new_connector_for_encoder(const struct >>> > >> > >drm_atomic_state *state, >>> > >> > > >>> > >> > > return NULL; >>> > >> > > } >>> > >> > > EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder); >>> > >> > > >>> > >> > >+/** >>> > >> > >+ * drm_atomic_get_connector_for_encoder - Get connector currently >>> > >> > >assigned to an encoder >>> > >> > >+ * @encoder: The encoder to find the connector of >>> > >> > >+ * @ctx: Modeset locking context >>> > >> > >+ * >>> > >> > >+ * This function finds and returns the connector currently >>> > >> > >assigned to >>> > >> > >+ * an @encoder. >>> > >> > >+ * >>> > >> > >+ * Returns: >>> > >> > >+ * The connector connected to @encoder, or an error pointer >>> > >> > >otherwise. >>> > >> > >+ * When the error is EDEADLK, a deadlock has been detected and the >>> > >> > >+ * sequence must be restarted. >>> > >> > >+ */ >>> > >> > >+struct drm_connector * >>> > >> > >+drm_atomic_get_connector_for_encoder(const struct drm_encoder >>> > >> > >*encoder, >>> > >> > >+ struct drm_modeset_acquire_ctx >>> > >> > >*ctx) >>> > >> > >+{ >>> > >> > >+ struct drm_connector_list_iter conn_iter; >>> > >> > >+ struct drm_connector *out_connector = ERR_PTR(-EINVAL); >>> > >> > >+ struct drm_connector *connector; >>> > >> > >+ struct drm_device *dev = encoder->dev; >>> > >> > >+ int ret; >>> > >> > >+ >>> > >> > >+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx); >>> > >> > >+ if (ret) >>> > >> > >+ return ERR_PTR(ret); >>> > >> > >>> > >> > It seems that this will cause a deadlock when called from a hotplug >>> > >> > handling path, I have a WIP DP diver[0], which suggested by Dmitry to >>> > >> > use this API from a &drm_bridge_funcs.detect callback to get the >>> > >> > connector, as detect is called by drm_helper_probe_detect, which will >>> > >> > hold connection_mutex first, so the deaklock happens: >>> > >> > >>> > >> > drm_helper_probe_detect(struct drm_connector *connector, >>> > >> > struct drm_modeset_acquire_ctx *ctx, >>> > >> > bool force) >>> > >> > { >>> > >> > const struct drm_connector_helper_funcs *funcs = >>> > >> > connector->helper_private; >>> > >> > struct drm_device *dev = connector->dev; >>> > >> > int ret; >>> > >> > >>> > >> > if (!ctx) >>> > >> > return drm_helper_probe_detect_ctx(connector, force); >>> > >> > >>> > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, >>> > >> > ctx); >>> > >> > if (ret) >>> > >> > return ret; >>> > >> > >>> > >> > if (funcs->detect_ctx) >>> > >> > ret = funcs->detect_ctx(connector, ctx, force); >>> > >> > else if (connector->funcs->detect) >>> > >> > ret = connector->funcs->detect(connector, force); >>> > >> > else >>> > >> > ret = connector_status_connected; >>> > >> > >>> > >> > if (ret != connector->status) >>> > >> > connector->epoch_counter += 1; >>> > >> > >>> > >> > So I wonder can we let drm_bridge_funcs.detect pass a connector for >>> > >> > this case ? >>> > >> >>> > >> Do you actually see a deadlock occurring? AFAIK, drm_modeset_lock is >>> > >> fine with reentrancy from the same context, so it should work just >>> > >> fine. >>> > > >>> > >Andy, that probably means that you should use .detect_ctx() and pass the >>> > >context to drm_atomic_get_connector_for_encoder(). >>> > >>> > Unfortunately, the drm_bridge_funcs does not have a .detect_ctx() >>> > version . >>> > The call chain is: >>> > drm_helper_probe_detect >>> > --> drm_bridge_connector_detect(struct drm_connector *connector, bool >>> > force) >>> > --> drm_bridge_funcs.detect(bridge) >>> > The ctx got dropped when drm_helper_probe_detect call >>> > drm_bridge_connector_detect >>> > The connector got dropped when connector call it's bridege.detect >>> > >>> > So I think the simplest solution is to have drm_bridge_funcs.detect >>> > directly pass the connector >>> >>> I don't disagree on principle, but I think a better first step would be >>> to provide a detect_ctx hook to bridges. >> >>Yup. There's other reasons you really want to get at the locking context >>in detect callbacks, doing this special case by passing something for >>everyone doesn't sound like the right approach to me. > >Ok, I will add a detect_ctx hook for bridge. Thanks for your advice. > >Just confirm that can I send this add detect_ctx hook patch alone first? >I think this patch will be easy to merge, so it can help my WIP DP driver >stay light on dependencies。
When I try to add the detect_ctx hook to bridge, I found that there is still a case that there is no ctx to pass to detect_ctx: int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY) { ............... struct drm_modeset_acquire_ctx ctx; WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); drm_modeset_acquire_init(&ctx, 0); drm_dbg_kms(dev, "[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); retry: ret = drm_modeset_lock(&dev->mode_config.connection_mutex, &ctx); ................... ret = drm_helper_probe_detect(connector, &ctx, true); ...................................... count = drm_helper_probe_get_modes(connector); Then in drm_bridge_connector_get_modes: static int drm_bridge_connector_get_modes(struct drm_connector *connector) { struct drm_bridge_connector *bridge_connector = to_drm_bridge_connector(connector); struct drm_bridge *bridge; ........................................... /* * If display exposes EDID, then we parse that in the normal way to * build table of supported modes. */ bridge = bridge_connector->bridge_edid; if (bridge) return drm_bridge_connector_get_modes_edid(connector, bridge); static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector, struct drm_bridge *bridge) { enum drm_connector_status status; const struct drm_edid *drm_edid; int n; status = drm_bridge_connector_detect(connector, false); ...................... -drm_bridge_connector_detect(struct drm_connector *connector, bool force) +drm_bridge_connector_detect(struct drm_connector *connector, + struct drm_modeset_acquire_ctx *ctx, + bool force) { struct drm_bridge_connector *bridge_connector = to_drm_bridge_connector(connector); @@ -186,7 +188,7 @@ drm_bridge_connector_detect(struct drm_connector *connector, bool force) enum drm_connector_status status; if (detect) { status = detect->funcs->detect(detect, ctx); There is still no ctx in this call chain. So there will be deadlock if I use drm_atomic_get_new_connector_for_encoder to find connector in my bridge detect_ctx hook. > > >>-Sima >>-- >>Simona Vetter >>Software Engineer, Intel Corporation >>http://blog.ffwll.ch