From: Sergey Lebedev <lsa.uz@pm.me>
To: Marcel Holtmann <marcel@holtmann.org>,
Luiz Augusto von Dentz <luiz.dentz@gmail.com>,
"Vladimir V . Kondratyev" <vladimirkondratyev2@gmail.com>,
Ravindra <ravindra@intel.com>
Cc: Ferenc Lengyel <dev@lengyelf.eu>,
Chethan Tumkur Narayan <chethan.tumkur.narayan@intel.com>,
Ravishankar Srivatsa <ravishankar.srivatsa@intel.com>,
Paul Menzel <pmenzel@molgen.mpg.de>, Kiran K <kiran.k@intel.com>,
Chandrashekar Devegowda <chandrashekar.devegowda@intel.com>,
Mahalingeshwara Chambarakatta
<mahalingeshwara.chambarakatta@intel.com>,
Arnd Bergmann <arnd@arndb.de>,
linux-bluetooth@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH 2/2] Bluetooth: btintel_pcie: fix PM flow for S0ix, S3 and S4
Date: Wed, 09 Sep 2026 12:34:38 +0000 [thread overview]
Message-ID: <20260909123416.71919-3-lsa.uz@pm.me> (raw)
In-Reply-To: <20260909123416.71919-1-lsa.uz@pm.me>
From: Ravindra <ravindra@intel.com>
Use pm_suspend_target_state to differentiate S0ix from S3/S4. Set the
controller to D3_HOT for S0ix (PM_SUSPEND_TO_IDLE) and D3_COLD for
S3/S4, freeze and hibernate to prevent post-resume instability.
Register .freeze, .thaw, .poweroff and .restore callbacks for proper
hibernation support. The freeze and poweroff (hibernate) paths set
D3_COLD via btintel_pcie_suspend_late. The thaw path resumes with a
normal D0 transition, while .restore forces FLR-based firmware recovery
after S4 since power is lost. S3 (PM_SUSPEND_MEM) resume also triggers
FLR. S0ix resumes via a normal D0 transition.
Fixes: e57362f4911b ("Bluetooth: btintel_pcie: Add support for _suspend() / _resume()")
Assisted-by: GitHub-Copilot:GPT5
Signed-off-by: Ravindra <ravindra@intel.com>
Assisted-by: Claude:claude-opus-5
Tested-by: Ferenc Lengyel <dev@lengyelf.eu>
Signed-off-by: Sergey Lebedev <lsa.uz@pm.me>
---
drivers/bluetooth/btintel_pcie.c | 64 ++++++++++++++++++++++----------
drivers/bluetooth/btintel_pcie.h | 2 -
2 files changed, 44 insertions(+), 22 deletions(-)
diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c
index 361c550b5..e37e710b9 100644
--- a/drivers/bluetooth/btintel_pcie.c
+++ b/drivers/bluetooth/btintel_pcie.c
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/acpi.h>
+#include <linux/suspend.h>
#include <linux/unaligned.h>
#include <linux/devcoredump.h>
@@ -4168,11 +4169,16 @@ static void btintel_pcie_coredump(struct device *dev)
static int btintel_pcie_set_dxstate(struct btintel_pcie_data *data, u32 dxstate)
{
- int retry = 0, status;
+ int retry = 0;
+ long status;
u32 dx_intr_timeout_ms = 200;
+ /* Not reset per retry: dxstate is unchanged, so a late interrupt from
+ * an earlier attempt still confirms the target state.
+ */
+ data->gp0_received = false;
+
do {
- data->gp0_received = false;
btintel_pcie_wr_sleep_cntrl(data, dxstate);
@@ -4220,18 +4226,23 @@ static int btintel_pcie_suspend_late(struct device *dev, pm_message_t mesg)
data = pci_get_drvdata(pdev);
- dxstate = (mesg.event == PM_EVENT_SUSPEND ?
- BTINTEL_PCIE_STATE_D3_HOT : BTINTEL_PCIE_STATE_D3_COLD);
-
- data->pm_sx_event = mesg.event;
+ /* S0ix (s2idle) uses D3_HOT; S3, freeze and hibernate use D3_COLD. */
+ if (mesg.event == PM_EVENT_SUSPEND &&
+ pm_suspend_target_state == PM_SUSPEND_TO_IDLE)
+ dxstate = BTINTEL_PCIE_STATE_D3_HOT;
+ else
+ dxstate = BTINTEL_PCIE_STATE_D3_COLD;
start = ktime_get();
/* Refer: 6.4.11.7 -> Platform power management */
err = btintel_pcie_set_dxstate(data, dxstate);
- if (err)
+ if (err) {
+ bt_dev_err(data->hdev, "Failed to set dxstate:%u (%d)",
+ dxstate, err);
return err;
+ }
bt_dev_dbg(data->hdev,
"device entered into d3 state from d0 in %lld us",
@@ -4254,7 +4265,7 @@ static int btintel_pcie_freeze(struct device *dev)
return btintel_pcie_suspend_late(dev, PMSG_FREEZE);
}
-static int btintel_pcie_resume(struct device *dev)
+static int btintel_pcie_resume_event(struct device *dev, pm_message_t mesg)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct btintel_pcie_data *data;
@@ -4262,19 +4273,15 @@ static int btintel_pcie_resume(struct device *dev)
int err;
data = pci_get_drvdata(pdev);
- data->gp0_received = false;
start = ktime_get();
- /* When the system enters S4 (hibernate) mode, bluetooth device loses
- * power, which results in the erasure of its loaded firmware.
- * Consequently, function level reset (flr) is required on system
- * resume to bring the controller back into an operational state by
- * initiating a new firmware download.
+ /* S3 and S4 may cut power, erasing the firmware. Force FLR to recover
+ * instead of a normal D0 transition.
*/
-
- if (data->pm_sx_event == PM_EVENT_FREEZE ||
- data->pm_sx_event == PM_EVENT_HIBERNATE) {
+ if (mesg.event == PM_EVENT_RESTORE ||
+ (mesg.event == PM_EVENT_RESUME &&
+ pm_suspend_target_state == PM_SUSPEND_MEM)) {
set_bit(BTINTEL_PCIE_CORE_HALTED, &data->flags);
btintel_pcie_request_reset(data, BTINTEL_PCIE_IOSF_PRR_FLR);
return 0;
@@ -4283,7 +4290,9 @@ static int btintel_pcie_resume(struct device *dev)
/* Refer: 6.4.11.7 -> Platform power management */
err = btintel_pcie_set_dxstate(data, BTINTEL_PCIE_STATE_D0);
- if (err == 0) {
+ if (err) {
+ bt_dev_err(data->hdev, "Failed to set D0 state (%d)", err);
+ } else {
bt_dev_dbg(data->hdev,
"device entered into d0 state from d3 in %lld us",
ktime_to_us(ktime_get() - start));
@@ -4308,13 +4317,28 @@ static int btintel_pcie_resume(struct device *dev)
return err;
}
+static int btintel_pcie_resume(struct device *dev)
+{
+ return btintel_pcie_resume_event(dev, PMSG_RESUME);
+}
+
+static int btintel_pcie_restore(struct device *dev)
+{
+ return btintel_pcie_resume_event(dev, PMSG_RESTORE);
+}
+
+static int btintel_pcie_thaw(struct device *dev)
+{
+ return btintel_pcie_resume_event(dev, PMSG_THAW);
+}
+
static const struct dev_pm_ops btintel_pcie_pm_ops = {
.suspend = btintel_pcie_suspend,
.resume = btintel_pcie_resume,
.freeze = btintel_pcie_freeze,
- .thaw = btintel_pcie_resume,
+ .thaw = btintel_pcie_thaw,
.poweroff = btintel_pcie_hibernate,
- .restore = btintel_pcie_resume,
+ .restore = btintel_pcie_restore,
};
static struct pci_driver btintel_pcie_driver = {
diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h
index 016795fcb..3030b4e8b 100644
--- a/drivers/bluetooth/btintel_pcie.h
+++ b/drivers/bluetooth/btintel_pcie.h
@@ -713,7 +713,6 @@ struct btintel_pcie_ini_dump_info {
* @txq: TX Queue struct
* @rxq: RX Queue struct
* @alive_intr_ctxt: Alive interrupt context
- * @pm_sx_event: PM event on which system got suspended
*/
struct btintel_pcie_data {
struct pci_dev *pdev;
@@ -773,7 +772,6 @@ struct btintel_pcie_data {
struct btintel_pcie_dbgc dbgc;
struct btintel_pcie_mdbgc mdbgc;
struct btintel_pcie_dump_header dmp_hdr;
- u8 pm_sx_event;
u32 debug_evt_addr;
u32 debug_evt_size;
dma_addr_t debug_table_addr;
--
2.50.1 (Apple Git-155)
next prev parent reply other threads:[~2026-09-09 12:34 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-09 12:34 [PATCH 0/2] Bluetooth: btintel_pcie: two PM fixes, assembled as one series Sergey Lebedev
2026-09-09 12:34 ` [PATCH 1/2] Bluetooth: btintel_pcie: fix stale cache in set_dxstate fallback check Sergey Lebedev
2026-09-09 15:59 ` Bluetooth: btintel_pcie: two PM fixes, assembled as one series bluez.test.bot
2026-09-09 12:34 ` Sergey Lebedev [this message]
2026-09-09 18:33 ` [PATCH 2/2] Bluetooth: btintel_pcie: fix PM flow for S0ix, S3 and S4 Luiz Augusto von Dentz
2026-09-09 20:47 ` Sergey Lebedev
2026-09-09 18:33 ` Consent for Assembly yCduIhFgkD
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=20260909123416.71919-3-lsa.uz@pm.me \
--to=lsa.uz@pm.me \
--cc=arnd@arndb.de \
--cc=chandrashekar.devegowda@intel.com \
--cc=chethan.tumkur.narayan@intel.com \
--cc=dev@lengyelf.eu \
--cc=kiran.k@intel.com \
--cc=linux-bluetooth@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luiz.dentz@gmail.com \
--cc=mahalingeshwara.chambarakatta@intel.com \
--cc=marcel@holtmann.org \
--cc=pmenzel@molgen.mpg.de \
--cc=ravindra@intel.com \
--cc=ravishankar.srivatsa@intel.com \
--cc=vladimirkondratyev2@gmail.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