Received: by 2002:ab2:620c:0:b0:1ef:ffd0:ce49 with SMTP id o12csp402682lqt; Mon, 18 Mar 2024 11:02:38 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCXtOiLA8ixX78duUIkY2+O5w/D/ZuCTclBiSyFLMFLY1YFVSdQ+Th+N3l04ASXTuzFnIQ54scbO6qntDdYAVJHb6SXBhlmlEPQXl4YJtg== X-Google-Smtp-Source: AGHT+IFI79imRCGm0jVH3mzNsSk1Ov7zrUZaTwQ4zLW02vzaYh+wENV9z/b8pUV1fT6ZYbfuOlHO X-Received: by 2002:a05:620a:a4a:b0:789:f8a5:c7ce with SMTP id j10-20020a05620a0a4a00b00789f8a5c7cemr5034623qka.1.1710784958438; Mon, 18 Mar 2024 11:02:38 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1710784958; cv=pass; d=google.com; s=arc-20160816; b=uejRihc1HrKTK68kQc1E6I2/iJBL9YJ7HTPTy+Qn64rebKlUdhC3tHgi+07dV12yoo MY9kRR+36qNfpNflcvxu/iO+59JQ2OskpY5gi9tyVyhcJmuQzfrAa0lLFmtRRkgcZivH OcB3/QaCxtwroTyMu8O6AM9GVI/sUKAd2+Ytv4gL7i0PKnbCsJJWgquQQRT7k96scOxx BK6Pr78HndTe+ubbqeMhicBRLA4nClG5771eG+7JIv7lX1evgzdOl5bNyoCUvU1iUG1N G3tnAuSRV+Pwza032EjpoPnDg9LOK1/gqcxSXtgGPgiJkQvQ9W1SfZOox2q54XBLDZGH Nm2w== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:in-reply-to:from:references:cc:to :content-language:subject:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:date:dkim-signature:message-id; bh=pmygLB5mwmDf7ougxQc0mLDBWEO79RLREmB0n06npVo=; fh=Olj4ugu32HAvPO4hCHMz34e4VxAY0srCRfUEFKzSzqU=; b=CdUqIVcigtFCxlFgywNjskF2NU5qADUnWTcivotkoiOsMQOh8lSDCClrnDnLh1n7HG 5kB3cBZz5FGCRQmDE2+Mc05b2JL68JlmaCTgszA2/ejPexiw1u3IFHii1nKqZntfZMCd QNy2zOqSe340Lip+rGD2U9++I0jrOzGfB9p+oDmb1/wqByLu5yi2MkohpJxdRpp8HJ+4 zSzLiDnLbq+dSY6q+7C41Yva91uZN8E2b8fzSyDHHihkgtoeYTgY8TNZn9yU9eTsVObD hRfYwstb2oTNTHoIQcGCJoXnCVyWvHyaPfnxO/Jlgu3f7A/NpHearp6Nnes5TsK9j81P VZug==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@linux.dev header.s=key1 header.b=iMrEI2uO; arc=pass (i=1 spf=pass spfdomain=linux.dev dkim=pass dkdomain=linux.dev dmarc=pass fromdomain=linux.dev); spf=pass (google.com: domain of linux-kernel+bounces-106494-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-106494-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linux.dev Return-Path: Received: from ny.mirrors.kernel.org (ny.mirrors.kernel.org. [147.75.199.223]) by mx.google.com with ESMTPS id h15-20020ae9ec0f000000b0078810974e1dsi9984556qkg.364.2024.03.18.11.02.38 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 18 Mar 2024 11:02:38 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel+bounces-106494-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) client-ip=147.75.199.223; Authentication-Results: mx.google.com; dkim=pass header.i=@linux.dev header.s=key1 header.b=iMrEI2uO; arc=pass (i=1 spf=pass spfdomain=linux.dev dkim=pass dkdomain=linux.dev dmarc=pass fromdomain=linux.dev); spf=pass (google.com: domain of linux-kernel+bounces-106494-linux.lists.archive=gmail.com@vger.kernel.org designates 147.75.199.223 as permitted sender) smtp.mailfrom="linux-kernel+bounces-106494-linux.lists.archive=gmail.com@vger.kernel.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linux.dev Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ny.mirrors.kernel.org (Postfix) with ESMTPS id 1CBAB1C22319 for ; Mon, 18 Mar 2024 18:02:38 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 3448856762; Mon, 18 Mar 2024 18:02:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="iMrEI2uO" Received: from out-189.mta0.migadu.com (out-189.mta0.migadu.com [91.218.175.189]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1BD4455E71 for ; Mon, 18 Mar 2024 18:02:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.189 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710784924; cv=none; b=YnDB6irzcS8vqZlQ+9a7wTBHj2b5NURH47UJzd3LfGubZwS478xemC8R2tXwbhTrLyU0mB9b9SRUNswZIYXeVFXpJxC0F42o5eQ1w2HRJCLQWdVmAxVnLhosjiw5HZkbELClfkdblyklz7ixJ2BX+ZaL+5H2EBiTsoc/42Cty/k= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710784924; c=relaxed/simple; bh=rD35FqWC/tw47uINeGa4HyGcO2hVyyU0qQVbJEtwIgE=; h=Message-ID:Date:MIME-Version:Subject:To:Cc:References:From: In-Reply-To:Content-Type; b=tPPXtaCymJs4z0D0rI3x+40zSgSGxEl18hgQDr58XQK7C9Tj93xBMxfkePxTj8FJjlJyw/7HtTXq10fMvi7XkDmovnYX4UrRfm9QiQG0BUda/ijRi92bH29TtoVWDGqfmWk0NqLUcqArsOOlxieMHh2vOTtA+no/NcPwqhgfiz4= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=iMrEI2uO; arc=none smtp.client-ip=91.218.175.189 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Message-ID: DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1710784919; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=pmygLB5mwmDf7ougxQc0mLDBWEO79RLREmB0n06npVo=; b=iMrEI2uOCru32Fbz5NDN82nYVdskyAlEjAkmIFRUuQRyKU2mBr7B9BPizOZeDKltxcBCSR datpU3d1yZvpr39mHLlqbLmMdSmnuzRipC+EamMQPxtOrKB2LYxgI+SqXD2IV9q4sB9GQx Qt72cls9B9A3E/3Lyhw2WM3O5QaU2/0= Date: Mon, 18 Mar 2024 14:01:55 -0400 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Subject: Re: [PATCH 3/6] drm: zynqmp_dp: Add locking Content-Language: en-US To: Laurent Pinchart Cc: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , dri-devel@lists.freedesktop.org, David Airlie , linux-kernel@vger.kernel.org, Michal Simek , linux-arm-kernel@lists.infradead.org, Daniel Vetter References: <20240315230916.1759060-1-sean.anderson@linux.dev> <20240315230916.1759060-4-sean.anderson@linux.dev> <20240318171651.GJ13682@pendragon.ideasonboard.com> <7e8e5e8e-ad50-4a6a-ac47-7fb1536a9df8@linux.dev> <20240318175921.GO13682@pendragon.ideasonboard.com> X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. From: Sean Anderson In-Reply-To: <20240318175921.GO13682@pendragon.ideasonboard.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Migadu-Flow: FLOW_OUT On 3/18/24 13:59, Laurent Pinchart wrote: > Hi Sean, > > On Mon, Mar 18, 2024 at 01:29:12PM -0400, Sean Anderson wrote: >> On 3/18/24 13:16, Laurent Pinchart wrote: >> > On Fri, Mar 15, 2024 at 07:09:13PM -0400, Sean Anderson wrote: >> >> Add some locking, since none is provided by the drm subsystem. This will >> > >> > That's not quite right, the DRM core doesn't call bridge operations >> > concurrently. >> >> I figured something like this was going on. >> >> > We may need locking to protect against race conditions >> > between bridge operations and interrupts though. >> >> And of course this will only get worse once we let userspace get involved. >> >> >> prevent the IRQ/workers/bridge API calls from stepping on each other's >> >> toes. >> >> >> >> Signed-off-by: Sean Anderson >> >> --- >> >> >> >> drivers/gpu/drm/xlnx/zynqmp_dp.c | 59 +++++++++++++++++++++++--------- >> >> 1 file changed, 42 insertions(+), 17 deletions(-) >> >> >> >> diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c >> >> index 8635b5673386..d2dee58e7bf2 100644 >> >> --- a/drivers/gpu/drm/xlnx/zynqmp_dp.c >> >> +++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c >> >> @@ -279,6 +279,7 @@ struct zynqmp_dp_config { >> >> * @dpsub: Display subsystem >> >> * @iomem: device I/O memory for register access >> >> * @reset: reset controller >> >> + * @lock: Mutex protecting this struct and register access (but not AUX) >> > >> > This patch does two things at once, it defers link training from the IRQ >> > handler to a work queue, and covers everything with a big lock. The >> > scope is too large. >> >> OK, I can split this. >> >> > Please restrict the lock scope and document the >> > individual fields that need to be protected, and explain the locking >> > design in the commit message (or comments in the code). >> >> As said, this lock protects >> >> - Non-atomic registers configuring the link. That is, everything but the IRQ >> registers (since these are accessed in an atomic fashion), and the DP AUX >> registers (since these don't affect the link). >> - Link configuration. This is effectively everything in zynqmp_dp which isn't >> read-only after probe time. So from next_bridge onward. >> >> It's designed to protect configuration changes so we don't have to do anything >> tricky. Configuration should never be in the hot path, so I'm not worried about >> performance. > > If userspace can control all this directly through debugfs, can you > guarantee that locks will be enough ? The driver doesn't expect direct > userspace access. I have a feeling this is really quite hacky. Yes, this is fine. The most userspace can do is force a lot of retraining. But we have timeouts on everything so I'm not really concerned. --Sean >> >> * @irq: irq >> >> * @bridge: DRM bridge for the DP encoder >> >> * @next_bridge: The downstream bridge >> >> @@ -299,6 +300,7 @@ struct zynqmp_dp { >> >> struct zynqmp_dpsub *dpsub; >> >> void __iomem *iomem; >> >> struct reset_control *reset; >> >> + struct mutex lock; >> >> int irq; >> >> >> >> struct drm_bridge bridge; >> >> @@ -308,7 +310,7 @@ struct zynqmp_dp { >> >> struct drm_dp_aux aux; >> >> struct phy *phy[ZYNQMP_DP_MAX_LANES]; >> >> u8 num_lanes; >> >> - struct delayed_work hpd_work; >> >> + struct delayed_work hpd_work, hpd_irq_work; >> > >> > One variable per line please. >> >> OK >> >> >> enum drm_connector_status status; >> >> bool enabled; >> >> >> >> @@ -1371,8 +1373,10 @@ zynqmp_dp_bridge_mode_valid(struct drm_bridge *bridge, >> >> } >> >> >> >> /* Check with link rate and lane count */ >> >> + mutex_lock(&dp->lock); >> >> rate = zynqmp_dp_max_rate(dp->link_config.max_rate, >> >> dp->link_config.max_lanes, dp->config.bpp); >> >> + mutex_unlock(&dp->lock); >> >> if (mode->clock > rate) { >> >> dev_dbg(dp->dev, "filtered mode %s for high pixel rate\n", >> >> mode->name); >> >> @@ -1399,6 +1403,7 @@ static void zynqmp_dp_bridge_atomic_enable(struct drm_bridge *bridge, >> >> >> >> pm_runtime_get_sync(dp->dev); >> >> >> >> + mutex_lock(&dp->lock); >> >> zynqmp_dp_disp_enable(dp, old_bridge_state); >> >> >> >> /* >> >> @@ -1459,6 +1464,7 @@ static void zynqmp_dp_bridge_atomic_enable(struct drm_bridge *bridge, >> >> zynqmp_dp_write(dp, ZYNQMP_DP_SOFTWARE_RESET, >> >> ZYNQMP_DP_SOFTWARE_RESET_ALL); >> >> zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_ENABLE, 1); >> >> + mutex_unlock(&dp->lock); >> >> } >> >> >> >> static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge, >> >> @@ -1466,6 +1472,7 @@ static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge, >> >> { >> >> struct zynqmp_dp *dp = bridge_to_dp(bridge); >> >> >> >> + mutex_lock(&dp->lock); >> >> dp->enabled = false; >> >> cancel_delayed_work(&dp->hpd_work); >> >> zynqmp_dp_write(dp, ZYNQMP_DP_MAIN_STREAM_ENABLE, 0); >> >> @@ -1476,6 +1483,7 @@ static void zynqmp_dp_bridge_atomic_disable(struct drm_bridge *bridge, >> >> zynqmp_dp_write(dp, ZYNQMP_DP_TX_AUDIO_CONTROL, 0); >> >> >> >> zynqmp_dp_disp_disable(dp, old_bridge_state); >> >> + mutex_unlock(&dp->lock); >> >> >> >> pm_runtime_put_sync(dp->dev); >> >> } >> >> @@ -1518,6 +1526,8 @@ static enum drm_connector_status zynqmp_dp_bridge_detect(struct drm_bridge *brid >> >> u32 state, i; >> >> int ret; >> >> >> >> + mutex_lock(&dp->lock); >> >> + >> >> /* >> >> * This is from heuristic. It takes some delay (ex, 100 ~ 500 msec) to >> >> * get the HPD signal with some monitors. >> >> @@ -1545,11 +1555,13 @@ static enum drm_connector_status zynqmp_dp_bridge_detect(struct drm_bridge *brid >> >> dp->num_lanes); >> >> >> >> dp->status = connector_status_connected; >> >> + mutex_unlock(&dp->lock); >> >> return connector_status_connected; >> >> } >> >> >> >> disconnected: >> >> dp->status = connector_status_disconnected; >> >> + mutex_unlock(&dp->lock); >> >> return connector_status_disconnected; >> >> } >> >> >> >> @@ -1611,6 +1623,29 @@ static void zynqmp_dp_hpd_work_func(struct work_struct *work) >> >> drm_bridge_hpd_notify(&dp->bridge, status); >> >> } >> >> >> >> +static void zynqmp_dp_hpd_irq_work_func(struct work_struct *work) >> >> +{ >> >> + struct zynqmp_dp *dp = container_of(work, struct zynqmp_dp, >> >> + hpd_irq_work.work); >> >> + u8 status[DP_LINK_STATUS_SIZE + 2]; >> >> + int err; >> >> + >> >> + mutex_lock(&dp->lock); >> >> + err = drm_dp_dpcd_read(&dp->aux, DP_SINK_COUNT, status, >> >> + DP_LINK_STATUS_SIZE + 2); >> >> + if (err < 0) { >> >> + dev_dbg_ratelimited(dp->dev, >> >> + "could not read sink status: %d\n", err); >> >> + } else { >> >> + if (status[4] & DP_LINK_STATUS_UPDATED || >> >> + !drm_dp_clock_recovery_ok(&status[2], dp->mode.lane_cnt) || >> >> + !drm_dp_channel_eq_ok(&status[2], dp->mode.lane_cnt)) { >> >> + zynqmp_dp_train_loop(dp); >> >> + } >> >> + } >> >> + mutex_unlock(&dp->lock); >> >> +} >> >> + >> >> static irqreturn_t zynqmp_dp_irq_handler(int irq, void *data) >> >> { >> >> struct zynqmp_dp *dp = (struct zynqmp_dp *)data; >> >> @@ -1635,23 +1670,9 @@ static irqreturn_t zynqmp_dp_irq_handler(int irq, void *data) >> >> if (status & ZYNQMP_DP_INT_HPD_EVENT) >> >> schedule_delayed_work(&dp->hpd_work, 0); >> >> >> >> - if (status & ZYNQMP_DP_INT_HPD_IRQ) { >> >> - int ret; >> >> - u8 status[DP_LINK_STATUS_SIZE + 2]; >> >> + if (status & ZYNQMP_DP_INT_HPD_IRQ) >> >> + schedule_delayed_work(&dp->hpd_irq_work, 0); >> >> >> >> - ret = drm_dp_dpcd_read(&dp->aux, DP_SINK_COUNT, status, >> >> - DP_LINK_STATUS_SIZE + 2); >> >> - if (ret < 0) >> >> - goto handled; >> >> - >> >> - if (status[4] & DP_LINK_STATUS_UPDATED || >> >> - !drm_dp_clock_recovery_ok(&status[2], dp->mode.lane_cnt) || >> >> - !drm_dp_channel_eq_ok(&status[2], dp->mode.lane_cnt)) { >> >> - zynqmp_dp_train_loop(dp); >> >> - } >> >> - } >> >> - >> >> -handled: >> >> return IRQ_HANDLED; >> >> } >> >> >> >> @@ -1674,8 +1695,10 @@ int zynqmp_dp_probe(struct zynqmp_dpsub *dpsub) >> >> dp->dev = &pdev->dev; >> >> dp->dpsub = dpsub; >> >> dp->status = connector_status_disconnected; >> >> + mutex_init(&dp->lock); >> >> >> >> INIT_DELAYED_WORK(&dp->hpd_work, zynqmp_dp_hpd_work_func); >> >> + INIT_DELAYED_WORK(&dp->hpd_irq_work, zynqmp_dp_hpd_irq_work_func); >> >> >> >> /* Acquire all resources (IOMEM, IRQ and PHYs). */ >> >> res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dp"); >> >> @@ -1775,6 +1798,7 @@ void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub) >> >> zynqmp_dp_write(dp, ZYNQMP_DP_INT_DS, ZYNQMP_DP_INT_ALL); >> >> disable_irq(dp->irq); >> >> >> >> + cancel_delayed_work_sync(&dp->hpd_irq_work); >> >> cancel_delayed_work_sync(&dp->hpd_work); >> >> >> >> zynqmp_dp_write(dp, ZYNQMP_DP_TRANSMITTER_ENABLE, 0); >> >> @@ -1782,4 +1806,5 @@ void zynqmp_dp_remove(struct zynqmp_dpsub *dpsub) >> >> >> >> zynqmp_dp_phy_exit(dp); >> >> zynqmp_dp_reset(dp, true); >> >> + mutex_destroy(&dp->lock); >> >> } >