RE: [PATCH v5] Bluetooth: btintel_pcie: Add support for _suspend() / _resume()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Paul,

Appreciate your comments.

>-----Original Message-----
>From: Paul Menzel <pmenzel@xxxxxxxxxxxxx>
>Sent: Thursday, July 24, 2025 11:48 AM
>To: K, Kiran <kiran.k@xxxxxxxxx>; Devegowda, Chandrashekar
><chandrashekar.devegowda@xxxxxxxxx>
>Cc: linux-bluetooth@xxxxxxxxxxxxxxx; Srivatsa, Ravishankar
><ravishankar.srivatsa@xxxxxxxxx>; Tumkur Narayan, Chethan
><chethan.tumkur.narayan@xxxxxxxxx>; bhelgaas@xxxxxxxxxx; linux-
>pci@xxxxxxxxxxxxxxx
>Subject: Re: [PATCH v5] Bluetooth: btintel_pcie: Add support for _suspend() /
>_resume()
>
>Dear Kiran, dear Chandrashekar,
>
>
>Thank you for your patch.
>
>Am 23.07.25 um 15:57 schrieb Kiran K:
>> From: Chandrashekar Devegowda <chandrashekar.devegowda@xxxxxxxxx>
>>
>> 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:
>> [  516.418316] Bluetooth: hci0: device entered into d3 state from d0
>> in 81 us
>>
>> On system resume:
>> [  542.174128] Bluetooth: hci0: device entered into d0 state from d3
>> in 357 us
>
>Just to avoid confusion, is the timestamp correct, as this is only a 26 s
>difference and your command says 60 s. (I am only aware of inaccurate
>timestamps using human-readable format (`dmesg -T`).)
The system was woken up by key press before the sleep timeout. To avoid the confusion, I will update the traces to reflect the system waking up independently.
>
>> Signed-off-by: Chandrashekar Devegowda
>> <chandrashekar.devegowda@xxxxxxxxx>
>> Signed-off-by: Kiran K <kiran.k@xxxxxxxxx>
>> ---
>> changes in v5:
>>       - Address review comments
>
>This should be more detailed, if code was changed.
Ack.

>
>> 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 | 102 +++++++++++++++++++++++++++++++
>>   drivers/bluetooth/btintel_pcie.h |   4 ++
>>   2 files changed, 106 insertions(+)
>>
>> diff --git a/drivers/bluetooth/btintel_pcie.c
>> b/drivers/bluetooth/btintel_pcie.c
>> index 6e7bbbd35279..a96975a55cbe 100644
>> --- a/drivers/bluetooth/btintel_pcie.c
>> +++ b/drivers/bluetooth/btintel_pcie.c
>> @@ -540,6 +540,12 @@ static int btintel_pcie_reset_bt(struct
>btintel_pcie_data *data)
>>   	return reg == 0 ? 0 : -ENODEV;
>>   }
>>
>> +static void btintel_pcie_set_persistence_mode(struct
>> +btintel_pcie_data *data) {
>> +	btintel_pcie_set_reg_bits(data,
>BTINTEL_PCIE_CSR_HW_BOOT_CONFIG,
>> +
>BTINTEL_PCIE_CSR_HW_BOOT_CONFIG_KEEP_ON);
>> +}
>> +
>>   static void btintel_pcie_mac_init(struct btintel_pcie_data *data)
>>   {
>>   	u32 reg;
>> @@ -829,6 +835,8 @@ static int btintel_pcie_enable_bt(struct
>btintel_pcie_data *data)
>>   	 */
>>   	data->boot_stage_cache = 0x0;
>>
>> +	btintel_pcie_set_persistence_mode(data);
>> +
>
>This hunk is not described in the commit message.
This register write is intended to retain firmware state across a warm reboot (S5) and is not relevant to this patch. Apologies for overlooking this detail.
>
>>   	/* Set MAC_INIT bit to start primary bootloader */
>>   	reg = btintel_pcie_rd_reg32(data,
>BTINTEL_PCIE_CSR_FUNC_CTRL_REG);
>>   	reg &= ~(BTINTEL_PCIE_CSR_FUNC_CTRL_FUNC_INIT | @@ -2573,11
>> +2581,105 @@ static void btintel_pcie_coredump(struct device *dev)
>>   }
>>   #endif
>>
>> +#ifdef CONFIG_PM
>> +static int btintel_pcie_suspend_late(struct device *dev, pm_message_t
>> +mesg) {
>> +	struct pci_dev *pdev = to_pci_dev(dev);
>> +	struct btintel_pcie_data *data;
>> +	ktime_t start;
>> +	u32 dxstate;
>> +	s64 delta;
>
>Append the unit to the name? `delta_us`?
Ack
>
>> +	int err;
>> +
>> +	data = pci_get_drvdata(pdev);
>> +
>> +	if (mesg.event == PM_EVENT_SUSPEND)
>> +		dxstate = BTINTEL_PCIE_STATE_D3_HOT;
>> +	else
>> +		dxstate = BTINTEL_PCIE_STATE_D3_COLD;
>
>I’d use the ternary operator.
Ack.

>
>> +
>> +	data->gp0_received = false;
>> +
>> +	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,
>> +
>msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS));
>> +	delta = ktime_to_ns(ktime_get() - start) / 1000;
>
>Move it below right before `bt_dev_info`?
Ack.

