From: Alex Elder <hidden> Date: 2021-08-19 22:19:35
This series replaces the remaining uses of ipa_clock_get() with
calls to pm_runtime_get_sync() instead. It replaces all calls to
ipa_clock_put() with calls to pm_runtime_put().
This completes the preparation for enabling automated suspend under
the control of the power management core code. The next patch (in
an upcoming series) enables that. Then the "ipa_clock" files and
symbols will switch to using an "ipa_power" naming convention instead.
Additional info
It is possible for pm_runtime_get_sync() to return an error. There
are really three cases, identified by return value:
- 1, meaning power was already active
- 0, meaning power was not previously active, but is now
- EACCES, meaning runtime PM is disabled
One additional case is EINVAL, meaning a previous suspend or resume
(or idle) call returned an error. But we have always assumed this
won't happen (we previously didn't even check for an error).
But because we use pm_runtime_force_suspend() to implement system
suspend, there's a chance we'd get an EACCES error (the first thing
that function does is disable runtime suspend). Individual patches
explain what happens in that case, but generally we just accept that
it could be an unlikely problem (occurring only at startup time).
Similarly, pm_runtime_put() could return an error. There too, we
ignore EINVAL, assuming the IPA suspend and resume operations won't
produce an error. EBUSY and EPERM are not applicable, EAGAIN is not
expected (and harmless). We should never get EACCES (runtime
suspend disabled), because pm_runtime_put() calls match prior
pm_runtime_get_sync() calls, and a system suspend will not be
started while a runtime suspend or resume is underway. In summary,
the value returned from pm_runtime_put() is not meaningful, so we
explicitly ignore it.
-Alex
Alex Elder (5):
net: ipa: don't use ipa_clock_get() in "ipa_main.c"
net: ipa: don't use ipa_clock_get() in "ipa_smp2p.c"
net: ipa: don't use ipa_clock_get() in "ipa_uc.c"
net: ipa: don't use ipa_clock_get() in "ipa_modem.c"
net: ipa: kill ipa_clock_get()
drivers/net/ipa/ipa_clock.c | 17 --------------
drivers/net/ipa/ipa_clock.h | 24 --------------------
drivers/net/ipa/ipa_interrupt.c | 14 ++++++------
drivers/net/ipa/ipa_main.c | 21 ++++++++---------
drivers/net/ipa/ipa_modem.c | 40 +++++++++++++++++++--------------
drivers/net/ipa/ipa_smp2p.c | 19 +++++++++-------
drivers/net/ipa/ipa_uc.c | 22 ++++++++++--------
7 files changed, 65 insertions(+), 92 deletions(-)
--
2.27.0
From: Alex Elder <hidden> Date: 2021-08-19 22:19:40
We need the hardware to be powered starting at the config stage of
initialization when the IPA driver probes. And we need it powered
when the driver is removed, at least until the deconfig stage has
completed.
Replace callers of ipa_clock_get() in ipa_probe() and ipa_exit(),
calling pm_runtime_get_sync() instead. Replace the corresponding
callers of ipa_clock_put(), calling pm_runtime_put() instead.
The only error we expect when getting power would occur when the
system is suspended. The ->probe and ->remove driver callbacks
won't be called when suspended, so issue a WARN() call if an error
is seen getting power.
Signed-off-by: Alex Elder <redacted>
---
drivers/net/ipa/ipa_main.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
@@ -737,13 +738,13 @@ static int ipa_probe(struct platform_device *pdev)gotoerr_table_exit;/* The clock needs to be active for config and setup */-ret=ipa_clock_get(ipa);+ret=pm_runtime_get_sync(dev);if(WARN_ON(ret<0))-gotoerr_clock_put;+gotoerr_power_put;ret=ipa_config(ipa,data);if(ret)-gotoerr_clock_put;+gotoerr_power_put;dev_info(dev,"IPA driver initialized");
@@ -765,14 +766,14 @@ static int ipa_probe(struct platform_device *pdev)if(ret)gotoerr_deconfig;done:-(void)ipa_clock_put(ipa);+(void)pm_runtime_put(dev);return0;err_deconfig:ipa_deconfig(ipa);-err_clock_put:-(void)ipa_clock_put(ipa);+err_power_put:+(void)pm_runtime_put(dev);ipa_modem_exit(ipa);err_table_exit:ipa_table_exit(ipa);
@@ -798,9 +799,9 @@ static int ipa_remove(struct platform_device *pdev)structipa_clock*clock=ipa->clock;intret;-ret=ipa_clock_get(ipa);+ret=pm_runtime_get_sync(&pdev->dev);if(WARN_ON(ret<0))-gotoout_clock_put;+gotoout_power_put;if(ipa->setup_complete){ret=ipa_modem_stop(ipa);
@@ -816,8 +817,8 @@ static int ipa_remove(struct platform_device *pdev)}ipa_deconfig(ipa);-out_clock_put:-(void)ipa_clock_put(ipa);+out_power_put:+(void)pm_runtime_put(&pdev->dev);ipa_modem_exit(ipa);ipa_table_exit(ipa);
From: Alex Elder <hidden> Date: 2021-08-19 22:19:43
If the "modem-init" Device Tree property is present for a platform,
the modem performs early IPA hardware initialization, and signals
this is complete with an "ipa-setup-ready" SMP2P interrupt. This
triggers a call to ipa_setup(), which requires the hardware to be
powered.
Replace the call to ipa_clock_get() in this case with a call to
pm_runtime_get_sync(). And replace the corresponding calls to
ipa_clock_put() with calls to pm_runtime_put() instead.
There is a chance we get an error when taking this power reference.
This is an unlikely scenario, where system suspend is initiated just
before the modem signals it has finished initializing the IPA
hardware. For now we'll just accept that this could occur, and
report it if it does.
Signed-off-by: Alex Elder <redacted>
---
drivers/net/ipa/ipa_smp2p.c | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
@@ -161,17 +161,20 @@ static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id)gotoout_mutex_unlock;smp2p->disabled=true;/* If any others arrive, ignore them */-/* The clock needs to be active for setup */-ret=ipa_clock_get(smp2p->ipa);-if(WARN_ON(ret<0))-gotoout_clock_put;+/* Power needs to be active for setup */+dev=&smp2p->ipa->pdev->dev;+ret=pm_runtime_get_sync(dev);+if(ret<0){+dev_err(dev,"error %d getting power for setup\n",ret);+gotoout_power_put;+}/* An error here won't cause driver shutdown, so warn if one occurs */ret=ipa_setup(smp2p->ipa);WARN(ret!=0,"error %d from ipa_setup()\n",ret);-out_clock_put:-(void)ipa_clock_put(smp2p->ipa);+out_power_put:+(void)pm_runtime_put(dev);out_mutex_unlock:mutex_unlock(&smp2p->mutex);
From: Alex Elder <hidden> Date: 2021-08-19 22:19:47
Replace the ipa_clock_get() call in ipa_uc_clock() when taking the
"proxy" clock reference for the microcontroller with a call to
pm_runtime_get_sync(). Replace calls of ipa_clock_put() for the
microcontroller with pm_runtime_put() calls instead.
There is a chance we get an error when taking the microcontroller
power reference. This is an unlikely scenario, where system suspend
is initiated just before we learn the modem is booting. For now
we'll just accept that this could occur, and report it if it does.
Signed-off-by: Alex Elder <redacted>
---
drivers/net/ipa/ipa_uc.c | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
@@ -182,25 +182,29 @@ void ipa_uc_deconfig(struct ipa *ipa)ipa_interrupt_remove(ipa->interrupt,IPA_IRQ_UC_1);ipa_interrupt_remove(ipa->interrupt,IPA_IRQ_UC_0);if(ipa->uc_clocked)-(void)ipa_clock_put(ipa);+(void)pm_runtime_put(&ipa->pdev->dev);}/* Take a proxy clock reference for the microcontroller */voidipa_uc_clock(structipa*ipa){staticboolalready;+structdevice*dev;intret;if(already)return;already=true;/* Only do this on first boot */-/* This clock reference dropped in ipa_uc_response_hdlr() above */-ret=ipa_clock_get(ipa);-if(WARN(ret<0,"error %d getting proxy clock\n",ret))-(void)ipa_clock_put(ipa);--ipa->uc_clocked=ret>=0;+/* This power reference dropped in ipa_uc_response_hdlr() above */+dev=&ipa->pdev->dev;+ret=pm_runtime_get_sync(dev);+if(ret<0){+pm_runtime_put_noidle(dev);+dev_err(dev,"error %d getting proxy power\n",ret);+}else{+ipa->uc_clocked=true;+}}/* Send a command to the microcontroller */
From: Alex Elder <hidden> Date: 2021-08-19 22:19:50
When we open or close the modem network device we need to ensure the
hardware is powered. Replace the callers of ipa_clock_get() found
in ipa_open() and ipa_stop() with calls to pm_runtime_get_sync().
If an error is returned, simply return that error to the caller
(without any error or warning message). This could conceivably
occur if the function was called while the system was suspended,
but that really shouldn't happen. Replace corresponding calls to
ipa_clock_put() with pm_runtime_put() also.
If the modem crashes we also need to ensure the hardware is powered
to recover. If getting power returns an error there's not much we
can do, but at least report the error. (Ideally the remoteproc SSR
code would ensure the AP was not suspended when it sends the
notification, but that is not (yet) the case.)
Signed-off-by: Alex Elder <redacted>
---
drivers/net/ipa/ipa_modem.c | 40 +++++++++++++++++++++----------------
1 file changed, 23 insertions(+), 17 deletions(-)
From: Alex Elder <hidden> Date: 2021-08-19 22:19:52
The only remaining user of the ipa_clock_{get,put}() interface is
ipa_isr_thread(). Replace calls to ipa_clock_get() there calling
pm_runtime_get_sync() instead. And call pm_runtime_put() there
rather than ipa_clock_put(). Warn if we ever get an error.
With that, we can get rid of ipa_clock_get() and ipa_clock_put().
Signed-off-by: Alex Elder <redacted>
---
drivers/net/ipa/ipa_clock.c | 17 -----------------
drivers/net/ipa/ipa_clock.h | 24 ------------------------
drivers/net/ipa/ipa_interrupt.c | 14 +++++++-------
3 files changed, 7 insertions(+), 48 deletions(-)
@@ -266,23 +266,6 @@ static int ipa_runtime_idle(struct device *dev)return-EAGAIN;}-/* Get an IPA clock reference. If the reference count is non-zero, it is-*incrementedandreturnisimmediate.OtherwisetheIPAclockis-*enabled.-*/-intipa_clock_get(structipa*ipa)-{-returnpm_runtime_get_sync(&ipa->pdev->dev);-}--/* Attempt to remove an IPA clock reference. If this represents the-*lastreference,disabletheIPAclock.-*/-intipa_clock_put(structipa*ipa)-{-returnpm_runtime_put(&ipa->pdev->dev);-}-staticintipa_suspend(structdevice*dev){structipa*ipa=dev_get_drvdata(dev);
@@ -80,14 +80,16 @@ static irqreturn_t ipa_isr_thread(int irq, void *dev_id)structipa_interrupt*interrupt=dev_id;structipa*ipa=interrupt->ipa;u32enabled=interrupt->enabled;+structdevice*dev;u32pending;u32offset;u32mask;intret;-ret=ipa_clock_get(ipa);+dev=&ipa->pdev->dev;+ret=pm_runtime_get_sync(dev);if(WARN_ON(ret<0))-gotoout_clock_put;+gotoout_power_put;/* The status register indicates which conditions are present,*includingconditionswhoseinterruptisnotenabled.Handle
@@ -108,15 +110,13 @@ static irqreturn_t ipa_isr_thread(int irq, void *dev_id)/* If any disabled interrupts are pending, clear them */if(pending){-structdevice*dev=&ipa->pdev->dev;-dev_dbg(dev,"clearing disabled IPA interrupts 0x%08x\n",pending);offset=ipa_reg_irq_clr_offset(ipa->version);iowrite32(pending,ipa->reg_virt+offset);}-out_clock_put:-(void)ipa_clock_put(ipa);+out_power_put:+(void)pm_runtime_put(dev);returnIRQ_HANDLED;}
Hello:
This series was applied to netdev/net-next.git (refs/heads/master):
On Thu, 19 Aug 2021 17:19:22 -0500 you wrote:
This series replaces the remaining uses of ipa_clock_get() with
calls to pm_runtime_get_sync() instead. It replaces all calls to
ipa_clock_put() with calls to pm_runtime_put().
This completes the preparation for enabling automated suspend under
the control of the power management core code. The next patch (in
an upcoming series) enables that. Then the "ipa_clock" files and
symbols will switch to using an "ipa_power" naming convention instead.
[...]