Received: by 2002:ab2:620c:0:b0:1ef:ffd0:ce49 with SMTP id o12csp384472lqt; Mon, 18 Mar 2024 10:29:27 -0700 (PDT) X-Forwarded-Encrypted: i=3; AJvYcCXk1WTCutH6mF94dvX5RA5QvZfY/xUDZ+D4QIc4ILRlbgOcFy41R4VMYyigdOU7KS115ZQWp4dMLBHTuLuaIn7BIEWGjl2TNp4yUe3xBw== X-Google-Smtp-Source: AGHT+IFnn0HceS7s2fKpGqwiSMc3si2/covWI+hAYM8K9I9+cJxJaP+V1XxyNhlkf4iX3J8XVkd6 X-Received: by 2002:a05:620a:4625:b0:789:e1af:601c with SMTP id br37-20020a05620a462500b00789e1af601cmr600219qkb.8.1710782967437; Mon, 18 Mar 2024 10:29:27 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1710782967; cv=pass; d=google.com; s=arc-20160816; b=sO5UD18POJIyumGvXuP2aIn3vEh44IpEdYGITC8AzUCweRmdtEODp838Y23vGNFUdm /tlrnicIcGhVK9TOYuGKcUxCFUoL4ag/M2OqayE9G1UaNW7uaDCpNTGBJ3evTikJ47sq hHlgw1MTMSil8OKB99SG/E2isMt2UkPCVTq2ERfS7ypsKVLUSwALoemL9fL3sNDsAiT0 LEVPD2MFb+deGGJlFN7ygboWWcctTqiBZUh6DNShX9AMJlHRJFGsYaSia1IlpAYx8XVr 1zzy68UVlqp7OtOYffpuublfguuwAXGIZdFy0tSATDn1MzDSyrGh0/vxetsWqpSuvB+x PJmw== 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=oeOc5O2pSjjSyVH+0LRn/BzLKrVmE3Ibu5Ixv+BJ/ts=; fh=Olj4ugu32HAvPO4hCHMz34e4VxAY0srCRfUEFKzSzqU=; b=Npq4d5pxvV6hIKC/od46jRX7mdbFBbsuMNeqvvYgktP9eInlT3vakm1QBy9+VX75PC OnFLP+eyydYEi2jpoxV0IQ8ppd3Bupt8TX/lugrfsF9ZFy/qWlDQWqPNWXmmU5FRcNzr fuzJerHz54HQXroOLyelNt7+q/eEcl/v+pUEjeyxk8Srk1ZjzgYzTDLVMuV0aobxZiQJ Uk+RbVcSLnZHUppduOQ5bY2rjGfttFcrw9xCHIR3FwuSTrdSWG0Aos4N/B9UWnz5nQSN uRmr6YS8cOCum+hUy6ScSp6lVHOgusU35aHka/l1FG/qXha1nAdMBlHg42SZIejbEd4n NqKQ==; dara=google.com ARC-Authentication-Results: i=2; mx.google.com; dkim=pass header.i=@linux.dev header.s=key1 header.b=AJZgv1yX; 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-106449-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-106449-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. [2604:1380:45d1:ec00::1]) by mx.google.com with ESMTPS id w8-20020a05620a148800b00789ec76486csi5702364qkj.682.2024.03.18.10.29.27 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 18 Mar 2024 10:29:27 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel+bounces-106449-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) client-ip=2604:1380:45d1:ec00::1; Authentication-Results: mx.google.com; dkim=pass header.i=@linux.dev header.s=key1 header.b=AJZgv1yX; 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-106449-linux.lists.archive=gmail.com@vger.kernel.org designates 2604:1380:45d1:ec00::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-106449-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 1A9D81C220DB for ; Mon, 18 Mar 2024 17:29:27 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 9449355784; Mon, 18 Mar 2024 17:29:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="AJZgv1yX" Received: from out-180.mta1.migadu.com (out-180.mta1.migadu.com [95.215.58.180]) (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 5EB85282EA for ; Mon, 18 Mar 2024 17:29:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.180 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710782960; cv=none; b=qa/ijYWfRfqObyg9J8a8tK/xJ9/5ZheX1whJWlz+FY/MfdfxoHeFM6Axj4T9QqNeu5WdlEs+gdEyqo244n7Tgtg5DWTzUCiC1DDcBUExhtscxKSct792EMc1nhzm6Mrg/SyugtEdzgIAuJ2s1oB/UCcuca40TLZcg9yoG628/vU= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1710782960; c=relaxed/simple; bh=Dhu0g76mediH0Kok8zcJP/hxQyBWWdekQZwYyQXXL2E=; h=Message-ID:Date:MIME-Version:Subject:To:Cc:References:From: In-Reply-To:Content-Type; b=ZQQjKVD1EKZ8FBh5kLSb+pohbssrSDxEtt5U1zqsPP7JcJ5MXURf5Lsz9NVYCaEfYhkC2ughrhOLJfVrv1/tVpWpZRmb36l5WGeSrztveK2es7pkH8uIQwMBYyN9kyD667VwcvYWcTcfg6+hYOcu+dgOqa2c/JQPYz5oeykzEsc= 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=AJZgv1yX; arc=none smtp.client-ip=95.215.58.180 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: <7e8e5e8e-ad50-4a6a-ac47-7fb1536a9df8@linux.dev> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1710782956; 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=oeOc5O2pSjjSyVH+0LRn/BzLKrVmE3Ibu5Ixv+BJ/ts=; b=AJZgv1yXFUeWwgm7q1/oprRrR5XsOmJozP7paI1MImM0FueXQZYO0lnstBDhThm1T40Xt7 Ll+nIiVjIePTXAnWxlTuSNN2Z6AinyZGT+t697RbzSiklgxrRUPKAScspuoa7qORSd7b55 Da20dN9YewkM+EIL33XsZAU/Ey0U8Rk= Date: Mon, 18 Mar 2024 13:29:12 -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> X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. From: Sean Anderson In-Reply-To: <20240318171651.GJ13682@pendragon.ideasonboard.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit X-Migadu-Flow: FLOW_OUT On 3/18/24 13:16, Laurent Pinchart wrote: > Hi Sean, > > Thank you for the patch. > > 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. >> * @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); >> } >