Received: by 2002:a25:1506:0:0:0:0:0 with SMTP id 6csp1594562ybv; Thu, 20 Feb 2020 23:57:52 -0800 (PST) X-Google-Smtp-Source: APXvYqxup2Z/pZ/POKsMJKgU65aVdmu4ydOCUxX4Sbron7glZ4LrcZ5aOxHHFJHgihSSF8eB+5h2 X-Received: by 2002:a9d:53c2:: with SMTP id i2mr25371408oth.43.1582271871988; Thu, 20 Feb 2020 23:57:51 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1582271871; cv=none; d=google.com; s=arc-20160816; b=mu+qqRE8C0A5C+AyZ82OQRyRD6vAy6ai3M3hyHXUkHQy/sMj869pAu2fVxKhKbvlh2 npC7Lq1PAxfON5AejVg7C2SwChWxJhYFK+h6OCFcxGTbgG9KzswR5uQY7YDgBOsAXQ2U 7UKONA80s5EWdJiyeJ1idoE5gfS/lws2n2mGo/zOLJ+ifjbqEUQp1mPDKPpOc4LRfot2 iVqgp/aV0EfapiBThi4Pq7CUJigMdnbxAmy7w/7wFZxvXqxsUtP+zU/H77ILq3vClMGk BG0hH2WyEm5GnDE4yf1T2DFiPdgaf4TN0J6aRbwxbmdTUXCD5E6LQrlrKc41Vgh3l2t+ Mw/w== 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 :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=afSkR17awkXV3Phwc+pabwFOGA4cpJzBvWU9+Swhivg=; b=Fah0EKDDiZ2zVXxkPovuQ5AV7w4RkRC5iYJHvwHMgpMDM/KN0FJzlqD00PwxEtsGQJ LY0Ag2Q/j20TpA2KDYDv3iXmaK/LUPtk1dmfEgnxjuVQync72Tr9dYzW8a5xCyyaY6BT sUd+R+FRVIA9z5cUz6d3luC7Eo4366BIjD7gGQTt5IG2hv/JQqiL+e3sjTR3DhcsYip9 Ae2nD/pq097KEhb2/lLS5YOuavm5hdQMidwV6E/TLeerLIodYkVPttynZZm56M3GUm48 nmMtXyMqYZfa5AAv3qKEtrZ9slA2OqutcbLfwXX7WPyVn88XjT8Go7Q28tHSle7/0try U71Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=IWYu+s8i; 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 v24si1111272otn.125.2020.02.20.23.57.39; Thu, 20 Feb 2020 23:57:51 -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; dkim=pass header.i=@kernel.org header.s=default header.b=IWYu+s8i; 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 S1730483AbgBUH4d (ORCPT + 99 others); Fri, 21 Feb 2020 02:56:33 -0500 Received: from mail.kernel.org ([198.145.29.99]:55784 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727872AbgBUH42 (ORCPT ); Fri, 21 Feb 2020 02:56:28 -0500 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id 29DFE20578; Fri, 21 Feb 2020 07:56:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1582271787; bh=7oaIDcG5sR819ZC9N4iXtsmUArGfUPkCaLdu3IjP0BA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IWYu+s8imCHyhI4L+ZxzMwkPnXNLBvyxOskXRmlDhthGfiZYQ86pzFH5fGKQsimVh pIQBC814OMVFyat7HXwM8V8CQ9NR3lkLj80Mno9u5KLo1ffnYYf7a0zV05aS3rPGrF L0ry1TKBBv4ssX7Nxg/8j7I6VibrzRZGmlJbXZoU= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Douglas Anderson , Enric Balletbo i Serra , Mark Brown , Sasha Levin Subject: [PATCH 5.5 298/399] regulator: vctrl-regulator: Avoid deadlock getting and setting the voltage Date: Fri, 21 Feb 2020 08:40:23 +0100 Message-Id: <20200221072430.711864171@linuxfoundation.org> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200221072402.315346745@linuxfoundation.org> References: <20200221072402.315346745@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Enric Balletbo i Serra [ Upstream commit e9153311491da9d9863ead9888a1613531cb4a1b ] `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 Link: https://lore.kernel.org/r/20200116094543.2847321-1-enric.balletbo@collabora.com Signed-off-by: Mark Brown Signed-off-by: Sasha Levin --- 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 03d79fee2987e..e7d167ce326cb 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 9a9ee81881098..cbadb1c996790 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.20.1