From: Lukas Wunner <lukas@wunner.de>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
linux-kernel@vger.kernel.org
Cc: Andreas Noever <andreas.noever@gmail.com>,
linux-pci@vger.kernel.org, linux-pm@vger.kernel.org,
Chen Yu <yu.c.chen@intel.com>,
Tomas Winkler <tomas.winkler@intel.com>,
Amir Levy <amir.jer.levy@intel.com>
Subject: [PATCH v4 8/8] thunderbolt: Runtime suspend NHI when idle
Date: Sun, 8 Jan 2017 09:41:45 +0100 [thread overview]
Message-ID: <2dd9744308f87f15e4e252157b327fcae5633693.1483806825.git.lukas@wunner.de> (raw)
In-Reply-To: <cover.1483806825.git.lukas@wunner.de>
Runtime suspend the NHI when no Thunderbolt devices have been plugged in
for 10 sec (user-configurable via autosuspend_delay_ms in sysfs).
The NHI is not able to detect plug events while suspended, it relies on
the GPE handler to resume it on hotplug.
After the NHI resumes, it takes about 700 ms until a hotplug event
appears on the RX ring. In case autosuspend_delay_ms has been reduced
to 0 by the user, we need to wait in tb_resume() to avoid going back to
sleep before we had a chance to detect a hotplugged device. A runtime
pm ref is held for the duration of tb_handle_hotplug() to keep the NHI
awake while the hotplug event is processed.
Apart from that we acquire a runtime pm ref for each newly allocated
switch (except for the root switch) and drop one when a switch is freed,
thereby ensuring the NHI stays active as long as devices are plugged in.
This behaviour is identical to the macOS driver.
Cc: Andreas Noever <andreas.noever@gmail.com>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
---
drivers/thunderbolt/nhi.c | 2 ++
drivers/thunderbolt/power.c | 9 +++++++++
drivers/thunderbolt/switch.c | 9 +++++++++
drivers/thunderbolt/tb.c | 13 +++++++++++++
4 files changed, 33 insertions(+)
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index 88fb2fb..319ed81 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -632,6 +632,8 @@ static void nhi_remove(struct pci_dev *pdev)
* pci-tunnels stay alive.
*/
.restore_noirq = nhi_resume_noirq,
+ .runtime_suspend = nhi_suspend_noirq,
+ .runtime_resume = nhi_resume_noirq,
};
static struct pci_device_id nhi_ids[] = {
diff --git a/drivers/thunderbolt/power.c b/drivers/thunderbolt/power.c
index 6e7ef07..06f535c 100644
--- a/drivers/thunderbolt/power.c
+++ b/drivers/thunderbolt/power.c
@@ -319,6 +319,12 @@ void thunderbolt_power_init(struct tb *tb)
tb->power = power;
+ pm_runtime_allow(nhi_dev);
+ pm_runtime_set_autosuspend_delay(nhi_dev, 10000);
+ pm_runtime_use_autosuspend(nhi_dev);
+ pm_runtime_mark_last_busy(nhi_dev);
+ pm_runtime_put_autosuspend(nhi_dev);
+
return;
err_free:
@@ -335,6 +341,9 @@ void thunderbolt_power_fini(struct tb *tb)
if (!power)
return; /* thunderbolt_power_init() failed */
+ pm_runtime_get(nhi_dev);
+ pm_runtime_forbid(nhi_dev);
+
tb->power = NULL;
dev_pm_domain_set(upstream_dev, NULL);
diff --git a/drivers/thunderbolt/switch.c b/drivers/thunderbolt/switch.c
index c6f30b1..422fe6e 100644
--- a/drivers/thunderbolt/switch.c
+++ b/drivers/thunderbolt/switch.c
@@ -5,6 +5,7 @@
*/
#include <linux/delay.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include "tb.h"
@@ -326,6 +327,11 @@ void tb_switch_free(struct tb_switch *sw)
if (!sw->is_unplugged)
tb_plug_events_active(sw, false);
+ if (sw != sw->tb->root_switch) {
+ pm_runtime_mark_last_busy(&sw->tb->nhi->pdev->dev);
+ pm_runtime_put_autosuspend(&sw->tb->nhi->pdev->dev);
+ }
+
kfree(sw->ports);
kfree(sw->drom);
kfree(sw);
@@ -420,6 +426,9 @@ struct tb_switch *tb_switch_alloc(struct tb *tb, u64 route)
if (tb_plug_events_active(sw, true))
goto err;
+ if (tb->root_switch)
+ pm_runtime_get(&tb->nhi->pdev->dev);
+
return sw;
err:
kfree(sw->ports);
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index 24b6d30..a3fedf9 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -7,6 +7,7 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/delay.h>
+#include <linux/pm_runtime.h>
#include "tb.h"
#include "tb_regs.h"
@@ -217,8 +218,11 @@ static void tb_handle_hotplug(struct work_struct *work)
{
struct tb_hotplug_event *ev = container_of(work, typeof(*ev), work);
struct tb *tb = ev->tb;
+ struct device *dev = &tb->nhi->pdev->dev;
struct tb_switch *sw;
struct tb_port *port;
+
+ pm_runtime_get(dev);
mutex_lock(&tb->lock);
if (!tb->hotplug_active)
goto out; /* during init, suspend or shutdown */
@@ -274,6 +278,8 @@ static void tb_handle_hotplug(struct work_struct *work)
out:
mutex_unlock(&tb->lock);
kfree(ev);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
}
/**
@@ -433,4 +439,11 @@ void thunderbolt_resume(struct tb *tb)
tb->hotplug_active = true;
mutex_unlock(&tb->lock);
tb_info(tb, "resume finished\n");
+
+ /*
+ * If runtime resuming due to a hotplug event (rather than resuming
+ * from system sleep), wait for it to arrive. May take about 700 ms.
+ */
+ if (tb->nhi->pdev->dev.power.runtime_status == RPM_RESUMING)
+ msleep(1000);
}
--
2.11.0
prev parent reply other threads:[~2017-01-08 8:45 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-01-08 8:41 [PATCH v4 0/8] Runtime PM for Thunderbolt on Macs Lukas Wunner
2017-01-08 8:41 ` [PATCH v4 6/8] PM / sleep: Define constant for direct_complete Lukas Wunner
2017-01-08 8:41 ` [PATCH v4 1/8] PCI: Recognize Thunderbolt devices Lukas Wunner
2017-01-08 10:23 ` Winkler, Tomas
2017-01-08 13:47 ` Lukas Wunner
2017-01-11 10:01 ` Winkler, Tomas
2017-01-08 8:41 ` [PATCH v4 3/8] PCI: Don't block runtime PM for Thunderbolt host hotplug ports Lukas Wunner
2017-01-11 10:02 ` Mika Westerberg
2017-01-12 1:47 ` Lukas Wunner
2017-01-12 9:02 ` Mika Westerberg
2017-01-15 9:36 ` Lukas Wunner
2017-01-08 8:41 ` [PATCH v4 5/8] PM: Make requirements of dev_pm_domain_set() more precise Lukas Wunner
2017-01-08 8:41 ` [PATCH v4 7/8] thunderbolt: Power down controller when idle Lukas Wunner
2017-01-08 8:41 ` [PATCH v4 2/8] PCI: Allow runtime PM on Thunderbolt ports Lukas Wunner
2017-01-11 9:54 ` Mika Westerberg
2017-01-08 8:41 ` [PATCH v4 4/8] Revert "PM / Runtime: Remove the exported function pm_children_suspended()" Lukas Wunner
2017-01-08 8:41 ` Lukas Wunner [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2dd9744308f87f15e4e252157b327fcae5633693.1483806825.git.lukas@wunner.de \
--to=lukas@wunner.de \
--cc=amir.jer.levy@intel.com \
--cc=andreas.noever@gmail.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-pm@vger.kernel.org \
--cc=tomas.winkler@intel.com \
--cc=yu.c.chen@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®