Received: by 2002:a25:8b91:0:0:0:0:0 with SMTP id j17csp7584389ybl; Thu, 16 Jan 2020 02:05:23 -0800 (PST) X-Google-Smtp-Source: APXvYqzcQPvTnsztuSQfHleL++tUXggmygbIEtFbBNUkvdqfjmHND8vGDaTeLnlXN+j39EB0OD9v X-Received: by 2002:a9d:6c01:: with SMTP id f1mr1265356otq.133.1579169123313; Thu, 16 Jan 2020 02:05:23 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1579169123; cv=none; d=google.com; s=arc-20160816; b=QdpN9+yZYg/ttUtW9nSf2IdLkavWTx8iKFVAgJuYgpzUmw8cO1WT93ajD0UbYbbaWM N/rVeivO6qNXIolJWp/2BGDh8sjjWwcvKpGQp/ULGRN1axVsr7h70ThGInyMJSLlK7EF PaldTLqAj7Hg6fi0fTOFUa39PYSKOnVJe8vERQbEq//6ZKWW/nY/LcVV93dA1jHYCkLN 0AhZ3Ojks1Pudot4EH0aLpfQkFoW/VKfl+/IvYfCmlcwz+2AoNUc93cVBcnXzdHhgK62 7VpxLuclRcQGF4+fU5yLejaSkS9EsWN03r4FupmLKBrugVhZj4wnbWcg2g2fGofp/ZGg xCqw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from; bh=hMPRtQHjP+ntEQO983tJ5/5SYgR9qXEca7jDezdBdh0=; b=Bw+fk7wfiGhAoYpZ0LgTPZgz/5X/pDwscFH8cAVj2P2JqGOGQPQDS1U6CqW5Zznyxi Fn2taHv9RNyZd8CRvz65+2LjSWu7zUl+/Q6MFzbFaagZ+NefWf6HM6fEjYN3vSqVq3qE V6G1SWKbQ2BiuDpFFGUbTV+3qV+ouS8PVsH37rzYjRQsIAjoaXeOOAxK7M5EL2oYXSf7 JnGw0D8rXYFFjvQ7U4aoJPLcrFgHt6NM7vJOZUgAVSAL8gK6P/TBxdind68CEJ/3f3Z8 NKT1d2pNjthlnccMLUHtgZ9Qi0r3LnuPADAI5N+jnCMVyKy5gltb8IrgN6NnFcd6TM2J V7wQ== ARC-Authentication-Results: i=1; mx.google.com; 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id h7si13242233otk.86.2020.01.16.02.05.11; Thu, 16 Jan 2020 02:05:23 -0800 (PST) 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; 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=collabora.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731685AbgAPJpw (ORCPT + 99 others); Thu, 16 Jan 2020 04:45:52 -0500 Received: from bhuna.collabora.co.uk ([46.235.227.227]:55406 "EHLO bhuna.collabora.co.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730061AbgAPJpw (ORCPT ); Thu, 16 Jan 2020 04:45:52 -0500 Received: from [127.0.0.1] (localhost [127.0.0.1]) (Authenticated sender: eballetbo) with ESMTPSA id 5D07E293886 From: Enric Balletbo i Serra To: linux-kernel@vger.kernel.org Cc: Collabora Kernel ML , drinkcat@chromium.org, Mark Brown , dianders@chromium.org, Liam Girdwood , mka@chromium.org, Dmitry Osipenko Subject: [PATCH] regulator: vctrl-regulator: Avoid deadlock getting and setting the voltage Date: Thu, 16 Jan 2020 10:45:43 +0100 Message-Id: <20200116094543.2847321-1-enric.balletbo@collabora.com> X-Mailer: git-send-email 2.24.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org `cat /sys/kernel/debug/regulator/regulator_summary` ends on a deadlock when you have a voltage controlled regulator (vctrl). The problem is that the vctrl_get_voltage() and vctrl_set_voltage() calls the regulator_get_voltage() and regulator_set_voltage() and that will try to lock again the dependent regulators (the regulator supplying the control voltage). Fix the issue by exporting the unlocked version of the regulator_get_voltage() and regulator_set_voltage() API so drivers that need it, like the voltage controlled regulator driver can use it. Fixes: f8702f9e4aa7 ("regulator: core: Use ww_mutex for regulators locking") Reported-by: Douglas Anderson Signed-off-by: Enric Balletbo i Serra --- drivers/regulator/core.c | 2 ++ drivers/regulator/vctrl-regulator.c | 38 +++++++++++++++++------------ 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 03d79fee2987..e7d167ce326c 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -3470,6 +3470,7 @@ int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, out: return ret; } +EXPORT_SYMBOL(regulator_set_voltage_rdev); static int regulator_limit_voltage_step(struct regulator_dev *rdev, int *current_uV, int *min_uV) @@ -4034,6 +4035,7 @@ int regulator_get_voltage_rdev(struct regulator_dev *rdev) return ret; return ret - rdev->constraints->uV_offset; } +EXPORT_SYMBOL(regulator_get_voltage_rdev); /** * regulator_get_voltage - get regulator output voltage diff --git a/drivers/regulator/vctrl-regulator.c b/drivers/regulator/vctrl-regulator.c index 9a9ee8188109..cbadb1c99679 100644 --- a/drivers/regulator/vctrl-regulator.c +++ b/drivers/regulator/vctrl-regulator.c @@ -11,10 +11,13 @@ #include #include #include +#include #include #include #include +#include "internal.h" + struct vctrl_voltage_range { int min_uV; int max_uV; @@ -79,7 +82,7 @@ static int vctrl_calc_output_voltage(struct vctrl_data *vctrl, int ctrl_uV) static int vctrl_get_voltage(struct regulator_dev *rdev) { struct vctrl_data *vctrl = rdev_get_drvdata(rdev); - int ctrl_uV = regulator_get_voltage(vctrl->ctrl_reg); + int ctrl_uV = regulator_get_voltage_rdev(vctrl->ctrl_reg->rdev); return vctrl_calc_output_voltage(vctrl, ctrl_uV); } @@ -90,16 +93,16 @@ static int vctrl_set_voltage(struct regulator_dev *rdev, { struct vctrl_data *vctrl = rdev_get_drvdata(rdev); struct regulator *ctrl_reg = vctrl->ctrl_reg; - int orig_ctrl_uV = regulator_get_voltage(ctrl_reg); + int orig_ctrl_uV = regulator_get_voltage_rdev(ctrl_reg->rdev); int uV = vctrl_calc_output_voltage(vctrl, orig_ctrl_uV); int ret; if (req_min_uV >= uV || !vctrl->ovp_threshold) /* voltage rising or no OVP */ - return regulator_set_voltage( - ctrl_reg, + return regulator_set_voltage_rdev(ctrl_reg->rdev, vctrl_calc_ctrl_voltage(vctrl, req_min_uV), - vctrl_calc_ctrl_voltage(vctrl, req_max_uV)); + vctrl_calc_ctrl_voltage(vctrl, req_max_uV), + PM_SUSPEND_ON); while (uV > req_min_uV) { int max_drop_uV = (uV * vctrl->ovp_threshold) / 100; @@ -114,9 +117,10 @@ static int vctrl_set_voltage(struct regulator_dev *rdev, next_uV = max_t(int, req_min_uV, uV - max_drop_uV); next_ctrl_uV = vctrl_calc_ctrl_voltage(vctrl, next_uV); - ret = regulator_set_voltage(ctrl_reg, + ret = regulator_set_voltage_rdev(ctrl_reg->rdev, + next_ctrl_uV, next_ctrl_uV, - next_ctrl_uV); + PM_SUSPEND_ON); if (ret) goto err; @@ -130,7 +134,8 @@ static int vctrl_set_voltage(struct regulator_dev *rdev, err: /* Try to go back to original voltage */ - regulator_set_voltage(ctrl_reg, orig_ctrl_uV, orig_ctrl_uV); + regulator_set_voltage_rdev(ctrl_reg->rdev, orig_ctrl_uV, orig_ctrl_uV, + PM_SUSPEND_ON); return ret; } @@ -155,9 +160,10 @@ static int vctrl_set_voltage_sel(struct regulator_dev *rdev, if (selector >= vctrl->sel || !vctrl->ovp_threshold) { /* voltage rising or no OVP */ - ret = regulator_set_voltage(ctrl_reg, + ret = regulator_set_voltage_rdev(ctrl_reg->rdev, + vctrl->vtable[selector].ctrl, vctrl->vtable[selector].ctrl, - vctrl->vtable[selector].ctrl); + PM_SUSPEND_ON); if (!ret) vctrl->sel = selector; @@ -173,9 +179,10 @@ static int vctrl_set_voltage_sel(struct regulator_dev *rdev, else next_sel = vctrl->vtable[vctrl->sel].ovp_min_sel; - ret = regulator_set_voltage(ctrl_reg, + ret = regulator_set_voltage_rdev(ctrl_reg->rdev, vctrl->vtable[next_sel].ctrl, - vctrl->vtable[next_sel].ctrl); + vctrl->vtable[next_sel].ctrl, + PM_SUSPEND_ON); if (ret) { dev_err(&rdev->dev, "failed to set control voltage to %duV\n", @@ -195,9 +202,10 @@ static int vctrl_set_voltage_sel(struct regulator_dev *rdev, err: if (vctrl->sel != orig_sel) { /* Try to go back to original voltage */ - if (!regulator_set_voltage(ctrl_reg, + if (!regulator_set_voltage_rdev(ctrl_reg->rdev, + vctrl->vtable[orig_sel].ctrl, vctrl->vtable[orig_sel].ctrl, - vctrl->vtable[orig_sel].ctrl)) + PM_SUSPEND_ON)) vctrl->sel = orig_sel; else dev_warn(&rdev->dev, @@ -482,7 +490,7 @@ static int vctrl_probe(struct platform_device *pdev) if (ret) return ret; - ctrl_uV = regulator_get_voltage(vctrl->ctrl_reg); + ctrl_uV = regulator_get_voltage_rdev(vctrl->ctrl_reg->rdev); if (ctrl_uV < 0) { dev_err(&pdev->dev, "failed to get control voltage\n"); return ctrl_uV; -- 2.24.1