Linux bluetooth development
 help / color / mirror / Atom feed
From: Ravindra <ravindra@intel.com>
To: linux-bluetooth@vger.kernel.org, lsa.uz@pm.me,
	vladimirkondratyev2@gmail.com
Cc: chethan.tumkur.narayan@intel.com, kiran.k@intel.com,
	pmenzel@molgen.mpg.de, Ravindra <ravindra@intel.com>
Subject: [PATCH v5 3/4] Bluetooth: btintel_pcie: verify state after alive interrupt
Date: Mon, 28 Sep 2026 10:33:43 +0530	[thread overview]
Message-ID: <20260928050344.2893790-4-ravindra@intel.com> (raw)
In-Reply-To: <20260928050344.2893790-1-ravindra@intel.com>

From: Sergey Lebedev <lsa.uz@pm.me>

The gp0_received flag only reports that the GP0 handler ran. It does
not guarantee that the handler completed the requested D-state
transition: a matched case can leave the state unchanged.

Refresh the boot-stage register before treating the transition as
successful. When the controller is in D0 but the handler did not
re-arm the interface, restore the alive context, reset the interface
arrays, restart RX, and complete the mailbox/alive handshake. Propagate
RX setup failures to the PM caller. Likewise, when the controller is in
D3 but the handler did not record it, restore the alive context so the
next transition dispatches correctly.

Signed-off-by: Ravindra <ravindra@intel.com>
Signed-off-by: Sergey Lebedev <lsa.uz@pm.me>
---
 drivers/bluetooth/btintel_pcie.c | 64 ++++++++++++++++++++++++--------
 1 file changed, 48 insertions(+), 16 deletions(-)

diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c
index 082f5ec8ba71..553fa927cf0a 100644
--- a/drivers/bluetooth/btintel_pcie.c
+++ b/drivers/bluetooth/btintel_pcie.c
@@ -4200,7 +4200,7 @@ static void btintel_pcie_coredump(struct device *dev)
 
 static int btintel_pcie_set_dxstate(struct btintel_pcie_data *data, u32 dxstate)
 {
-	int retry = 0;
+	int retry = 0, err;
 	long status;
 	u32 dx_intr_timeout_ms = 200;
 
@@ -4212,30 +4212,62 @@ static int btintel_pcie_set_dxstate(struct btintel_pcie_data *data, u32 dxstate)
 		status = wait_event_timeout(data->gp0_wait_q, data->gp0_received,
 			msecs_to_jiffies(dx_intr_timeout_ms));
 
-		if (status)
-			return 0;
-
-		bt_dev_warn(data->hdev,
-			   "Timeout (%u ms) on alive interrupt for D%d entry, retry count %d",
-			   dx_intr_timeout_ms, dxstate, retry);
+		if (!status) {
+			bt_dev_warn(data->hdev,
+				    "Timeout (%u ms) on alive interrupt for D%d entry, retry count %d",
+				    dx_intr_timeout_ms, dxstate, retry);
 
-		/* clear gp0 cause */
-		btintel_pcie_clr_reg_bits(data,
-					  BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES,
-					  BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0);
+			/* clear gp0 cause */
+			btintel_pcie_clr_reg_bits(data,
+						  BTINTEL_PCIE_CSR_MSIX_HW_INT_CAUSES,
+						  BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0);
+		}
 
-		/* A hardware bug may cause the alive interrupt to be missed. Refresh
-		 * boot_stage_cache from hardware, since only the interrupt handler
-		 * updates it. Finally retry only if the state check still fails.
+		/* gp0_received is set at the top of the handler, before the switch on
+		 * alive_intr_ctxt. Error and lockdown are filtered out above it, but a
+		 * matched case can still complete without doing anything - D3 breaks
+		 * unchanged while the controller has not reached D0 - and a hardware
+		 * bug may drop the interrupt outright. Either way the flag says a gp0
+		 * was handled, not that the transition completed, and only the register
+		 * knows. Refresh the cache here and retry only if the state check still
+		 * fails.
 		 */
 		data->boot_stage_cache = btintel_pcie_rd_reg32(data,
 							       BTINTEL_PCIE_CSR_BOOT_STAGE_REG);
 		if (dxstate == BTINTEL_PCIE_STATE_D0) {
-			if (btintel_pcie_in_d0(data))
+			if (btintel_pcie_in_d0(data)) {
+				/* Do what the handler's D3 -> D0 branch
+				 * would have done, unless it already has.
+				 */
+				if (data->alive_intr_ctxt == BTINTEL_PCIE_D0)
+					return 0;
+
+				data->alive_intr_ctxt = BTINTEL_PCIE_D0;
+				btintel_pcie_reset_ia(data);
+				err = btintel_pcie_start_rx(data);
+				if (err)
+					return err;
+
+				/* Complete the mbox<->alive handshake */
+				if (test_and_clear_bit(BTINTEL_PCIE_MBOX_PARSE_PENDING,
+						       &data->flags)) {
+					set_bit(BTINTEL_PCIE_MBOX_PARSE_READY, &data->flags);
+					wake_up(&data->mbox_parse_wait_q);
+				}
+
 				return 0;
+			}
 		} else {
-			if (btintel_pcie_in_d3(data))
+			if (btintel_pcie_in_d3(data)) {
+				/* Do what the handler's D0 -> D3 branch
+				 * would have done, unless it already has.
+				 */
+				if (data->alive_intr_ctxt == BTINTEL_PCIE_D3)
+					return 0;
+
+				data->alive_intr_ctxt = BTINTEL_PCIE_D3;
 				return 0;
+			}
 		}
 
 	} while (++retry < BTINTEL_PCIE_DX_TRANSITION_MAX_RETRIES);
-- 
2.43.0


  parent reply	other threads:[~2026-09-28  5:01 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-28  5:03 [PATCH v5 0/4] Bluetooth: btintel_pcie: fix D-state transition and PM flows Ravindra
2026-09-28  5:03 ` [PATCH v5 1/4] Bluetooth: btintel_pcie: fix stale cache in set_dxstate fallback check Ravindra
2026-09-28  7:39   ` Bluetooth: btintel_pcie: fix D-state transition and PM flows bluez.test.bot
2026-09-28  5:03 ` [PATCH v5 2/4] Bluetooth: btintel_pcie: fix PM flow for S0ix, S3 and S4 Ravindra
2026-09-28  5:03 ` Ravindra [this message]
2026-09-28 16:59   ` [PATCH v5 3/4] Bluetooth: btintel_pcie: verify state after alive interrupt Ravindra
2026-09-28  5:03 ` [PATCH v5 4/4] Bluetooth: btintel_pcie: clear the GP0 cause with a W1C write Ravindra
2026-09-29 15:10 ` [PATCH v5 0/4] Bluetooth: btintel_pcie: fix D-state transition and PM flows patchwork-bot+bluetooth

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=20260928050344.2893790-4-ravindra@intel.com \
    --to=ravindra@intel.com \
    --cc=chethan.tumkur.narayan@intel.com \
    --cc=kiran.k@intel.com \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=lsa.uz@pm.me \
    --cc=pmenzel@molgen.mpg.de \
    --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