Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH v2 0/2] Bluetooth: add hardware rfkill handling
@ 2026-10-02  1:43 Sai Teja Aluvala
  2026-10-02  1:43 ` [PATCH v2 1/2] Bluetooth: Add interface to allow stack to communicate hw rfkill events Sai Teja Aluvala
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Sai Teja Aluvala @ 2026-10-02  1:43 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth
  Cc: kiran.k, chethan.tumkur.narayan, Sai Teja Aluvala

This series adds hardware rfkill handling for the Intel PCIe transport and
the Bluetooth-side notification path.

The resulting flow is:

  transport hardware event
    -> hci_rfkill_set_hw_state()
    -> rfkill hardware state
    -> hdev->rfkill_block work
    -> HCI_RFKILLED state and device power handling

For Intel PCIe controllers, the series adds GP2 and HW_RFKILL MSI-X
handling, IPC_CONTROL doorbell synchronization, delayed state checking,
reset/shutdown/remove lifecycle handling, and notification of the
generic HCI rfkill layer.

Compared with v1, this version drops the Bluetooth-specific debugfs test
hook, the redundant hdev->rfkill pointer-clear patch, and the separate
RFKILL-core helper dependency. The real btintel_pcie hardware event path
and HCI notification interface are retained.

Sai Teja Aluvala (2):
  Bluetooth: Add interface to allow stack to communicate hw rfkill
    events
  Bluetooth: btintel_pcie: add HW rfkill interrupt/doorbell flow

 drivers/bluetooth/btintel_pcie.c | 140 ++++++++++++++++++++++++++++++-
 drivers/bluetooth/btintel_pcie.h |  27 ++++++
 include/net/bluetooth/hci_core.h |   3 +
 net/bluetooth/hci_core.c         |  34 ++++++++
 4 files changed, 200 insertions(+), 4 deletions(-)


base-commit: 3b44711c52eaf62723a4a715e1b7b4e49f1595ce
-- 
2.53.0

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v2 1/2] Bluetooth: Add interface to allow stack to communicate hw rfkill events
  2026-10-02  1:43 [PATCH v2 0/2] Bluetooth: add hardware rfkill handling Sai Teja Aluvala
@ 2026-10-02  1:43 ` Sai Teja Aluvala
  2026-10-02  3:14   ` Bluetooth: add hardware rfkill handling bluez.test.bot
  2026-10-02  1:43 ` [PATCH v2 2/2] Bluetooth: btintel_pcie: add HW rfkill interrupt/doorbell flow Sai Teja Aluvala
  2026-10-02 15:24 ` [PATCH v2 0/2] Bluetooth: add hardware rfkill handling Luiz Augusto von Dentz
  2 siblings, 1 reply; 5+ messages in thread
From: Sai Teja Aluvala @ 2026-10-02  1:43 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth
  Cc: kiran.k, chethan.tumkur.narayan, Sai Teja Aluvala

Introduce hci_rfkill_set_hw_state() to allow drivers to notify the HCI
stack about hardware rfkill events. The helper updates the rfkill core
hardware state and schedules hdev->rfkill_block work, which applies the
resulting block state through hci_rfkill_set_block(). This lets the
stack handle hardware rfkill events through the same procedure as
software rfkill events, without blocking the calling driver context.

Serialize the helper and rfkill teardown with hdev->unregister_lock, and
reject notifications after HCI_UNREGISTER has been set. This prevents a
late driver notification from accessing the rfkill object while it is
being destroyed.

The helper is a no-op when the device has no rfkill handle registered
(rfkill_alloc() or rfkill_register() may fail and leave hdev->rfkill
NULL). The work is disabled in hci_unregister_dev() before the rfkill
handle is destroyed.

Signed-off-by: Sai Teja Aluvala <aluvala.sai.teja@intel.com>
---
 include/net/bluetooth/hci_core.h |  3 +++
 net/bluetooth/hci_core.c         | 34 ++++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index f631d9484a0b..c44c50c78088 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -586,6 +586,7 @@ struct hci_dev {
 	struct device		dev;
 
 	struct rfkill		*rfkill;
+	struct work_struct	rfkill_block;
 
 	DECLARE_BITMAP(dev_flags, __HCI_NUM_FLAGS);
 	hci_conn_flags_t	conn_flags;
@@ -1822,6 +1823,8 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src, u8 src_type);
 
 struct hci_dev *hci_alloc_dev_priv(int sizeof_priv);
 
+void hci_rfkill_set_hw_state(struct hci_dev *hdev, bool blocked);
+
 static inline struct hci_dev *hci_alloc_dev(void)
 {
 	return hci_alloc_dev_priv(0);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 05d1ca25f44f..ca75932acf84 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -900,6 +900,36 @@ static int hci_rfkill_set_block(void *data, bool blocked)
 	return 0;
 }
 
+void hci_rfkill_set_hw_state(struct hci_dev *hdev, bool blocked)
+{
+	mutex_lock(&hdev->unregister_lock);
+	if (hci_dev_test_flag(hdev, HCI_UNREGISTER) ||
+	    IS_ERR_OR_NULL(hdev->rfkill)) {
+		mutex_unlock(&hdev->unregister_lock);
+		return;
+	}
+
+	rfkill_set_hw_state(hdev->rfkill, blocked);
+	mutex_unlock(&hdev->unregister_lock);
+
+	/* schedule work to avoid blocking the driver context calling this api */
+	schedule_work(&hdev->rfkill_block);
+}
+EXPORT_SYMBOL(hci_rfkill_set_hw_state);
+
+static void hci_rfkill_block_work(struct work_struct *work)
+{
+	struct hci_dev *hdev = container_of(work, struct hci_dev, rfkill_block);
+
+	if (!hdev->rfkill)
+		return;
+
+	if (rfkill_blocked(hdev->rfkill))
+		hci_rfkill_set_block(hdev, true);
+	else
+		hci_rfkill_set_block(hdev, false);
+}
+
 static const struct rfkill_ops hci_rfkill_ops = {
 	.set_block = hci_rfkill_set_block,
 };
@@ -2518,6 +2548,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
 	INIT_LIST_HEAD(&hdev->monitored_devices);
 
 	INIT_LIST_HEAD(&hdev->local_codecs);
+	INIT_WORK(&hdev->rfkill_block, hci_rfkill_block_work);
 	INIT_WORK(&hdev->rx_work, hci_rx_work);
 	INIT_WORK(&hdev->cmd_work, hci_cmd_work);
 	INIT_WORK(&hdev->tx_work, hci_tx_work);
@@ -2683,6 +2714,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
 	disable_work_sync(&hdev->tx_work);
 	disable_work_sync(&hdev->power_on);
 	disable_work_sync(&hdev->error_reset);
+	disable_work_sync(&hdev->rfkill_block);
 	disable_delayed_work_sync(&hdev->cmd_timer);
 	disable_delayed_work_sync(&hdev->ncmd_timer);
 	hci_devcd_shutdown(hdev);
@@ -2707,10 +2739,12 @@ void hci_unregister_dev(struct hci_dev *hdev)
 
 	hci_sock_dev_event(hdev, HCI_DEV_UNREG);
 
+	mutex_lock(&hdev->unregister_lock);
 	if (hdev->rfkill) {
 		rfkill_unregister(hdev->rfkill);
 		rfkill_destroy(hdev->rfkill);
 	}
+	mutex_unlock(&hdev->unregister_lock);
 
 	device_del(&hdev->dev);
 	/* Actual cleanup is deferred until hci_release_dev(). */
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v2 2/2] Bluetooth: btintel_pcie: add HW rfkill interrupt/doorbell flow
  2026-10-02  1:43 [PATCH v2 0/2] Bluetooth: add hardware rfkill handling Sai Teja Aluvala
  2026-10-02  1:43 ` [PATCH v2 1/2] Bluetooth: Add interface to allow stack to communicate hw rfkill events Sai Teja Aluvala
@ 2026-10-02  1:43 ` Sai Teja Aluvala
  2026-10-02 15:24 ` [PATCH v2 0/2] Bluetooth: add hardware rfkill handling Luiz Augusto von Dentz
  2 siblings, 0 replies; 5+ messages in thread
From: Sai Teja Aluvala @ 2026-10-02  1:43 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth
  Cc: kiran.k, chethan.tumkur.narayan, Sai Teja Aluvala

Add host-driven HW rfkill handling for Intel PCIe controllers and report
state changes to the Bluetooth stack with hci_rfkill_set_hw_state().

Enable the GP2 and HW_RFKILL MSI-X hardware causes. A HW_RFKILL
interrupt schedules a delayed worker that reads the FUNC_CTRL and
IPC_CONTROL registers to determine the HW rfkill state. On assertion,
the worker marks HW rfkill as active and reports a blocked state. On
release, it clears the IPC_CONTROL HW rfkill doorbell, waits for the
firmware GP2 acknowledgment, and reports an unblocked state only after
the acknowledgment is received. IPC_CONTROL updates are serialized with
a new ipc_lock.

After a successful setup, schedule an initial state check. That check
reports an already asserted HW rfkill state but does not report an
unblocked transition when rfkill was never asserted. The check flag is
consumed on every run so that it cannot suppress a later genuine
release.

On shutdown, cancel the worker and re-assert the doorbell if HW rfkill
is active before calling the common Intel shutdown handler. Cancel the
worker on remove, and disable it across PCIe FLR/PLDR recovery so that
it does not access registers while the device is being reset.

Signed-off-by: Sai Teja Aluvala <aluvala.sai.teja@intel.com>
---
 drivers/bluetooth/btintel_pcie.c | 140 ++++++++++++++++++++++++++++++-
 drivers/bluetooth/btintel_pcie.h |  27 ++++++
 2 files changed, 163 insertions(+), 4 deletions(-)

diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c
index bcbfe2d5151a..d3c7842b3e43 100644
--- a/drivers/bluetooth/btintel_pcie.c
+++ b/drivers/bluetooth/btintel_pcie.c
@@ -2708,6 +2708,106 @@ static inline bool btintel_pcie_is_txackq_empty(struct btintel_pcie_data *data)
 	return data->ia.cr_tia[BTINTEL_PCIE_TXQ_NUM] == data->ia.cr_hia[BTINTEL_PCIE_TXQ_NUM];
 }
 
+static bool btintel_pcie_hw_rfkill_doorbell(struct btintel_pcie_data *data,
+					    bool state)
+{
+	unsigned long flags;
+	u32 reg;
+	int err;
+
+	data->rfkill_wait_done = false;
+
+	spin_lock_irqsave(&data->ipc_lock, flags);
+	reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_IPC_CONTROL_REG);
+	if (state)
+		reg |= BTINTEL_PCIE_CSR_IPC_CONTROL_HW_RFKILL;
+	else
+		reg &= ~BTINTEL_PCIE_CSR_IPC_CONTROL_HW_RFKILL;
+	btintel_pcie_wr_reg32(data, BTINTEL_PCIE_CSR_IPC_CONTROL_REG, reg);
+	spin_unlock_irqrestore(&data->ipc_lock, flags);
+
+	err = wait_event_timeout(data->rfkill_wait_q, data->rfkill_wait_done,
+				 msecs_to_jiffies(BTINTEL_PCIE_HW_RFKILL_INTERRUPT_TIMEOUT));
+	if (!err) {
+		bt_dev_err(data->hdev, "Timeout (%u ms) on alive interrupt for RFKILL",
+			   BTINTEL_PCIE_HW_RFKILL_INTERRUPT_TIMEOUT);
+		return false;
+	}
+
+	return true;
+}
+
+static void btintel_pcie_hw_rfkill_delay_work(struct work_struct *wk)
+{
+	struct btintel_pcie_data *data =
+		container_of(wk, struct btintel_pcie_data, hw_rfkill_work.work);
+	u32 func_ctrl, ipc_ctrl;
+	bool set_rfkill, first_check;
+
+	/* Consume the initial post-setup state check unconditionally so it
+	 * cannot get stuck set after the "on" branch runs, which would
+	 * otherwise cause the next genuine "off" transition to be skipped.
+	 */
+	first_check = test_and_clear_bit(BTINTEL_PCIE_HW_RFKILL_STATE_CHECK,
+					 &data->flags);
+
+	func_ctrl = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_FUNC_CTRL_REG);
+	ipc_ctrl = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_IPC_CONTROL_REG);
+
+	set_rfkill = !(func_ctrl & BTINTEL_PCIE_CSR_FUNC_CTRL_HW_RFKILL) &&
+			    !(ipc_ctrl & BTINTEL_PCIE_CSR_IPC_CONTROL_HW_RFKILL);
+	if (set_rfkill) {
+		bt_dev_dbg(data->hdev, "hw rfkill on");
+		set_bit(BTINTEL_PCIE_HWRFKILL_ON, &data->flags);
+		hci_rfkill_set_hw_state(data->hdev, true);
+	} else {
+		bt_dev_dbg(data->hdev, "hw rfkill off");
+		/* Nothing changed at the initial post-setup check, so there
+		 * is no transition to report.
+		 */
+		if (first_check)
+			return;
+
+		if (btintel_pcie_hw_rfkill_doorbell(data, false)) {
+			clear_bit(BTINTEL_PCIE_HWRFKILL_ON, &data->flags);
+			hci_rfkill_set_hw_state(data->hdev, false);
+		}
+	}
+}
+
+static void btintel_delayed_hw_rfkill(struct btintel_pcie_data *data,
+				      bool delay)
+{
+	mod_delayed_work(system_wq, &data->hw_rfkill_work,
+			 delay ? msecs_to_jiffies(BTINTEL_PCIE_HW_RFKILL_DELAY) : 0);
+}
+
+static void btintel_pcie_msix_gp2_handler(struct btintel_pcie_data *data)
+{
+	u32 reg, boot_stage_reg;
+
+	boot_stage_reg = btintel_pcie_rd_reg32(data,
+					       BTINTEL_PCIE_CSR_BOOT_STAGE_REG);
+	reg = btintel_pcie_rd_reg32(data, BTINTEL_PCIE_CSR_IPC_STATUS_REG);
+
+	if ((reg & BTINTEL_PCIE_CSR_IPC_STATUS_HW_RFKILL) &&
+	    (boot_stage_reg & BTINTEL_PCIE_CSR_BOOT_STAGE_HW_RFKILL_STATE)) {
+		bt_dev_dbg(data->hdev,
+			   "firmware done handling HW RF-KILL SET state update");
+		data->rfkill_wait_done = true;
+	}
+
+	if (!(reg & BTINTEL_PCIE_CSR_IPC_STATUS_HW_RFKILL) &&
+	    !(boot_stage_reg & BTINTEL_PCIE_CSR_BOOT_STAGE_HW_RFKILL_STATE)) {
+		bt_dev_dbg(data->hdev,
+			   "firmware done handling HW RF-KILL CLEAR state update");
+		data->rfkill_wait_done = true;
+	}
+
+	if (data->rfkill_wait_done)
+		wake_up(&data->rfkill_wait_q);
+}
+
 static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id)
 {
 	struct msix_entry *entry = dev_id;
@@ -2738,6 +2838,8 @@ static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id)
 	if (intr_hw & BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP1)
 		btintel_pcie_msix_gp1_handler(data);
 
+	if (intr_hw & BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP2)
+		btintel_pcie_msix_gp2_handler(data);
 
 	/* For TX */
 	if (intr_fh & BTINTEL_PCIE_MSIX_FH_INT_CAUSES_0) {
@@ -2756,6 +2858,9 @@ static irqreturn_t btintel_pcie_irq_msix_handler(int irq, void *dev_id)
 	if (intr_hw & BTINTEL_PCIE_MSIX_HW_INT_CAUSES_FWTRIG)
 		btintel_pcie_msix_fw_trigger_handler(data);
 
+	if (intr_hw & BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HW_RFKILL)
+		btintel_delayed_hw_rfkill(data, false);
+
 	/* This interrupt is triggered by the firmware after updating
 	 * boot_stage register and image_response register
 	 */
@@ -2829,8 +2934,10 @@ static struct btintel_pcie_causes_list causes_list[] = {
 	{ BTINTEL_PCIE_MSIX_FH_INT_CAUSES_0,	BTINTEL_PCIE_CSR_MSIX_FH_INT_MASK,	0x00 },
 	{ BTINTEL_PCIE_MSIX_FH_INT_CAUSES_1,	BTINTEL_PCIE_CSR_MSIX_FH_INT_MASK,	0x01 },
 	{ BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0,	BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK,	0x20 },
+	{ BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP2,	BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK,	0x22 },
 	{ BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HWEXP, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK,	0x23 },
 	{ BTINTEL_PCIE_MSIX_HW_INT_CAUSES_FWTRIG, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK,	0x25 },
+	{ BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HW_RFKILL, BTINTEL_PCIE_CSR_MSIX_HW_INT_MASK,	0x27 },
 };
 
 /* This function configures the interrupt masks for both HW_INT_CAUSES and
@@ -3548,8 +3655,11 @@ static int btintel_pcie_setup(struct hci_dev *hdev)
 		btintel_pcie_start_rx(data);
 	}
 
-	if (!err)
+	if (!err) {
 		set_bit(BTINTEL_PCIE_SETUP_DONE, &data->flags);
+		set_bit(BTINTEL_PCIE_HW_RFKILL_STATE_CHECK, &data->flags);
+		btintel_delayed_hw_rfkill(data, true);
+	}
 	return err;
 }
 
@@ -3781,13 +3891,14 @@ static void btintel_pcie_reset_work(struct work_struct *wk)
 	btintel_pcie_synchronize_irqs(data);
 
 	flush_work(&data->rx_work);
-	/* Drain any in-flight dump workers and block new ones across reset.
-	 * Safe from self-deadlock: they all run on a separate wq.
+	/* Drain any in-flight dump/rfkill workers and block new ones across
+	 * reset. Safe from self-deadlock: they all run on a separate wq.
 	 */
 	disable_work_sync(&data->coredump_work);
 	disable_work_sync(&data->hwexp_work);
 	disable_work_sync(&data->fwtrigger_work);
 	disable_work_sync(&data->mbox_work);
+	disable_delayed_work_sync(&data->hw_rfkill_work);
 
 	bt_dev_dbg(data->hdev, "Release bluetooth interface");
 
@@ -3813,6 +3924,7 @@ static void btintel_pcie_reset_work(struct work_struct *wk)
 		enable_work(&data->hwexp_work);
 		enable_work(&data->fwtrigger_work);
 		enable_work(&data->mbox_work);
+		enable_delayed_work(&data->hw_rfkill_work);
 	}
 
 out:
