* [PATCH v7] Bluetooth: btintel_pcie: Add support for _suspend() / _resume()
@ 2025-07-26 16:40 Kiran K
0 siblings, 0 replies; only message in thread
From: Kiran K @ 2025-07-26 16:40 UTC (permalink / raw)
To: linux-bluetooth
Cc: ravishankar.srivatsa, chethan.tumkur.narayan, bhelgaas, linux-pci,
Chandrashekar Devegowda, Paul Menzel, Manivannan Sadhasivam,
Kiran K
From: Chandrashekar Devegowda <chandrashekar.devegowda@intel.com>
This patch implements _suspend() and _resume() functions for the
Bluetooth controller. When the system enters a suspended state, the
driver notifies the controller to perform necessary housekeeping tasks
by writing to the sleep control register and waits for an alive
interrupt. The firmware raises the alive interrupt when it has
transitioned to the D3 state. The same flow occurs when the system
resumes.
Command to test host initiated wakeup after 60 seconds
sudo rtcwake -m mem -s 60
dmesg log (tested on Whale Peak2 on Panther Lake platform)
On system suspend:
[Fri Jul 25 11:05:37 2025] Bluetooth: hci0: device entered into d3 state
from d0 in 80 us
On system resume:
[Fri Jul 25 11:06:36 2025] Bluetooth: hci0: device entered into d0 state
from d3 in 7117 us
Reviewed-by: Paul Menzel <pmenzel@molgen.mpg.de>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Chandrashekar Devegowda <chandrashekar.devegowda@intel.com>
Signed-off-by: Kiran K <kiran.k@intel.com>
---
changes in v7:
- Use ktime_to_us() instead of ktime_to_ns() / 1000
- Remove CONFIG_PM_SLEEP and instead use pm_sleep_ptr() and pm_ptr()
- Use __maybe_unused to avoid compiler warnings if CONFIG_PM_SLEEP and/or
CONFIG_PM are not defined
- Use parenthesis for only conditon in ternary operator
- Include reviewers in commit message
changes in v6:
- s/delta/delta_us/g
- s/CONFIG_PM/CONFIG_PM_SLEEP/g
- use pm_sleep_pr()/pm_str() to avoid #ifdefs
- remove the code to set persistance mode as its not relevant to this patch
changes in v5:
- refactor _suspend() / _resume() to set the D3HOT/D3COLD based on power
event
- remove SIMPLE_DEV_PM_OPS and define the required pm_ops callback
functions
changes in v4:
- Moved document and section details from the commit message as comment in code.
changes in v3:
- Corrected the typo's
- Updated the CC list as suggested.
- Corrected the format specifiers in the logs.
changes in v2:
- Updated the commit message with test steps and logs.
- Added logs to include the timeout message.
- Fixed a potential race condition during suspend and resume.
drivers/bluetooth/btintel_pcie.c | 95 ++++++++++++++++++++++++++++++++
1 file changed, 95 insertions(+)
diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c
index d08f59ae7720..fc48cd878406 100644
--- a/drivers/bluetooth/btintel_pcie.c
+++ b/drivers/bluetooth/btintel_pcie.c
@@ -2574,11 +2574,106 @@ static void btintel_pcie_coredump(struct device *dev)
}
#endif
+static int __maybe_unused btintel_pcie_suspend_late(struct device *dev,
+ pm_message_t mesg)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct btintel_pcie_data *data;
+ unsigned long timeout;
+ struct hci_dev *hdev;
+ ktime_t start;
+ u32 dxstate;
+ s64 delta_us;
+ int err;
+
+ data = pci_get_drvdata(pdev);
+ hdev = data->hdev;
+
+ dxstate = (mesg.event == PM_EVENT_SUSPEND) ? BTINTEL_PCIE_STATE_D3_HOT :
+ BTINTEL_PCIE_STATE_D3_COLD;
+
+ data->gp0_received = false;
+ timeout = msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS);
+
+ start = ktime_get();
+
+ /* Refer: 6.4.11.7 -> Platform power management */
+ btintel_pcie_wr_sleep_cntrl(data, dxstate);
+ err = wait_event_timeout(data->gp0_wait_q, data->gp0_received, timeout);
+ if (err == 0) {
+ bt_dev_err(hdev, "Timeout (%u ms) on alive interrupt for D3 entry",
+ BTINTEL_DEFAULT_INTR_TIMEOUT_MS);
+ return -EBUSY;
+ }
+
+ delta_us = ktime_to_us(ktime_get() - start);
+ bt_dev_info(hdev, "device entered into d3 state from d0 in %lld us",
+ delta_us);
+ return 0;
+}
+
+static int __maybe_unused btintel_pcie_suspend(struct device *dev)
+{
+ return btintel_pcie_suspend_late(dev, PMSG_SUSPEND);
+}
+
+static int __maybe_unused btintel_pcie_hibernate(struct device *dev)
+{
+ return btintel_pcie_suspend_late(dev, PMSG_HIBERNATE);
+}
+
+static int __maybe_unused btintel_pcie_freeze(struct device *dev)
+{
+ return btintel_pcie_suspend_late(dev, PMSG_FREEZE);
+}
+
+static int __maybe_unused btintel_pcie_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct btintel_pcie_data *data;
+ unsigned long timeout;
+ struct hci_dev *hdev;
+ ktime_t start;
+ int err;
+ s64 delta_us;
+
+ data = pci_get_drvdata(pdev);
+ hdev = data->hdev;
+ data->gp0_received = false;
+ timeout = msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS);
+
+ start = ktime_get();
+
+ /* Refer: 6.4.11.7 -> Platform power management */
+ btintel_pcie_wr_sleep_cntrl(data, BTINTEL_PCIE_STATE_D0);
+ err = wait_event_timeout(data->gp0_wait_q, data->gp0_received, timeout);
+ if (err == 0) {
+ bt_dev_err(hdev, "Timeout (%u ms) on alive interrupt for D0 entry",
+ BTINTEL_DEFAULT_INTR_TIMEOUT_MS);
+ return -EBUSY;
+ }
+
+ delta_us = ktime_to_us(ktime_get() - start);
+ bt_dev_info(hdev, "device entered into d0 state from d3 in %lld us",
+ delta_us);
+ return 0;
+}
+
+static const struct dev_pm_ops __maybe_unused btintel_pcie_pm_ops = {
+ .suspend = pm_sleep_ptr(btintel_pcie_suspend),
+ .resume = pm_sleep_ptr(btintel_pcie_resume),
+ .freeze = pm_sleep_ptr(btintel_pcie_freeze),
+ .thaw = pm_sleep_ptr(btintel_pcie_resume),
+ .poweroff = pm_sleep_ptr(btintel_pcie_hibernate),
+ .restore = pm_sleep_ptr(btintel_pcie_resume),
+};
+
static struct pci_driver btintel_pcie_driver = {
.name = KBUILD_MODNAME,
.id_table = btintel_pcie_table,
.probe = btintel_pcie_probe,
.remove = btintel_pcie_remove,
+ .driver.pm = pm_ptr(&btintel_pcie_pm_ops),
#ifdef CONFIG_DEV_COREDUMP
.driver.coredump = btintel_pcie_coredump
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2025-07-26 16:23 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-26 16:40 [PATCH v7] Bluetooth: btintel_pcie: Add support for _suspend() / _resume() Kiran K
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).