>
>> +
>> +	if (err == 0) {
>> +		bt_dev_err(data->hdev, "Timeout (%u ms) on alive interrupt
>for D3 entry",
>> +				BTINTEL_DEFAULT_INTR_TIMEOUT_MS);
>> +		return -EBUSY;
>> +	}
>> +	bt_dev_info(data->hdev, "device entered into d3 state from d0 in %lld
>us",
>> +		    delta);
>> +	return 0;
>> +}
>> +
>> +static int btintel_pcie_suspend(struct device *dev) {
>> +	return btintel_pcie_suspend_late(dev, PMSG_SUSPEND); }
>> +
>> +static int btintel_pcie_hibernate(struct device *dev) {
>> +	return btintel_pcie_suspend_late(dev, PMSG_HIBERNATE); }
>> +
>> +static int btintel_pcie_freeze(struct device *dev) {
>> +	return btintel_pcie_suspend_late(dev, PMSG_FREEZE); }
>> +
>> +static int btintel_pcie_resume(struct device *dev) {
>> +	struct pci_dev *pdev = to_pci_dev(dev);
>> +	struct btintel_pcie_data *data;
>> +	ktime_t start;
>> +	int err;
>> +	s64 delta;
>> +
>> +	data = pci_get_drvdata(pdev);
>> +	data->gp0_received = false;
>> +
>> +	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,
>> +
>msecs_to_jiffies(BTINTEL_DEFAULT_INTR_TIMEOUT_MS));
>> +	delta = ktime_to_ns(ktime_get() - start) / 1000;
>> +
>> +	if (err == 0) {
>> +		bt_dev_err(data->hdev, "Timeout (%u ms) on alive interrupt
>for D0 entry",
>> +				BTINTEL_DEFAULT_INTR_TIMEOUT_MS);
>> +		return -EBUSY;
>> +	}
>> +	bt_dev_info(data->hdev, "device entered into d0 state from d3 in %lld
>us",
>> +		    delta);
>> +	return 0;
>> +}
>> +
>> +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,
>> +	.poweroff = btintel_pcie_hibernate,
>> +	.restore = btintel_pcie_resume,
>> +};
>> +#define BTINTELPCIE_PM_OPS	(&btintel_pcie_pm_ops)
>> +#else
>> +#define BTINTELPCIE_PM_OPS	NULL
>> +#endif
>>   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 = BTINTELPCIE_PM_OPS,
>>   #ifdef CONFIG_DEV_COREDUMP
>>   	.driver.coredump = btintel_pcie_coredump
>>   #endif
>> diff --git a/drivers/bluetooth/btintel_pcie.h
>> b/drivers/bluetooth/btintel_pcie.h
>> index 0fa876c5b954..5bc69004b692 100644
>> --- a/drivers/bluetooth/btintel_pcie.h
>> +++ b/drivers/bluetooth/btintel_pcie.h
>> @@ -8,6 +8,7 @@
>>
>>   /* Control and Status Register(BTINTEL_PCIE_CSR) */
>>   #define BTINTEL_PCIE_CSR_BASE			(0x000)
>> +#define BTINTEL_PCIE_CSR_HW_BOOT_CONFIG
>	(BTINTEL_PCIE_CSR_BASE + 0x000)
>>   #define BTINTEL_PCIE_CSR_FUNC_CTRL_REG
>	(BTINTEL_PCIE_CSR_BASE + 0x024)
>>   #define BTINTEL_PCIE_CSR_HW_REV_REG
>	(BTINTEL_PCIE_CSR_BASE + 0x028)
>>   #define BTINTEL_PCIE_CSR_RF_ID_REG
>	(BTINTEL_PCIE_CSR_BASE + 0x09C)
>> @@ -55,6 +56,9 @@
>>   #define BTINTEL_PCIE_CSR_BOOT_STAGE_ALIVE		(BIT(23))
>>   #define BTINTEL_PCIE_CSR_BOOT_STAGE_D3_STATE_READY	(BIT(24))
>>
>> +/* CSR HW BOOT CONFIG Register */
>> +#define BTINTEL_PCIE_CSR_HW_BOOT_CONFIG_KEEP_ON
>	(BIT(31))
>> +
>>   /* Registers for MSI-X */
>>   #define BTINTEL_PCIE_CSR_MSIX_BASE		(0x2000)
>>   #define BTINTEL_PCIE_CSR_MSIX_FH_INT_CAUSES
>	(BTINTEL_PCIE_CSR_MSIX_BASE + 0x0800)
>
>
>Kind regards,
>
>Paul

Thanks,
Kiran





[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux