From 1aac309d32075e73d1f93208b38cd2d5f03e0a5c Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Fri, 20 Aug 2021 11:01:27 -0500 Subject: [PATCH] net: ipa: use autosuspend 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 Signed-off-by: David S. Miller --- drivers/net/ipa/ipa_clock.c | 15 +++++++-------- drivers/net/ipa/ipa_interrupt.c | 3 ++- drivers/net/ipa/ipa_main.c | 11 ++++++----- drivers/net/ipa/ipa_modem.c | 16 ++++++++++------ drivers/net/ipa/ipa_smp2p.c | 8 ++++++-- drivers/net/ipa/ipa_uc.c | 12 +++++++++--- 6 files changed, 40 insertions(+), 25 deletions(-) diff --git a/drivers/net/ipa/ipa_clock.c b/drivers/net/ipa/ipa_clock.c index 149b24da0bcc..54d684945a7f 100644 --- a/drivers/net/ipa/ipa_clock.c +++ b/drivers/net/ipa/ipa_clock.c @@ -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 @@ err_clk_put: /* 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, }; diff --git a/drivers/net/ipa/ipa_interrupt.c b/drivers/net/ipa/ipa_interrupt.c index 3fecaadb4a37..b35170a93b0f 100644 --- a/drivers/net/ipa/ipa_interrupt.c +++ b/drivers/net/ipa/ipa_interrupt.c @@ -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; } diff --git a/drivers/net/ipa/ipa_main.c b/drivers/net/ipa/ipa_main.c index 3969aef6c437..b4d7534045a1 100644 --- a/drivers/net/ipa/ipa_main.c +++ b/drivers/net/ipa/ipa_main.c @@ -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); diff --git a/drivers/net/ipa/ipa_modem.c b/drivers/net/ipa/ipa_modem.c index 11f0204a9695..18b1f8d6d729 100644 --- a/drivers/net/ipa/ipa_modem.c +++ b/drivers/net/ipa/ipa_modem.c @@ -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, diff --git a/drivers/net/ipa/ipa_smp2p.c b/drivers/net/ipa/ipa_smp2p.c index f6e2061cd391..7e1cef0fc67c 100644 --- a/drivers/net/ipa/ipa_smp2p.c +++ b/drivers/net/ipa/ipa_smp2p.c @@ -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; } diff --git a/drivers/net/ipa/ipa_uc.c b/drivers/net/ipa/ipa_uc.c index a0bdd25b65b4..de0438527019 100644 --- a/drivers/net/ipa/ipa_uc.c +++ b/drivers/net/ipa/ipa_uc.c @@ -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 */