Commit c1125062 authored by David S. Miller's avatar David S. Miller

Merge branch 'ipa-kill-off-ipa_clock_get'

Alex Elder says:

====================
net: ipa: kill off ipa_clock_get()

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.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b8e36e13 c3f115aa
......@@ -272,23 +272,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
* incremented and return is immediate. Otherwise the IPA clock is
* enabled.
*/
int ipa_clock_get(struct ipa *ipa)
{
return pm_runtime_get_sync(&ipa->pdev->dev);
}
/* Attempt to remove an IPA clock reference. If this represents the
* last reference, disable the IPA clock.
*/
int ipa_clock_put(struct ipa *ipa)
{
return pm_runtime_put(&ipa->pdev->dev);
}
static int ipa_suspend(struct device *dev)
{
struct ipa *ipa = dev_get_drvdata(dev);
......
......@@ -70,28 +70,4 @@ struct ipa_clock *ipa_clock_init(struct device *dev,
*/
void ipa_clock_exit(struct ipa_clock *clock);
/**
* ipa_clock_get() - Get an IPA clock reference
* @ipa: IPA pointer
*
* Return: 0 if clock started, 1 if clock already running, or a negative
* error code
*
* This call blocks if this is the first reference. A reference is
* taken even if an error occurs starting the IPA clock.
*/
int ipa_clock_get(struct ipa *ipa);
/**
* ipa_clock_put() - Drop an IPA clock reference
* @ipa: IPA pointer
*
* Return: 0 if successful, or a negative error code
*
* This drops a clock reference. If the last reference is being dropped,
* the clock is stopped and RX endpoints are suspended. This call will
* not block unless the last reference is dropped.
*/
int ipa_clock_put(struct ipa *ipa);
#endif /* _IPA_CLOCK_H_ */
......@@ -21,9 +21,9 @@
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include "ipa.h"
#include "ipa_clock.h"
#include "ipa_reg.h"
#include "ipa_endpoint.h"
#include "ipa_interrupt.h"
......@@ -80,14 +80,16 @@ static irqreturn_t ipa_isr_thread(int irq, void *dev_id)
struct ipa_interrupt *interrupt = dev_id;
struct ipa *ipa = interrupt->ipa;
u32 enabled = interrupt->enabled;
struct device *dev;
u32 pending;
u32 offset;
u32 mask;
int ret;
ret = ipa_clock_get(ipa);
dev = &ipa->pdev->dev;
ret = pm_runtime_get_sync(dev);
if (WARN_ON(ret < 0))
goto out_clock_put;
goto out_power_put;
/* The status register indicates which conditions are present,
* including conditions whose interrupt is not enabled. 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) {
struct device *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);
return IRQ_HANDLED;
}
......
......@@ -15,6 +15,7 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/pm_runtime.h>
#include <linux/qcom_scm.h>
#include <linux/soc/qcom/mdt_loader.h>
......@@ -737,13 +738,13 @@ static int ipa_probe(struct platform_device *pdev)
goto err_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))
goto err_clock_put;
goto err_power_put;
ret = ipa_config(ipa, data);
if (ret)
goto err_clock_put;
goto err_power_put;
dev_info(dev, "IPA driver initialized");
......@@ -765,14 +766,14 @@ static int ipa_probe(struct platform_device *pdev)
if (ret)
goto err_deconfig;
done:
(void)ipa_clock_put(ipa);
(void)pm_runtime_put(dev);
return 0;
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)
struct ipa_clock *clock = ipa->clock;
int ret;
ret = ipa_clock_get(ipa);
ret = pm_runtime_get_sync(&pdev->dev);
if (WARN_ON(ret < 0))
goto out_clock_put;
goto out_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);
......
......@@ -49,15 +49,17 @@ static int ipa_open(struct net_device *netdev)
{
struct ipa_priv *priv = netdev_priv(netdev);
struct ipa *ipa = priv->ipa;
struct device *dev;
int ret;
ret = ipa_clock_get(ipa);
if (WARN_ON(ret < 0))
goto err_clock_put;
dev = &ipa->pdev->dev;
ret = pm_runtime_get_sync(dev);
if (ret < 0)
goto err_power_put;
ret = ipa_endpoint_enable_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]);
if (ret)
goto err_clock_put;
goto err_power_put;
ret = ipa_endpoint_enable_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]);
if (ret)
......@@ -65,14 +67,14 @@ static int ipa_open(struct net_device *netdev)
netif_start_queue(netdev);
(void)ipa_clock_put(ipa);
(void)pm_runtime_put(dev);
return 0;
err_disable_tx:
ipa_endpoint_disable_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]);
err_clock_put:
(void)ipa_clock_put(ipa);
err_power_put:
(void)pm_runtime_put(dev);
return ret;
}
......@@ -82,18 +84,20 @@ static int ipa_stop(struct net_device *netdev)
{
struct ipa_priv *priv = netdev_priv(netdev);
struct ipa *ipa = priv->ipa;
struct device *dev;
int ret;
ret = ipa_clock_get(ipa);
if (WARN_ON(ret < 0))
goto out_clock_put;
dev = &ipa->pdev->dev;
ret = pm_runtime_get_sync(dev);
if (ret < 0)
goto out_power_put;
netif_stop_queue(netdev);
ipa_endpoint_disable_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_RX]);
ipa_endpoint_disable_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]);
out_clock_put:
(void)ipa_clock_put(ipa);
out_power_put:
(void)pm_runtime_put(dev);
return 0;
}
......@@ -362,9 +366,11 @@ static void ipa_modem_crashed(struct ipa *ipa)
struct device *dev = &ipa->pdev->dev;
int ret;
ret = ipa_clock_get(ipa);
if (WARN_ON(ret < 0))
goto out_clock_put;
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
dev_err(dev, "error %d getting power to handle crash\n", ret);
goto out_power_put;
}
ipa_endpoint_modem_pause_all(ipa, true);
......@@ -391,8 +397,8 @@ static void ipa_modem_crashed(struct ipa *ipa)
if (ret)
dev_err(dev, "error %d zeroing modem memory regions\n", ret);
out_clock_put:
(void)ipa_clock_put(ipa);
out_power_put:
(void)pm_runtime_put(dev);
}
static int ipa_modem_notify(struct notifier_block *nb, unsigned long action,
......
......@@ -16,7 +16,6 @@
#include "ipa_smp2p.h"
#include "ipa.h"
#include "ipa_uc.h"
#include "ipa_clock.h"
/**
* DOC: IPA SMP2P communication with the modem
......@@ -153,6 +152,7 @@ static void ipa_smp2p_panic_notifier_unregister(struct ipa_smp2p *smp2p)
static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id)
{
struct ipa_smp2p *smp2p = dev_id;
struct device *dev;
int ret;
mutex_lock(&smp2p->mutex);
......@@ -161,17 +161,20 @@ static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id)
goto out_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))
goto out_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);
goto out_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);
......@@ -211,7 +214,7 @@ static void ipa_smp2p_clock_release(struct ipa *ipa)
if (!ipa->smp2p->clock_on)
return;
(void)ipa_clock_put(ipa);
(void)pm_runtime_put(&ipa->pdev->dev);
ipa->smp2p->clock_on = false;
}
......
......@@ -7,9 +7,9 @@
#include <linux/types.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include "ipa.h"
#include "ipa_clock.h"
#include "ipa_uc.h"
/**
......@@ -154,7 +154,7 @@ static void ipa_uc_response_hdlr(struct ipa *ipa, enum ipa_irq_id irq_id)
case IPA_UC_RESPONSE_INIT_COMPLETED:
if (ipa->uc_clocked) {
ipa->uc_loaded = true;
(void)ipa_clock_put(ipa);
(void)pm_runtime_put(dev);
ipa->uc_clocked = false;
} else {
dev_warn(dev, "unexpected init_completed response\n");
......@@ -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 */
void ipa_uc_clock(struct ipa *ipa)
{
static bool already;
struct device *dev;
int ret;
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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment