* [PATCH] i2c: i2c-qcom-geni: Serve transfer during early resume stage
@ 2024-04-02 10:27 Mukesh Kumar Savaliya
2024-09-12 10:02 ` Andi Shyti
2024-09-13 2:54 ` Bjorn Andersson
0 siblings, 2 replies; 5+ messages in thread
From: Mukesh Kumar Savaliya @ 2024-04-02 10:27 UTC (permalink / raw)
To: konrad.dybcio, andersson, andi.shyti, linux-arm-msm, linux-kernel,
linux-i2c
Cc: quic_vdadhani, vkoul, Mukesh Kumar Savaliya
pm_runtime_get_sync() function fails during PM early resume and returning
-EACCES because runtime PM for the device is disabled at the early stage
causing i2c transfer to fail. Make changes to serve transfer with force
resume.
1. Register interrupt with IRQF_EARLY_RESUME and IRQF_NO_SUSPEND flags
to avoid timeout of transfer when IRQ is not enabled during early stage.
2. Do force resume if pm_runtime_get_sync() is failing after system
suspend when runtime PM is not enabled.
3. Increment power usage count after forced resume to balance
it against regular runtime suspend.
Co-developed-by: Viken Dadhaniya <quic_vdadhani@quicinc.com>
Signed-off-by: Viken Dadhaniya <quic_vdadhani@quicinc.com>
Signed-off-by: Mukesh Kumar Savaliya <quic_msavaliy@quicinc.com>
---
v1 -> v2:
- Changed gi2c->se.dev to dev during dev_dbg() calls.
- Addressed review comments from Andi.
---
drivers/i2c/busses/i2c-qcom-geni.c | 55 ++++++++++++++++++++++++------
1 file changed, 45 insertions(+), 10 deletions(-)
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index da94df466e83..30c335b02ac4 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -134,6 +134,8 @@ struct geni_i2c_clk_fld {
u8 t_cycle_cnt;
};
+static int geni_i2c_runtime_resume(struct device *dev);
+
/*
* Hardware uses the underlying formula to calculate time periods of
* SCL clock cycle. Firmware uses some additional cycles excluded from the
@@ -677,22 +679,48 @@ static int geni_i2c_fifo_xfer(struct geni_i2c_dev *gi2c,
return num;
}
+static int geni_i2c_force_resume(struct geni_i2c_dev *gi2c)
+{
+ struct device *dev = gi2c->se.dev;
+ int ret;
+
+ ret = geni_i2c_runtime_resume(dev);
+ if (ret) {
+ dev_err(gi2c->se.dev, "Error turning SE resources:%d\n", ret);
+ pm_runtime_put_noidle(dev);
+ pm_runtime_set_suspended(dev);
+ return ret;
+ }
+ pm_runtime_get_noresume(dev);
+ pm_runtime_set_active(dev);
+ return ret;
+}
+
static int geni_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg msgs[],
int num)
{
struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap);
+ struct device *dev = gi2c->se.dev;
int ret;
gi2c->err = 0;
reinit_completion(&gi2c->done);
- ret = pm_runtime_get_sync(gi2c->se.dev);
- if (ret < 0) {
- dev_err(gi2c->se.dev, "error turning SE resources:%d\n", ret);
- pm_runtime_put_noidle(gi2c->se.dev);
- /* Set device in suspended since resume failed */
- pm_runtime_set_suspended(gi2c->se.dev);
- return ret;
+
+ if (!pm_runtime_enabled(dev) && gi2c->suspended) {
+ dev_dbg(dev, "RT_PM disabled, Do force resume, pm_usage_count: %d\n",
+ atomic_read(&dev->power.usage_count));
+ ret = geni_i2c_force_resume(gi2c);
+ if (ret)
+ return ret;
+ } else {
+ ret = pm_runtime_get_sync(dev);
+ if (ret == -EACCES && gi2c->suspended) {
+ dev_dbg(dev, "PM get_sync() failed-%d, force resume\n", ret);
+ ret = geni_i2c_force_resume(gi2c);
+ if (ret)
+ return ret;
+ }
}
qcom_geni_i2c_conf(gi2c);
@@ -702,8 +730,15 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
else
ret = geni_i2c_fifo_xfer(gi2c, msgs, num);
- pm_runtime_mark_last_busy(gi2c->se.dev);
- pm_runtime_put_autosuspend(gi2c->se.dev);
+ if (!pm_runtime_enabled(dev) && !gi2c->suspended) {
+ pm_runtime_put_noidle(dev);
+ pm_runtime_set_suspended(dev);
+ gi2c->suspended = 0;
+ } else {
+ pm_runtime_mark_last_busy(gi2c->se.dev);
+ pm_runtime_put_autosuspend(gi2c->se.dev);
+ }
+
gi2c->cur = NULL;
gi2c->err = 0;
return ret;
@@ -820,7 +855,7 @@ static int geni_i2c_probe(struct platform_device *pdev)
init_completion(&gi2c->done);
spin_lock_init(&gi2c->lock);
platform_set_drvdata(pdev, gi2c);
- ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, 0,
+ ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, IRQF_EARLY_RESUME | IRQF_NO_SUSPEND,
dev_name(dev), gi2c);
if (ret) {
dev_err(dev, "Request_irq failed:%d: err:%d\n",
--
2.25.1
^ permalink raw reply related [flat|nested] 5+ messages in thread* Re: [PATCH] i2c: i2c-qcom-geni: Serve transfer during early resume stage
2024-04-02 10:27 [PATCH] i2c: i2c-qcom-geni: Serve transfer during early resume stage Mukesh Kumar Savaliya
@ 2024-09-12 10:02 ` Andi Shyti
2024-09-27 12:19 ` Mukesh Kumar Savaliya
2024-09-13 2:54 ` Bjorn Andersson
1 sibling, 1 reply; 5+ messages in thread
From: Andi Shyti @ 2024-09-12 10:02 UTC (permalink / raw)
To: Mukesh Kumar Savaliya
Cc: konrad.dybcio, andersson, linux-arm-msm, linux-kernel, linux-i2c,
quic_vdadhani, vkoul
Hi Mukesh,
Is this patch still needed? Can anyone active in the Qualcomm
drivers take a look?
On Tue, Apr 02, 2024 at 03:57:41PM GMT, Mukesh Kumar Savaliya wrote:
> pm_runtime_get_sync() function fails during PM early resume and returning
> -EACCES because runtime PM for the device is disabled at the early stage
> causing i2c transfer to fail. Make changes to serve transfer with force
> resume.
>
> 1. Register interrupt with IRQF_EARLY_RESUME and IRQF_NO_SUSPEND flags
> to avoid timeout of transfer when IRQ is not enabled during early stage.
> 2. Do force resume if pm_runtime_get_sync() is failing after system
> suspend when runtime PM is not enabled.
> 3. Increment power usage count after forced resume to balance
> it against regular runtime suspend.
>
> Co-developed-by: Viken Dadhaniya <quic_vdadhani@quicinc.com>
> Signed-off-by: Viken Dadhaniya <quic_vdadhani@quicinc.com>
> Signed-off-by: Mukesh Kumar Savaliya <quic_msavaliy@quicinc.com>
Should this be considered a fix?
Thanks,
Andi
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] i2c: i2c-qcom-geni: Serve transfer during early resume stage
2024-09-12 10:02 ` Andi Shyti
@ 2024-09-27 12:19 ` Mukesh Kumar Savaliya
0 siblings, 0 replies; 5+ messages in thread
From: Mukesh Kumar Savaliya @ 2024-09-27 12:19 UTC (permalink / raw)
To: Andi Shyti
Cc: konrad.dybcio, andersson, linux-arm-msm, linux-kernel, linux-i2c,
quic_vdadhani, vkoul
Hi Andi, sorry. Yes this is active. let me push V2 addressing comments
for V1. i was completely away earlier hence restarting now.
On 9/12/2024 3:32 PM, Andi Shyti wrote:
> Hi Mukesh,
>
> Is this patch still needed? Can anyone active in the Qualcomm
> drivers take a look?
>
> On Tue, Apr 02, 2024 at 03:57:41PM GMT, Mukesh Kumar Savaliya wrote:
>> pm_runtime_get_sync() function fails during PM early resume and returning
>> -EACCES because runtime PM for the device is disabled at the early stage
>> causing i2c transfer to fail. Make changes to serve transfer with force
>> resume.
>>
>> 1. Register interrupt with IRQF_EARLY_RESUME and IRQF_NO_SUSPEND flags
>> to avoid timeout of transfer when IRQ is not enabled during early stage.
>> 2. Do force resume if pm_runtime_get_sync() is failing after system
>> suspend when runtime PM is not enabled.
>> 3. Increment power usage count after forced resume to balance
>> it against regular runtime suspend.
>>
>> Co-developed-by: Viken Dadhaniya <quic_vdadhani@quicinc.com>
>> Signed-off-by: Viken Dadhaniya <quic_vdadhani@quicinc.com>
>> Signed-off-by: Mukesh Kumar Savaliya <quic_msavaliy@quicinc.com>
>
> Should this be considered a fix?
>
> Thanks,
> Andi
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] i2c: i2c-qcom-geni: Serve transfer during early resume stage
2024-04-02 10:27 [PATCH] i2c: i2c-qcom-geni: Serve transfer during early resume stage Mukesh Kumar Savaliya
2024-09-12 10:02 ` Andi Shyti
@ 2024-09-13 2:54 ` Bjorn Andersson
2024-09-27 12:32 ` Mukesh Kumar Savaliya
1 sibling, 1 reply; 5+ messages in thread
From: Bjorn Andersson @ 2024-09-13 2:54 UTC (permalink / raw)
To: Mukesh Kumar Savaliya
Cc: konrad.dybcio, andersson, andi.shyti, linux-arm-msm, linux-kernel,
linux-i2c, quic_vdadhani, vkoul
On Tue, Apr 02, 2024 at 03:57:41PM +0530, Mukesh Kumar Savaliya wrote:
> pm_runtime_get_sync() function fails during PM early resume and returning
> -EACCES because runtime PM for the device is disabled at the early stage
> causing i2c transfer to fail. Make changes to serve transfer with force
> resume.
>
I'm guessing that this is caused by some other driver that wants to
perform an I2C access during early resume? If so, can you describe what
that use case is?
Regards,
Bjorn
> 1. Register interrupt with IRQF_EARLY_RESUME and IRQF_NO_SUSPEND flags
> to avoid timeout of transfer when IRQ is not enabled during early stage.
> 2. Do force resume if pm_runtime_get_sync() is failing after system
> suspend when runtime PM is not enabled.
> 3. Increment power usage count after forced resume to balance
> it against regular runtime suspend.
>
> Co-developed-by: Viken Dadhaniya <quic_vdadhani@quicinc.com>
> Signed-off-by: Viken Dadhaniya <quic_vdadhani@quicinc.com>
> Signed-off-by: Mukesh Kumar Savaliya <quic_msavaliy@quicinc.com>
> ---
> v1 -> v2:
> - Changed gi2c->se.dev to dev during dev_dbg() calls.
> - Addressed review comments from Andi.
> ---
> drivers/i2c/busses/i2c-qcom-geni.c | 55 ++++++++++++++++++++++++------
> 1 file changed, 45 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
> index da94df466e83..30c335b02ac4 100644
> --- a/drivers/i2c/busses/i2c-qcom-geni.c
> +++ b/drivers/i2c/busses/i2c-qcom-geni.c
> @@ -134,6 +134,8 @@ struct geni_i2c_clk_fld {
> u8 t_cycle_cnt;
> };
>
> +static int geni_i2c_runtime_resume(struct device *dev);
> +
> /*
> * Hardware uses the underlying formula to calculate time periods of
> * SCL clock cycle. Firmware uses some additional cycles excluded from the
> @@ -677,22 +679,48 @@ static int geni_i2c_fifo_xfer(struct geni_i2c_dev *gi2c,
> return num;
> }
>
> +static int geni_i2c_force_resume(struct geni_i2c_dev *gi2c)
> +{
> + struct device *dev = gi2c->se.dev;
> + int ret;
> +
> + ret = geni_i2c_runtime_resume(dev);
> + if (ret) {
> + dev_err(gi2c->se.dev, "Error turning SE resources:%d\n", ret);
> + pm_runtime_put_noidle(dev);
> + pm_runtime_set_suspended(dev);
> + return ret;
> + }
> + pm_runtime_get_noresume(dev);
> + pm_runtime_set_active(dev);
> + return ret;
> +}
> +
> static int geni_i2c_xfer(struct i2c_adapter *adap,
> struct i2c_msg msgs[],
> int num)
> {
> struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap);
> + struct device *dev = gi2c->se.dev;
> int ret;
>
> gi2c->err = 0;
> reinit_completion(&gi2c->done);
> - ret = pm_runtime_get_sync(gi2c->se.dev);
> - if (ret < 0) {
> - dev_err(gi2c->se.dev, "error turning SE resources:%d\n", ret);
> - pm_runtime_put_noidle(gi2c->se.dev);
> - /* Set device in suspended since resume failed */
> - pm_runtime_set_suspended(gi2c->se.dev);
> - return ret;
> +
> + if (!pm_runtime_enabled(dev) && gi2c->suspended) {
> + dev_dbg(dev, "RT_PM disabled, Do force resume, pm_usage_count: %d\n",
> + atomic_read(&dev->power.usage_count));
> + ret = geni_i2c_force_resume(gi2c);
> + if (ret)
> + return ret;
> + } else {
> + ret = pm_runtime_get_sync(dev);
> + if (ret == -EACCES && gi2c->suspended) {
> + dev_dbg(dev, "PM get_sync() failed-%d, force resume\n", ret);
> + ret = geni_i2c_force_resume(gi2c);
> + if (ret)
> + return ret;
> + }
> }
>
> qcom_geni_i2c_conf(gi2c);
> @@ -702,8 +730,15 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
> else
> ret = geni_i2c_fifo_xfer(gi2c, msgs, num);
>
> - pm_runtime_mark_last_busy(gi2c->se.dev);
> - pm_runtime_put_autosuspend(gi2c->se.dev);
> + if (!pm_runtime_enabled(dev) && !gi2c->suspended) {
> + pm_runtime_put_noidle(dev);
> + pm_runtime_set_suspended(dev);
> + gi2c->suspended = 0;
> + } else {
> + pm_runtime_mark_last_busy(gi2c->se.dev);
> + pm_runtime_put_autosuspend(gi2c->se.dev);
> + }
> +
> gi2c->cur = NULL;
> gi2c->err = 0;
> return ret;
> @@ -820,7 +855,7 @@ static int geni_i2c_probe(struct platform_device *pdev)
> init_completion(&gi2c->done);
> spin_lock_init(&gi2c->lock);
> platform_set_drvdata(pdev, gi2c);
> - ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, 0,
> + ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, IRQF_EARLY_RESUME | IRQF_NO_SUSPEND,
> dev_name(dev), gi2c);
> if (ret) {
> dev_err(dev, "Request_irq failed:%d: err:%d\n",
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] i2c: i2c-qcom-geni: Serve transfer during early resume stage
2024-09-13 2:54 ` Bjorn Andersson
@ 2024-09-27 12:32 ` Mukesh Kumar Savaliya
0 siblings, 0 replies; 5+ messages in thread
From: Mukesh Kumar Savaliya @ 2024-09-27 12:32 UTC (permalink / raw)
To: Bjorn Andersson
Cc: konrad.dybcio, andersson, andi.shyti, linux-arm-msm, linux-kernel,
linux-i2c, quic_vdadhani, vkoul
Hi Bjorn,
On 9/13/2024 8:24 AM, Bjorn Andersson wrote:
> On Tue, Apr 02, 2024 at 03:57:41PM +0530, Mukesh Kumar Savaliya wrote:
>> pm_runtime_get_sync() function fails during PM early resume and returning
>> -EACCES because runtime PM for the device is disabled at the early stage
>> causing i2c transfer to fail. Make changes to serve transfer with force
>> resume.
>>
>
> I'm guessing that this is caused by some other driver that wants to
> perform an I2C access during early resume? If so, can you describe what
> that use case is?
>
Yes, PCIe is a client driver and uses i2c for transfer during very early
stage. We could not serve transfer request since runtime PM was not
active during early resume. We plan to support the similar request from
any client, hence the change.
I am planning to push V2 very soon. i was late here.
> Regards,
> Bjorn
>
>> 1. Register interrupt with IRQF_EARLY_RESUME and IRQF_NO_SUSPEND flags
>> to avoid timeout of transfer when IRQ is not enabled during early stage.
>> 2. Do force resume if pm_runtime_get_sync() is failing after system
>> suspend when runtime PM is not enabled.
>> 3. Increment power usage count after forced resume to balance
>> it against regular runtime suspend.
>>
>> Co-developed-by: Viken Dadhaniya <quic_vdadhani@quicinc.com>
>> Signed-off-by: Viken Dadhaniya <quic_vdadhani@quicinc.com>
>> Signed-off-by: Mukesh Kumar Savaliya <quic_msavaliy@quicinc.com>
>> ---
>> v1 -> v2:
>> - Changed gi2c->se.dev to dev during dev_dbg() calls.
>> - Addressed review comments from Andi.
>> ---
>> drivers/i2c/busses/i2c-qcom-geni.c | 55 ++++++++++++++++++++++++------
>> 1 file changed, 45 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
>> index da94df466e83..30c335b02ac4 100644
>> --- a/drivers/i2c/busses/i2c-qcom-geni.c
>> +++ b/drivers/i2c/busses/i2c-qcom-geni.c
>> @@ -134,6 +134,8 @@ struct geni_i2c_clk_fld {
>> u8 t_cycle_cnt;
>> };
>>
>> +static int geni_i2c_runtime_resume(struct device *dev);
>> +
>> /*
>> * Hardware uses the underlying formula to calculate time periods of
>> * SCL clock cycle. Firmware uses some additional cycles excluded from the
>> @@ -677,22 +679,48 @@ static int geni_i2c_fifo_xfer(struct geni_i2c_dev *gi2c,
>> return num;
>> }
>>
>> +static int geni_i2c_force_resume(struct geni_i2c_dev *gi2c)
>> +{
>> + struct device *dev = gi2c->se.dev;
>> + int ret;
>> +
>> + ret = geni_i2c_runtime_resume(dev);
>> + if (ret) {
>> + dev_err(gi2c->se.dev, "Error turning SE resources:%d\n", ret);
>> + pm_runtime_put_noidle(dev);
>> + pm_runtime_set_suspended(dev);
>> + return ret;
>> + }
>> + pm_runtime_get_noresume(dev);
>> + pm_runtime_set_active(dev);
>> + return ret;
>> +}
>> +
>> static int geni_i2c_xfer(struct i2c_adapter *adap,
>> struct i2c_msg msgs[],
>> int num)
>> {
>> struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap);
>> + struct device *dev = gi2c->se.dev;
>> int ret;
>>
>> gi2c->err = 0;
>> reinit_completion(&gi2c->done);
>> - ret = pm_runtime_get_sync(gi2c->se.dev);
>> - if (ret < 0) {
>> - dev_err(gi2c->se.dev, "error turning SE resources:%d\n", ret);
>> - pm_runtime_put_noidle(gi2c->se.dev);
>> - /* Set device in suspended since resume failed */
>> - pm_runtime_set_suspended(gi2c->se.dev);
>> - return ret;
>> +
>> + if (!pm_runtime_enabled(dev) && gi2c->suspended) {
>> + dev_dbg(dev, "RT_PM disabled, Do force resume, pm_usage_count: %d\n",
>> + atomic_read(&dev->power.usage_count));
>> + ret = geni_i2c_force_resume(gi2c);
>> + if (ret)
>> + return ret;
>> + } else {
>> + ret = pm_runtime_get_sync(dev);
>> + if (ret == -EACCES && gi2c->suspended) {
>> + dev_dbg(dev, "PM get_sync() failed-%d, force resume\n", ret);
>> + ret = geni_i2c_force_resume(gi2c);
>> + if (ret)
>> + return ret;
>> + }
>> }
>>
>> qcom_geni_i2c_conf(gi2c);
>> @@ -702,8 +730,15 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
>> else
>> ret = geni_i2c_fifo_xfer(gi2c, msgs, num);
>>
>> - pm_runtime_mark_last_busy(gi2c->se.dev);
>> - pm_runtime_put_autosuspend(gi2c->se.dev);
>> + if (!pm_runtime_enabled(dev) && !gi2c->suspended) {
>> + pm_runtime_put_noidle(dev);
>> + pm_runtime_set_suspended(dev);
>> + gi2c->suspended = 0;
>> + } else {
>> + pm_runtime_mark_last_busy(gi2c->se.dev);
>> + pm_runtime_put_autosuspend(gi2c->se.dev);
>> + }
>> +
>> gi2c->cur = NULL;
>> gi2c->err = 0;
>> return ret;
>> @@ -820,7 +855,7 @@ static int geni_i2c_probe(struct platform_device *pdev)
>> init_completion(&gi2c->done);
>> spin_lock_init(&gi2c->lock);
>> platform_set_drvdata(pdev, gi2c);
>> - ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, 0,
>> + ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, IRQF_EARLY_RESUME | IRQF_NO_SUSPEND,
>> dev_name(dev), gi2c);
>> if (ret) {
>> dev_err(dev, "Request_irq failed:%d: err:%d\n",
>> --
>> 2.25.1
>>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2024-09-27 12:32 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-04-02 10:27 [PATCH] i2c: i2c-qcom-geni: Serve transfer during early resume stage Mukesh Kumar Savaliya
2024-09-12 10:02 ` Andi Shyti
2024-09-27 12:19 ` Mukesh Kumar Savaliya
2024-09-13 2:54 ` Bjorn Andersson
2024-09-27 12:32 ` Mukesh Kumar Savaliya
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox