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]
Message-ID: <68f0a261-ba4b-8411-82f1-37eed4eccf24@codeaurora.org>
Date:   Tue, 22 Jan 2019 13:32:30 -0700
From:   Jeffrey Hugo <jhugo@...eaurora.org>
To:     Bjorn Andersson <bjorn.andersson@...aro.org>
Cc:     Liam Girdwood <lgirdwood@...il.com>,
        Mark Brown <broonie@...nel.org>, linux-kernel@...r.kernel.org,
        linux-arm-msm@...r.kernel.org
Subject: Re: [PATCH] regulator: qcom-smd: Batch up requests for disabled
 regulators

On 1/22/2019 1:11 PM, Bjorn Andersson wrote:
> On Tue 22 Jan 11:25 PST 2019, Jeffrey Hugo wrote:
> 
>> Hi Bjorn,
>>
>> This seems intresting, but I'm not sure I fully understand it yet.
>>
>> On 1/22/2019 12:01 PM, Bjorn Andersson wrote:
>>> In some scenarios the early stages of the boot chain has configured
>>> regulators to be in a required state, but the later stages has skipped
>>> to inform the RPM about it's requirements.
>> So if I understand this correctly, the boot chain turned on and configured
>> the regulator, but didn't give the RPM its vote, so the RPM doesn't know
>> anything and just assumes the default state - off/unconfigured.  Right?
>>
> 
> In our particular case we see that if ABL decides not to enter fastboot
> it will not request the RPM to power the USB block. But the particular
> regulator is part of the power-on sequence of the PMIC, so it's on.
> 
> So there's no votes in the RPM to have this on, but it is on and
> disabling it causes the system to reboot.
> 
>> If we are in Linux, is that boot chain "vote" valid anymore?
> 
> I've never seen this code, but I assume it treats votes from "unsecure
> apps" the same. The problem here is that there's no votes, from anyone,
> to keep this regulator enabled.

As far as I am aware, yes "unsecured apps" has one vote, be it Linux or 
the boot chain.  I was thinking conceptually, the boot chain is done, 
why do we care about what hardware they were using, but you pointed out 
above that you get a board reset, so I guess we do.

> 
>>>
>>> But as the SMD RPM regulators are being initialized voltage change
>>> requests will be issued to align the voltage with the valid ranges. The
>>> RPM aggregates all parameters for the specific regulator, the voltage
>>> will be adjusted and the "enabled" state will be "off" - and the
>>> regulator is turned off.
>>
>> So, this would happen when Linux is processing the constraints from DT for
>> example, but is still initing the devices, so there are no consumers and
>> thus the device is not enabled, but the voltage configuration is sent to the
>> RPM to ensure the constraints are met?
>>
> 
> Correct.
> 
>>>
>>> This patch addresses this problem by caching the requested enable state,
>>> voltage and load and send the parameters in a batch, depending on the
>>> enable state - effectively delaying the voltage request for disabled
>>> regulators.
>>
>> I'm curious, would any sort of additional latency be expected because the
>> RPM has delayed work to the enable "stage"?
>>
> 
> Afaict the PMIC itself is enabled/disabled by setting the voltage, so
> there should be no negative latency difference in postponing the voltage
> change until enable time. There's quite likely a positive gain though,
> by removing the extra round trip over SMD.

Sounds good.  That's what I thought, but I was wondering if I was wrong.

> 
>> While I suspect there are benefits to this change regardless, it seems like
>> what you are describing above should be addressed by "regulator-boot-on" in
>> the DT.  Why is that not a valid solution for this scenario?
>>
> 
> Because set_machine_constraints() first calls
> machine_constraints_voltage() then _regulator_do_enable() (if boot_on is
> set). So without this patch the RPM will disable the regulator in the
> beginning of the function and not reach the end of it.

Makes sense.