@@ -4003,6 +4115,18 @@ static struct hci_drv btintel_pcie_hci_drv = {
 	.specific_handlers      = btintel_pcie_hci_drv_specific_handlers,
 };
 
+static int btintel_pcie_shutdown(struct hci_dev *hdev)
+{
+	struct btintel_pcie_data *data = hci_get_drvdata(hdev);
+
+	cancel_delayed_work_sync(&data->hw_rfkill_work);
+
+	if (test_bit(BTINTEL_PCIE_HWRFKILL_ON, &data->flags))
+		btintel_pcie_hw_rfkill_doorbell(data, true);
+
+	return btintel_shutdown_combined(hdev);
+}
+
 static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data)
 {
 	int err;
@@ -4022,7 +4146,7 @@ static int btintel_pcie_setup_hdev(struct btintel_pcie_data *data)
 	hdev->close = btintel_pcie_close;
 	hdev->send = btintel_pcie_send_frame;
 	hdev->setup = btintel_pcie_setup;
-	hdev->shutdown = btintel_shutdown_combined;
+	hdev->shutdown = btintel_pcie_shutdown;
 	hdev->hw_error = btintel_pcie_hw_error;
 	hdev->set_diag = btintel_set_diag;
 	hdev->set_bdaddr = btintel_set_bdaddr;
@@ -4063,6 +4187,7 @@ static int btintel_pcie_probe(struct pci_dev *pdev,
 
 	spin_lock_init(&data->irq_lock);
 	spin_lock_init(&data->hci_rx_lock);
+	spin_lock_init(&data->ipc_lock);
 
 	init_waitqueue_head(&data->gp0_wait_q);
 	data->gp0_received = false;
@@ -4070,6 +4195,9 @@ static int btintel_pcie_probe(struct pci_dev *pdev,
 	init_waitqueue_head(&data->tx_wait_q);
 	data->tx_wait_done = false;
 
+	init_waitqueue_head(&data->rfkill_wait_q);
+	data->rfkill_wait_done = false;
+
 	init_waitqueue_head(&data->mbox_parse_wait_q);
 
 	data->workqueue = alloc_ordered_workqueue(KBUILD_MODNAME, WQ_HIGHPRI);
@@ -4084,6 +4212,8 @@ static int btintel_pcie_probe(struct pci_dev *pdev,
 
 	skb_queue_head_init(&data->rx_skb_q);
 	INIT_WORK(&data->rx_work, btintel_pcie_rx_work);
+	INIT_DELAYED_WORK(&data->hw_rfkill_work,
+			  btintel_pcie_hw_rfkill_delay_work);
 	INIT_WORK(&data->reset_work, btintel_pcie_reset_work);
 	INIT_WORK(&data->coredump_work, btintel_pcie_coredump_worker);
 	INIT_WORK(&data->hwexp_work, btintel_pcie_hwexp_worker);
@@ -4173,6 +4303,8 @@ static void btintel_pcie_remove(struct pci_dev *pdev)
 
 	btintel_pcie_synchronize_irqs(data);
 
+	cancel_delayed_work_sync(&data->hw_rfkill_work);
+
 	flush_work(&data->rx_work);
 
 	btintel_pcie_reset_bt(data);
diff --git a/drivers/bluetooth/btintel_pcie.h b/drivers/bluetooth/btintel_pcie.h
index 3030b4e8b750..55f08d6b621c 100644
--- a/drivers/bluetooth/btintel_pcie.h
+++ b/drivers/bluetooth/btintel_pcie.h
@@ -33,6 +33,7 @@
 #define BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_INIT		(BIT(6))
 #define BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT		(BIT(7))
 #define BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_STS	(BIT(20))
+#define BTINTEL_PCIE_CSR_FUNC_CTRL_HW_RFKILL		(BIT(27))
 
 #define BTINTEL_PCIE_CSR_FUNC_CTRL_MAC_ACCESS_REQ	(BIT(21))
 
@@ -40,6 +41,12 @@
 #define BTINTEL_PCIE_CSR_FUNC_CTRL_BUS_MASTER_DISCON	(BIT(29))
 #define BTINTEL_PCIE_CSR_FUNC_CTRL_SW_RESET		(BIT(31))
 
+/* BTINTEL PCIE CSR IPC Control Register */
+#define BTINTEL_PCIE_CSR_IPC_CONTROL_HW_RFKILL		(BIT(7))
+
+/* BTINTEL PCIE CSR IPC Status Register */
+#define BTINTEL_PCIE_CSR_IPC_STATUS_HW_RFKILL		(BIT(7))
+
 /* Value for BTINTEL_PCIE_CSR_BOOT_STAGE register */
 #define BTINTEL_PCIE_CSR_BOOT_STAGE_ROM		(BIT(0))
 #define BTINTEL_PCIE_CSR_BOOT_STAGE_IML		(BIT(1))
@@ -53,6 +60,7 @@
 #define BTINTEL_PCIE_CSR_BOOT_STAGE_ALIVE		(BIT(23))
 /* Reflects live D-state. Updated by hardware on every D-state transition. */
 #define BTINTEL_PCIE_CSR_BOOT_STAGE_D3_STATE_READY	(BIT(24))
+#define BTINTEL_PCIE_CSR_BOOT_STAGE_HW_RFKILL_STATE	(BIT(25))
 
 #define BTINTEL_PCIE_CSR_DOORBELL_MBOX_READ_CONFIRM	(BIT(4))
 
@@ -135,8 +143,10 @@ enum msix_fh_int_causes {
 enum msix_hw_int_causes {
 	BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP0	= BIT(0),	/* cause 32 */
 	BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP1	= BIT(1),	/* cause 33 */
+	BTINTEL_PCIE_MSIX_HW_INT_CAUSES_GP2	= BIT(2),	/* cause 34 */
 	BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HWEXP	= BIT(3),	/* cause 35 */
 	BTINTEL_PCIE_MSIX_HW_INT_CAUSES_FWTRIG	= BIT(5),	/* cause 37 */
+	BTINTEL_PCIE_MSIX_HW_INT_CAUSES_HW_RFKILL	= BIT(7),	/* cause 39 */
 };
 
 /* PCIe device states
@@ -155,6 +165,8 @@ enum {
 	BTINTEL_PCIE_COREDUMP_INPROGRESS,
 	BTINTEL_PCIE_FWTRIGGER_DUMP_INPROGRESS,
 	BTINTEL_PCIE_RECOVERY_IN_PROGRESS,
+	BTINTEL_PCIE_HWRFKILL_ON,
+	BTINTEL_PCIE_HW_RFKILL_STATE_CHECK,
 	BTINTEL_PCIE_SETUP_DONE,
 	BTINTEL_PCIE_MAIL_BOX_INTR,
 	BTINTEL_PCIE_MBOX_PARSE_PENDING,
@@ -215,6 +227,12 @@ enum btintel_pcie_mbox_msg {
 
 #define BTINTEL_PCIE_DX_TRANSITION_MAX_RETRIES	3
 
+/* HW rfkill interrupt timeout */
+#define BTINTEL_PCIE_HW_RFKILL_INTERRUPT_TIMEOUT	200
+
+/* HW rfkill check timeout */
+#define BTINTEL_PCIE_HW_RFKILL_DELAY			1000
+
 /* The number of descriptors in TX queues */
 #define BTINTEL_PCIE_TX_DESCS_COUNT	32
 
@@ -680,6 +698,7 @@ struct btintel_pcie_ini_dump_info {
  * @flags: driver state
  * @irq_lock: spinlock for MSI-X
  * @hci_rx_lock: spinlock for HCI RX flow
+ * @ipc_lock: spinlock for IPC control register read-modify-write
  * @base_addr: pci base address (from BAR)
  * @msix_entries: array of MSI-X entries
  * @msix_enabled: true if MSI-X is enabled;
@@ -696,6 +715,8 @@ struct btintel_pcie_ini_dump_info {
  * @gp0_wait_q: wait_q for gp0 interrupt
  * @tx_wait_done: condition for tx interrupt
  * @tx_wait_q: wait_q for tx interrupt
+ * @rfkill_wait_done: condition for HW rfkill GP2 interrupt
+ * @rfkill_wait_q: wait_q for HW rfkill GP2 interrupt
  * @workqueue: workqueue for RX work
  * @rx_skb_q: SKB queue for RX packet
  * @rx_work: RX work struct to process the RX packet in @rx_skb_q
@@ -723,6 +744,8 @@ struct btintel_pcie_data {
 	spinlock_t	irq_lock;
 	/* lock to serialize rx events */
 	spinlock_t	hci_rx_lock;
+	/* lock to serialize IPC control register updates */
+	spinlock_t	ipc_lock;
 
 	void __iomem	*base_addr;
 
@@ -747,9 +770,13 @@ struct btintel_pcie_data {
 	bool	tx_wait_done;
 	wait_queue_head_t	tx_wait_q;
 
+	bool	rfkill_wait_done;
+	wait_queue_head_t	rfkill_wait_q;
+
 	struct workqueue_struct	*workqueue;
 	struct sk_buff_head	rx_skb_q;
 	struct work_struct	rx_work;
+	struct delayed_work	hw_rfkill_work;
 	struct work_struct      reset_work;
 
 	struct workqueue_struct	*dump_workqueue;
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* RE: Bluetooth: add hardware rfkill handling
  2026-10-02  1:43 ` [PATCH v2 1/2] Bluetooth: Add interface to allow stack to communicate hw rfkill events Sai Teja Aluvala
@ 2026-10-02  3:14   ` bluez.test.bot
  0 siblings, 0 replies; 5+ messages in thread
From: bluez.test.bot @ 2026-10-02  3:14 UTC (permalink / raw)
  To: linux-bluetooth, aluvala.sai.teja

[-- Attachment #1: Type: text/plain, Size: 2225 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/series/1178028/

---Test result---

Test Summary:
CheckPatch                    PASS      1.50 seconds
VerifyFixes                   PASS      0.86 seconds
VerifySignedoff               PASS      0.74 seconds
GitLint                       PASS      0.56 seconds
SubjectPrefix                 PASS      0.17 seconds
BuildKernel                   PASS      22.65 seconds
CheckAllWarning               PASS      26.26 seconds
CheckSparse                   PASS      27.89 seconds
BuildKernel32                 PASS      22.88 seconds
CheckKernelLLVM               PASS      25.29 seconds
TestRunnerSetup               PASS      566.67 seconds
TestRunner_l2cap-tester       PASS      13.50 seconds
TestRunner_iso-tester         PASS      9.48 seconds
TestRunner_bnep-tester        PASS      2.74 seconds
TestRunner_mgmt-tester        FAIL      56.99 seconds
TestRunner_rfcomm-tester      PASS      4.01 seconds
TestRunner_sco-tester         PASS      5.04 seconds
TestRunner_ioctl-tester       PASS      4.14 seconds
TestRunner_mesh-tester        FAIL      7.64 seconds
TestRunner_smp-tester         PASS      3.91 seconds
TestRunner_userchan-tester    PASS      7.88 seconds
TestRunner_6lowpan-tester     PASS      5.01 seconds
IncrementalBuild              PASS      23.03 seconds

Details
##############################
Test: TestRunner_mgmt-tester - FAIL
Desc: Run mgmt-tester with test-runner
Output:
Total: 503, Passed: 502 (99.8%), Failed: 1, Not Run: 0

Failed Test Cases
Pairing Acceptor - LE Security Level Changed         Failed       0.020 seconds
##############################
Test: TestRunner_mesh-tester - FAIL
Desc: Run mesh-tester with test-runner
Output:
Total: 10, Passed: 8 (80.0%), Failed: 2, Not Run: 0

Failed Test Cases
Mesh - Send cancel - 1                               Timed out    2.668 seconds
Mesh - Send cancel - 2                               Timed out    1.998 seconds


https://github.com/bluez/bluetooth-next/pull/849

---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v2 0/2] Bluetooth: add hardware rfkill handling
  2026-10-02  1:43 [PATCH v2 0/2] Bluetooth: add hardware rfkill handling Sai Teja Aluvala
  2026-10-02  1:43 ` [PATCH v2 1/2] Bluetooth: Add interface to allow stack to communicate hw rfkill events Sai Teja Aluvala
  2026-10-02  1:43 ` [PATCH v2 2/2] Bluetooth: btintel_pcie: add HW rfkill interrupt/doorbell flow Sai Teja Aluvala
@ 2026-10-02 15:24 ` Luiz Augusto von Dentz
  2 siblings, 0 replies; 5+ messages in thread
From: Luiz Augusto von Dentz @ 2026-10-02 15:24 UTC (permalink / raw)
  To: Sai Teja Aluvala; +Cc: linux-bluetooth, kiran.k, chethan.tumkur.narayan

Hi Sai,

On Thu, Oct 1, 2026 at 9:52 PM Sai Teja Aluvala
<aluvala.sai.teja@intel.com> wrote:
>
> This series adds hardware rfkill handling for the Intel PCIe transport and
> the Bluetooth-side notification path.
>
> The resulting flow is:
>
>   transport hardware event
>     -> hci_rfkill_set_hw_state()
>     -> rfkill hardware state
>     -> hdev->rfkill_block work
>     -> HCI_RFKILLED state and device power handling
>
> For Intel PCIe controllers, the series adds GP2 and HW_RFKILL MSI-X
> handling, IPC_CONTROL doorbell synchronization, delayed state checking,
> reset/shutdown/remove lifecycle handling, and notification of the
> generic HCI rfkill layer.
>
> Compared with v1, this version drops the Bluetooth-specific debugfs test
> hook, the redundant hdev->rfkill pointer-clear patch, and the separate
> RFKILL-core helper dependency. The real btintel_pcie hardware event path
> and HCI notification interface are retained.
>
> Sai Teja Aluvala (2):
>   Bluetooth: Add interface to allow stack to communicate hw rfkill
>     events
>   Bluetooth: btintel_pcie: add HW rfkill interrupt/doorbell flow
>
>  drivers/bluetooth/btintel_pcie.c | 140 ++++++++++++++++++++++++++++++-
>  drivers/bluetooth/btintel_pcie.h |  27 ++++++
>  include/net/bluetooth/hci_core.h |   3 +
>  net/bluetooth/hci_core.c         |  34 ++++++++
>  4 files changed, 200 insertions(+), 4 deletions(-)
>
>
> base-commit: 3b44711c52eaf62723a4a715e1b7b4e49f1595ce
> --
> 2.53.0

Sashiko flagged quite a few issues:

https://sashiko.dev/#/patchset/cover.1790905146.git.aluvala.sai.teja%40intel.com

-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-10-02 15:24 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-02  1:43 [PATCH v2 0/2] Bluetooth: add hardware rfkill handling Sai Teja Aluvala
2026-10-02  1:43 ` [PATCH v2 1/2] Bluetooth: Add interface to allow stack to communicate hw rfkill events Sai Teja Aluvala
2026-10-02  3:14   ` Bluetooth: add hardware rfkill handling bluez.test.bot
2026-10-02  1:43 ` [PATCH v2 2/2] Bluetooth: btintel_pcie: add HW rfkill interrupt/doorbell flow Sai Teja Aluvala
2026-10-02 15:24 ` [PATCH v2 0/2] Bluetooth: add hardware rfkill handling Luiz Augusto von Dentz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox