Skip to content

Commit

Permalink
net: ipa: use autosuspend
Browse files Browse the repository at this point in the history
Use runtime power management autosuspend.

Up until this point, we only suspended the IPA hardware for system
suspend; now we'll suspend it aggressively using runtime power
management, setting the initial autosuspend delay to half a second
of inactivity.

Replace pm_runtime_put() calls with pm_runtime_put_autosuspend(),
call pm_runtime_mark_last_busy() before each of those.  In places
where we're shutting things down, or decrementing power references
for errors, use pm_runtime_put_noidle() instead.

Finally, remove ipa_runtime_idle(), so the ->runtime_suspend
callback will occur if idle.

Signed-off-by: Alex Elder <elder@linaro.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Alex Elder authored and David S. Miller committed Aug 22, 2021
1 parent 4af14db commit 1aac309
Showing 6 changed files with 40 additions and 25 deletions.
15 changes: 7 additions & 8 deletions drivers/net/ipa/ipa_clock.c
Original file line number Diff line number Diff line change
@@ -32,6 +32,8 @@
* An IPA clock reference must be held for any access to IPA hardware.
*/

#define IPA_AUTOSUSPEND_DELAY 500 /* milliseconds */

/**
* struct ipa_interconnect - IPA interconnect information
* @path: Interconnect path
@@ -267,11 +269,6 @@ static int ipa_runtime_resume(struct device *dev)
return 0;
}

static int ipa_runtime_idle(struct device *dev)
{
return -EAGAIN;
}

static int ipa_suspend(struct device *dev)
{
struct ipa *ipa = dev_get_drvdata(dev);
@@ -443,7 +440,8 @@ ipa_clock_init(struct device *dev, const struct ipa_clock_data *data)
if (ret)
goto err_kfree;

pm_runtime_dont_use_autosuspend(dev);
pm_runtime_set_autosuspend_delay(dev, IPA_AUTOSUSPEND_DELAY);
pm_runtime_use_autosuspend(dev);
pm_runtime_enable(dev);

return clock;
@@ -459,9 +457,11 @@ ipa_clock_init(struct device *dev, const struct ipa_clock_data *data)
/* Inverse of ipa_clock_init() */
void ipa_clock_exit(struct ipa_clock *clock)
{
struct device *dev = clock->dev;
struct clk *clk = clock->core;

pm_runtime_disable(clock->dev);
pm_runtime_disable(dev);
pm_runtime_dont_use_autosuspend(dev);
ipa_interconnect_exit(clock);
kfree(clock);
clk_put(clk);
@@ -472,5 +472,4 @@ const struct dev_pm_ops ipa_pm_ops = {
.resume = ipa_resume,
.runtime_suspend = ipa_runtime_suspend,
.runtime_resume = ipa_runtime_resume,
.runtime_idle = ipa_runtime_idle,
};
3 changes: 2 additions & 1 deletion drivers/net/ipa/ipa_interrupt.c
Original file line number Diff line number Diff line change
@@ -116,7 +116,8 @@ static irqreturn_t ipa_isr_thread(int irq, void *dev_id)
iowrite32(pending, ipa->reg_virt + offset);
}
out_power_put:
(void)pm_runtime_put(dev);
pm_runtime_mark_last_busy(dev);
(void)pm_runtime_put_autosuspend(dev);

return IRQ_HANDLED;
}
11 changes: 6 additions & 5 deletions drivers/net/ipa/ipa_main.c
Original file line number Diff line number Diff line change
@@ -766,14 +766,15 @@ static int ipa_probe(struct platform_device *pdev)
if (ret)
goto err_deconfig;
done:
(void)pm_runtime_put(dev);
pm_runtime_mark_last_busy(dev);
(void)pm_runtime_put_autosuspend(dev);

return 0;

err_deconfig:
ipa_deconfig(ipa);
err_power_put:
(void)pm_runtime_put(dev);
pm_runtime_put_noidle(dev);
ipa_modem_exit(ipa);
err_table_exit:
ipa_table_exit(ipa);
@@ -797,9 +798,10 @@ static int ipa_remove(struct platform_device *pdev)
{
struct ipa *ipa = dev_get_drvdata(&pdev->dev);
struct ipa_clock *clock = ipa->clock;
struct device *dev = &pdev->dev;
int ret;

ret = pm_runtime_get_sync(&pdev->dev);
ret = pm_runtime_get_sync(dev);
if (WARN_ON(ret < 0))
goto out_power_put;

@@ -818,8 +820,7 @@ static int ipa_remove(struct platform_device *pdev)

ipa_deconfig(ipa);
out_power_put:
(void)pm_runtime_put(&pdev->dev);

pm_runtime_put_noidle(dev);
ipa_modem_exit(ipa);
ipa_table_exit(ipa);
ipa_endpoint_exit(ipa);
16 changes: 10 additions & 6 deletions drivers/net/ipa/ipa_modem.c
Original file line number Diff line number Diff line change
@@ -67,14 +67,15 @@ static int ipa_open(struct net_device *netdev)

netif_start_queue(netdev);

(void)pm_runtime_put(dev);
pm_runtime_mark_last_busy(dev);
(void)pm_runtime_put_autosuspend(dev);

return 0;

err_disable_tx:
ipa_endpoint_disable_one(ipa->name_map[IPA_ENDPOINT_AP_MODEM_TX]);
err_power_put:
(void)pm_runtime_put(dev);
pm_runtime_put_noidle(dev);

return ret;
}
@@ -97,7 +98,8 @@ static int ipa_stop(struct net_device *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_power_put:
(void)pm_runtime_put(dev);
pm_runtime_mark_last_busy(dev);
(void)pm_runtime_put_autosuspend(dev);

return 0;
}
@@ -145,7 +147,7 @@ ipa_start_xmit(struct sk_buff *skb, struct net_device *netdev)
*/
ipa_power_modem_queue_stop(ipa);

(void)pm_runtime_put(dev);
pm_runtime_put_noidle(dev);

return NETDEV_TX_BUSY;
}
@@ -154,7 +156,8 @@ ipa_start_xmit(struct sk_buff *skb, struct net_device *netdev)

ret = ipa_endpoint_skb_tx(endpoint, skb);

(void)pm_runtime_put(dev);
pm_runtime_mark_last_busy(dev);
(void)pm_runtime_put_autosuspend(dev);

if (ret) {
if (ret != -E2BIG)
@@ -398,7 +401,8 @@ static void ipa_modem_crashed(struct ipa *ipa)
dev_err(dev, "error %d zeroing modem memory regions\n", ret);

out_power_put:
(void)pm_runtime_put(dev);
pm_runtime_mark_last_busy(dev);
(void)pm_runtime_put_autosuspend(dev);
}

static int ipa_modem_notify(struct notifier_block *nb, unsigned long action,
8 changes: 6 additions & 2 deletions drivers/net/ipa/ipa_smp2p.c
Original file line number Diff line number Diff line change
@@ -174,7 +174,8 @@ static irqreturn_t ipa_smp2p_modem_setup_ready_isr(int irq, void *dev_id)
WARN(ret != 0, "error %d from ipa_setup()\n", ret);

out_power_put:
(void)pm_runtime_put(dev);
pm_runtime_mark_last_busy(dev);
(void)pm_runtime_put_autosuspend(dev);
out_mutex_unlock:
mutex_unlock(&smp2p->mutex);

@@ -211,10 +212,13 @@ static void ipa_smp2p_irq_exit(struct ipa_smp2p *smp2p, u32 irq)
/* Drop the clock reference if it was taken in ipa_smp2p_notify() */
static void ipa_smp2p_clock_release(struct ipa *ipa)
{
struct device *dev = &ipa->pdev->dev;

if (!ipa->smp2p->clock_on)
return;

(void)pm_runtime_put(&ipa->pdev->dev);
pm_runtime_mark_last_busy(dev);
(void)pm_runtime_put_autosuspend(dev);
ipa->smp2p->clock_on = false;
}

12 changes: 9 additions & 3 deletions drivers/net/ipa/ipa_uc.c
Original file line number Diff line number Diff line change
@@ -154,7 +154,8 @@ 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)pm_runtime_put(dev);
pm_runtime_mark_last_busy(dev);
(void)pm_runtime_put_autosuspend(dev);
ipa->uc_clocked = false;
} else {
dev_warn(dev, "unexpected init_completed response\n");
@@ -179,10 +180,15 @@ void ipa_uc_config(struct ipa *ipa)
/* Inverse of ipa_uc_config() */
void ipa_uc_deconfig(struct ipa *ipa)
{
struct device *dev = &ipa->pdev->dev;

ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_1);
ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_0);
if (ipa->uc_clocked)
(void)pm_runtime_put(&ipa->pdev->dev);
if (!ipa->uc_clocked)
return;

pm_runtime_mark_last_busy(dev);
(void)pm_runtime_put_autosuspend(dev);
}

/* Take a proxy clock reference for the microcontroller */

0 comments on commit 1aac309

Please sign in to comment.