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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.