> 
> Regards,
> Bjorn
> 
>>>
>>> Signed-off-by: Bjorn Andersson <bjorn.andersson@...aro.org>
>>> ---
>>>    drivers/regulator/qcom_smd-regulator.c | 104 ++++++++++++++++---------
>>>    1 file changed, 69 insertions(+), 35 deletions(-)
>>>
>>> diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c
>>> index f5bca77d67c1..dfdc67da5cec 100644
>>> --- a/drivers/regulator/qcom_smd-regulator.c
>>> +++ b/drivers/regulator/qcom_smd-regulator.c
>>> @@ -31,6 +31,11 @@ struct qcom_rpm_reg {
>>>    	int is_enabled;
>>>    	int uV;
>>> +	u32 load;
>>> +
>>> +	unsigned int enabled_updated:1;
>>> +	unsigned int uv_updated:1;
>>> +	unsigned int load_updated:1;
>>>    };
>>>    struct rpm_regulator_req {
>>> @@ -43,30 +48,59 @@ struct rpm_regulator_req {
>>>    #define RPM_KEY_UV	0x00007675 /* "uv" */
>>>    #define RPM_KEY_MA	0x0000616d /* "ma" */
>>> -static int rpm_reg_write_active(struct qcom_rpm_reg *vreg,
>>> -				struct rpm_regulator_req *req,
>>> -				size_t size)
>>> +static int rpm_reg_write_active(struct qcom_rpm_reg *vreg)
>>>    {
>>> -	return qcom_rpm_smd_write(vreg->rpm,
>>> -				  QCOM_SMD_RPM_ACTIVE_STATE,
>>> -				  vreg->type,
>>> -				  vreg->id,
>>> -				  req, size);
>>> +	struct rpm_regulator_req req[3];
>>> +	int reqlen = 0;
>>> +	int ret;
>>> +
>>> +	if (vreg->enabled_updated) {
>>> +		req[reqlen].key = cpu_to_le32(RPM_KEY_SWEN);
>>> +		req[reqlen].nbytes = cpu_to_le32(sizeof(u32));
>>> +		req[reqlen].value = cpu_to_le32(vreg->is_enabled);
>>> +		reqlen++;
>>> +	}
>>> +
>>> +	if (vreg->uv_updated && vreg->is_enabled) {
>>> +		req[reqlen].key = cpu_to_le32(RPM_KEY_UV);
>>> +		req[reqlen].nbytes = cpu_to_le32(sizeof(u32));
>>> +		req[reqlen].value = cpu_to_le32(vreg->uV);
>>> +		reqlen++;
>>> +	}
>>> +
>>> +	if (vreg->load_updated && vreg->is_enabled) {
>>> +		req[reqlen].key = cpu_to_le32(RPM_KEY_MA);
>>> +		req[reqlen].nbytes = cpu_to_le32(sizeof(u32));
>>> +		req[reqlen].value = cpu_to_le32(vreg->load / 1000);
>>> +		reqlen++;
>>> +	}
>>> +
>>> +	if (!reqlen)
>>> +		return 0;
>>> +
>>> +	ret = qcom_rpm_smd_write(vreg->rpm, QCOM_SMD_RPM_ACTIVE_STATE,
>>> +				 vreg->type, vreg->id,
>>> +				 req, sizeof(req[0]) * reqlen);
>>> +	if (!ret) {
>>> +		vreg->enabled_updated = 0;
>>> +		vreg->uv_updated = 0;
>>> +		vreg->load_updated = 0;
>>> +	}
>>> +
>>> +	return ret;
>>>    }
>>>    static int rpm_reg_enable(struct regulator_dev *rdev)
>>>    {
>>>    	struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
>>> -	struct rpm_regulator_req req;
>>>    	int ret;
>>> -	req.key = cpu_to_le32(RPM_KEY_SWEN);
>>> -	req.nbytes = cpu_to_le32(sizeof(u32));
>>> -	req.value = cpu_to_le32(1);
>>> +	vreg->is_enabled = 1;
>>> +	vreg->enabled_updated = 1;
>>> -	ret = rpm_reg_write_active(vreg, &req, sizeof(req));
>>> -	if (!ret)
>>> -		vreg->is_enabled = 1;
>>> +	ret = rpm_reg_write_active(vreg);
>>> +	if (ret)
>>> +		vreg->is_enabled = 0;
>>>    	return ret;
>>>    }
>>> @@ -81,16 +115,14 @@ static int rpm_reg_is_enabled(struct regulator_dev *rdev)
>>>    static int rpm_reg_disable(struct regulator_dev *rdev)
>>>    {
>>>    	struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
>>> -	struct rpm_regulator_req req;
>>>    	int ret;
>>> -	req.key = cpu_to_le32(RPM_KEY_SWEN);
>>> -	req.nbytes = cpu_to_le32(sizeof(u32));
>>> -	req.value = 0;
>>> +	vreg->is_enabled = 0;
>>> +	vreg->enabled_updated = 1;
>>> -	ret = rpm_reg_write_active(vreg, &req, sizeof(req));
>>> -	if (!ret)
>>> -		vreg->is_enabled = 0;
>>> +	ret = rpm_reg_write_active(vreg);
>>> +	if (ret)
>>> +		vreg->is_enabled = 1;
>>>    	return ret;
>>>    }
>>> @@ -108,16 +140,15 @@ static int rpm_reg_set_voltage(struct regulator_dev *rdev,
>>>    			       unsigned *selector)
>>>    {
>>>    	struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
>>> -	struct rpm_regulator_req req;
>>> -	int ret = 0;
>>> +	int ret;
>>> +	int old_uV = vreg->uV;
>>> -	req.key = cpu_to_le32(RPM_KEY_UV);
>>> -	req.nbytes = cpu_to_le32(sizeof(u32));
>>> -	req.value = cpu_to_le32(min_uV);
>>> +	vreg->uV = min_uV;
>>> +	vreg->uv_updated = 1;
>>> -	ret = rpm_reg_write_active(vreg, &req, sizeof(req));
>>> -	if (!ret)
>>> -		vreg->uV = min_uV;
>>> +	ret = rpm_reg_write_active(vreg);
>>> +	if (ret)
>>> +		vreg->uV = old_uV;
>>>    	return ret;
>>>    }
>>> @@ -125,13 +156,16 @@ static int rpm_reg_set_voltage(struct regulator_dev *rdev,
>>>    static int rpm_reg_set_load(struct regulator_dev *rdev, int load_uA)
>>>    {
>>>    	struct qcom_rpm_reg *vreg = rdev_get_drvdata(rdev);
>>> -	struct rpm_regulator_req req;
>>> +	u32 old_load = vreg->load;
>>> +	int ret;
>>> -	req.key = cpu_to_le32(RPM_KEY_MA);
>>> -	req.nbytes = cpu_to_le32(sizeof(u32));
>>> -	req.value = cpu_to_le32(load_uA / 1000);
>>> +	vreg->load = load_uA;
>>> +	vreg->load_updated = 1;
>>> +	ret = rpm_reg_write_active(vreg);
>>> +	if (ret)
>>> +		vreg->load = old_load;
>>> -	return rpm_reg_write_active(vreg, &req, sizeof(req));
>>> +	return ret;
>>>    }
>>>    static const struct regulator_ops rpm_smps_ldo_ops = {
>>>
>>
>>
>> -- 
>> Jeffrey Hugo
>> Qualcomm Datacenter Technologies as an affiliate of Qualcomm Technologies,
>> Inc.
>> Qualcomm Technologies, Inc. is a member of the
>> Code Aurora Forum, a Linux Foundation Collaborative Project.


-- 
Jeffrey Hugo
Qualcomm Datacenter Technologies as an affiliate of Qualcomm 
Technologies, Inc.
Qualcomm Technologies, Inc. is a member of the
Code Aurora Forum, a Linux Foundation Collaborative Project.

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