lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Wed, 22 Mar 2017 18:53:06 +0200
From:   Leonard Crestez <leonard.crestez@....com>
To:     Mark Brown <broonie@...nel.org>,
        Liam Girdwood <lgirdwood@...il.com>,
        Viresh Kumar <viresh.kumar@...aro.org>,
        "Rafael J. Wysocki" <rjw@...ysocki.net>,
        Shawn Guo <shawnguo@...nel.org>,
        Sascha Hauer <kernel@...gutronix.de>
CC:     Leonard Crestez <leonard.crestez@....com>,
        Robin Gong <yibin.gong@....com>,
        Anson Huang <Anson.Huang@....com>,
        Irina Tirdea <irina.tirdea@....com>,
        Rob Herring <robh+dt@...nel.org>,
        Mark Rutland <mark.rutland@....com>,
        Fabio Estevam <fabio.estevam@....com>,
        Octavian Purdila <octavian.purdila@....com>,
        <linux-pm@...r.kernel.org>, <linux-arm-kernel@...ts.infradead.org>,
        <devicetree@...r.kernel.org>, <linux-kernel@...r.kernel.org>
Subject: [RFC 4/8] regulator: core: Check enabling bypass respects constraints

Enabling bypass mode makes a regulator passthrough the supply voltage
directly. It is possible that the supply voltage is set high enough that
it violates machine constraints so let's check for that.

The supply voltage might be higher because of min_dropout_uV or maybe
there is just an unrelated consumer who requested a higher voltage.

Signed-off-by: Leonard Crestez <leonard.crestez@....com>
---
 drivers/regulator/core.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 50 insertions(+), 2 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 53d4fc7..9d893aa 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -3453,6 +3453,54 @@ int regulator_set_load(struct regulator *regulator, int uA_load)
 }
 EXPORT_SYMBOL_GPL(regulator_set_load);
 
+static int _regulator_set_bypass(struct regulator *regulator, bool bypass)
+{
+	struct regulator_dev *rdev = regulator->rdev;
+	int output_voltage;
+	int supply_voltage;
+
+	if (bypass && !rdev->supply) {
+		rdev_err(rdev, "Refuse to set bypass on regulator with no supply!\n");
+		return -EINVAL;
+	}
+
+	/* Check that enabling bypass won't break constraints */
+	if (bypass && _regulator_is_enabled(rdev)) {
+		output_voltage = _regulator_get_voltage(rdev);
+		if (output_voltage < 0) {
+			rdev_err(rdev, "Failed to get old output voltage before"
+					" enabling bypass: %d\n", output_voltage);
+			return output_voltage;
+		}
+		supply_voltage = _regulator_get_voltage(rdev->supply->rdev);
+		if (supply_voltage < 0) {
+			rdev_err(rdev, "Failed to get supply voltage before"
+					" enabling bypass: %d\n", supply_voltage);
+			return supply_voltage;
+		}
+		if (supply_voltage < rdev->constraints->min_uV ||
+				supply_voltage > rdev->constraints->max_uV) {
+			rdev_err(rdev, "Enabling bypass would change voltage"
+					" from %duV to %duV violating"
+					" constraint range %duV to %duV\n",
+				output_voltage,
+				supply_voltage,
+				rdev->constraints->min_uV,
+				rdev->constraints->max_uV);
+			return -EINVAL;
+		}
+		rdev_dbg(rdev, "Enabling bypass would change voltage"
+				" from %duV to %duV respecting"
+				" constraint range %duV to %duV\n",
+			output_voltage,
+			supply_voltage,
+			rdev->constraints->min_uV,
+			rdev->constraints->max_uV);
+	}
+
+	return rdev->desc->ops->set_bypass(rdev, bypass);
+}
+
 /**
  * regulator_allow_bypass - allow the regulator to go into bypass mode
  *
@@ -3481,7 +3529,7 @@ int regulator_allow_bypass(struct regulator *regulator, bool enable)
 		rdev->bypass_count++;
 
 		if (rdev->bypass_count == rdev->open_count) {
-			ret = rdev->desc->ops->set_bypass(rdev, enable);
+			ret = _regulator_set_bypass(regulator, enable);
 			if (ret != 0)
 				rdev->bypass_count--;
 		}
@@ -3490,7 +3538,7 @@ int regulator_allow_bypass(struct regulator *regulator, bool enable)
 		rdev->bypass_count--;
 
 		if (rdev->bypass_count != rdev->open_count) {
-			ret = rdev->desc->ops->set_bypass(rdev, enable);
+			ret = _regulator_set_bypass(regulator, enable);
 			if (ret != 0)
 				rdev->bypass_count++;
 		}
-- 
2.7.4

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