Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH] bluetooth: hci_bcm4377: Implement Runtime PM support
@ 2026-07-15 14:59 gg582
  2026-07-15 15:07 ` bluez.test.bot
  0 siblings, 1 reply; 2+ messages in thread
From: gg582 @ 2026-07-15 14:59 UTC (permalink / raw)
  To: marcel@holtmann.org, luiz.dentz@gmail.com, sven@kernel.org,
	j@jannau.net
  Cc: neal@gompa.dev, linux-bluetooth@vger.kernel.org,
	asahi@lists.linux.dev, linux-kernel@vger.kernel.org

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

From dc47862023158e5a244a0a2b9025dd544e658a13 Mon Sep 17 00:00:00 2001
From: Lee Yunjin <gg582@proton.me>
Date: Fri, 3 Jul 2026 10:12:56 +0900
Subject: [PATCH] bluetooth: hci_bcm4377: Implement Runtime PM support

Signed-off-by: Lee Yunjin <gg582@proton.me>
---
 drivers/bluetooth/hci_bcm4377.c | 96 +++++++++++++++++++++++++++++++--
 1 file changed, 91 insertions(+), 5 deletions(-)

diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c
index 5f79920c0306..0d5f818bde71 100644
--- a/drivers/bluetooth/hci_bcm4377.c
+++ b/drivers/bluetooth/hci_bcm4377.c
@@ -15,6 +15,7 @@
 #include <linux/msi.h>
 #include <linux/of.h>
 #include <linux/pci.h>
+#include <linux/pm_runtime.h>
 #include <linux/printk.h>
 
 #include <linux/unaligned.h>
@@ -840,6 +841,8 @@ static irqreturn_t bcm4377_irq(int irq, void *data)
 	struct bcm4377_data *bcm4377 = data;
 	u32 bootstage, rti_status;
 
+	pm_runtime_get(&bcm4377->pdev->dev);
+
 	bootstage = ioread32(bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_BOOTSTAGE);
 	rti_status = ioread32(bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_RTI_STATUS);
 
@@ -863,6 +866,9 @@ static irqreturn_t bcm4377_irq(int irq, void *data)
 	bcm4377_poll_completion_ring(bcm4377, &bcm4377->sco_ack_ring);
 	bcm4377_poll_completion_ring(bcm4377, &bcm4377->sco_event_ring);
 
+	pm_runtime_mark_last_busy(&bcm4377->pdev->dev);
+	pm_runtime_put_autosuspend(&bcm4377->pdev->dev);
+
 	return IRQ_HANDLED;
 }
 
@@ -892,6 +898,8 @@ static int bcm4377_enqueue(struct bcm4377_data *bcm4377,
 	if (ring->virtual)
 		return -EINVAL;
 
+	pm_runtime_get(&bcm4377->pdev->dev);
+
 	spin_lock_irqsave(&ring->lock, flags);
 
 	head = le16_to_cpu(bcm4377->ring_state->xfer_ring_head[ring->ring_id]);
@@ -974,6 +982,8 @@ static int bcm4377_enqueue(struct bcm4377_data *bcm4377,
 		spin_unlock_irqrestore(&ring->lock, flags);
 	}
 
+	pm_runtime_mark_last_busy(&bcm4377->pdev->dev);
+	pm_runtime_put_autosuspend(&bcm4377->pdev->dev);
 	return ret;
 }
 
@@ -1309,6 +1319,12 @@ static int bcm4377_hci_open(struct hci_dev *hdev)
 	struct bcm4377_data *bcm4377 = hci_get_drvdata(hdev);
 	int ret;
 
+	ret = pm_runtime_get_sync(&bcm4377->pdev->dev);
+	if (ret < 0) {
+		pm_runtime_put_noidle(&bcm4377->pdev->dev);
+		return ret;
+	}
+
 	dev_dbg(&bcm4377->pdev->dev, "creating rings\n");
 
 	ret = bcm4377_create_completion_ring(bcm4377,
@@ -1392,6 +1408,8 @@ static int bcm4377_hci_close(struct hci_dev *hdev)
 	bcm4377_destroy_completion_ring(bcm4377, &bcm4377->hci_acl_event_ring);
 	bcm4377_destroy_completion_ring(bcm4377, &bcm4377->hci_acl_ack_ring);
 
+	pm_runtime_put_sync_suspend(&bcm4377->pdev->dev);
+
 	return 0;
 }
 
@@ -2273,6 +2291,14 @@ static void bcm4377_hci_unregister_dev(void *data)
 	hci_unregister_dev(data);
 }
 
+static void bcm4377_pm_runtime_disable(void *data)
+{
+	struct pci_dev *pdev = data;
+
+	pm_runtime_dont_use_autosuspend(&pdev->dev);
+	pm_runtime_forbid(&pdev->dev);
+}
+
 static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	struct bcm4377_data *bcm4377;
@@ -2414,8 +2440,25 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	ret = hci_register_dev(hdev);
 	if (ret)
 		return ret;
-	return devm_add_action_or_reset(&pdev->dev, bcm4377_hci_unregister_dev,
-					hdev);
+	ret = devm_add_action_or_reset(&pdev->dev, bcm4377_hci_unregister_dev,
+				       hdev);
+	if (ret)
+		return ret;
+
+	ret = devm_add_action_or_reset(&pdev->dev, bcm4377_pm_runtime_disable,
+				       pdev);
+	if (ret)
+		return ret;
+
+	pm_runtime_set_autosuspend_delay(&pdev->dev, 2000);
+	pm_runtime_use_autosuspend(&pdev->dev);
+	/* pm_runtime_enable() already called by PCI bus core (pci/bus.c);
+	 * calling it again would cause "Unbalanced pm_runtime_enable!"
+	 * pm_runtime_irq_safe(&pdev->dev) is removed to avoid lock/timing issues in GNOME bluetooth. */
+	pm_runtime_mark_last_busy(&pdev->dev);
+	pm_runtime_put_autosuspend(&pdev->dev);
+
+	return 0;
 }
 
 static int bcm4377_suspend(struct device *dev)
@@ -2424,9 +2467,17 @@ static int bcm4377_suspend(struct device *dev)
 	struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev);
 	int ret;
 
+	ret = pm_runtime_get_sync(dev);
+	if (ret < 0) {
+		pm_runtime_put_noidle(dev);
+		return ret;
+	}
+
 	ret = hci_suspend_dev(bcm4377->hdev);
-	if (ret)
+	if (ret) {
+		pm_runtime_put_sync(dev);
 		return ret;
+	}
 
 	iowrite32(BCM4377_BAR0_SLEEP_CONTROL_QUIESCE,
 		  bcm4377->bar0 + BCM4377_BAR0_SLEEP_CONTROL);
@@ -2438,15 +2489,50 @@ static int bcm4377_resume(struct device *dev)
 {
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev);
+	int ret;
 
 	iowrite32(BCM4377_BAR0_SLEEP_CONTROL_UNQUIESCE,
 		  bcm4377->bar0 + BCM4377_BAR0_SLEEP_CONTROL);
 
-	return hci_resume_dev(bcm4377->hdev);
+	ret = hci_resume_dev(bcm4377->hdev);
+
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
+
+	return ret;
+}
+
+static int bcm4377_runtime_suspend(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev);
+
+	iowrite32(BCM4377_BAR0_SLEEP_CONTROL_QUIESCE,
+		  bcm4377->bar0 + BCM4377_BAR0_SLEEP_CONTROL);
+
+	pci_save_state(pdev);
+	return 0;
+}
+
+static int bcm4377_runtime_resume(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev);
+
+	iowrite32(BCM4377_BAR0_SLEEP_CONTROL_UNQUIESCE,
+		  bcm4377->bar0 + BCM4377_BAR0_SLEEP_CONTROL);
+
+	return 0;
 }
 
 static DEFINE_SIMPLE_DEV_PM_OPS(bcm4377_ops, bcm4377_suspend, bcm4377_resume);
 
+/* Re-define with runtime PM once callbacks are in place */
+static const struct dev_pm_ops bcm4377_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(bcm4377_suspend, bcm4377_resume)
+	SET_RUNTIME_PM_OPS(bcm4377_runtime_suspend, bcm4377_runtime_resume, NULL)
+};
+
 static const struct dmi_system_id bcm4377_dmi_board_table[] = {
 	{
 		.matches = {
@@ -2547,7 +2633,7 @@ static struct pci_driver bcm4377_pci_driver = {
 	.name = "hci_bcm4377",
 	.id_table = bcm4377_devid_table,
 	.probe = bcm4377_probe,
-	.driver.pm = &bcm4377_ops,
+	.driver.pm = &bcm4377_pm_ops,
 };
 module_pci_driver(bcm4377_pci_driver);
 
-- 
2.55.0

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-bluetooth-hci_bcm4377-Implement-Runtime-PM-support.patch --]
[-- Type: text/x-patch; name=0001-bluetooth-hci_bcm4377-Implement-Runtime-PM-support.patch, Size: 6207 bytes --]

From dc47862023158e5a244a0a2b9025dd544e658a13 Mon Sep 17 00:00:00 2001
From: Lee Yunjin <gg582@proton.me>
Date: Fri, 3 Jul 2026 10:12:56 +0900
Subject: [PATCH] bluetooth: hci_bcm4377: Implement Runtime PM support

Signed-off-by: Lee Yunjin <gg582@proton.me>
---
 drivers/bluetooth/hci_bcm4377.c | 96 +++++++++++++++++++++++++++++++--
 1 file changed, 91 insertions(+), 5 deletions(-)

diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c
index 5f79920c0306..0d5f818bde71 100644
--- a/drivers/bluetooth/hci_bcm4377.c
+++ b/drivers/bluetooth/hci_bcm4377.c
@@ -15,6 +15,7 @@
 #include <linux/msi.h>
 #include <linux/of.h>
 #include <linux/pci.h>
+#include <linux/pm_runtime.h>
 #include <linux/printk.h>
 
 #include <linux/unaligned.h>
@@ -840,6 +841,8 @@ static irqreturn_t bcm4377_irq(int irq, void *data)
 	struct bcm4377_data *bcm4377 = data;
 	u32 bootstage, rti_status;
 
+	pm_runtime_get(&bcm4377->pdev->dev);
+
 	bootstage = ioread32(bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_BOOTSTAGE);
 	rti_status = ioread32(bcm4377->bar2 + bcm4377->hw->bar2_offset + BCM4377_BAR2_RTI_STATUS);
 
@@ -863,6 +866,9 @@ static irqreturn_t bcm4377_irq(int irq, void *data)
 	bcm4377_poll_completion_ring(bcm4377, &bcm4377->sco_ack_ring);
 	bcm4377_poll_completion_ring(bcm4377, &bcm4377->sco_event_ring);
 
+	pm_runtime_mark_last_busy(&bcm4377->pdev->dev);
+	pm_runtime_put_autosuspend(&bcm4377->pdev->dev);
+
 	return IRQ_HANDLED;
 }
 
@@ -892,6 +898,8 @@ static int bcm4377_enqueue(struct bcm4377_data *bcm4377,
 	if (ring->virtual)
 		return -EINVAL;
 
+	pm_runtime_get(&bcm4377->pdev->dev);
+
 	spin_lock_irqsave(&ring->lock, flags);
 
 	head = le16_to_cpu(bcm4377->ring_state->xfer_ring_head[ring->ring_id]);
@@ -974,6 +982,8 @@ static int bcm4377_enqueue(struct bcm4377_data *bcm4377,
 		spin_unlock_irqrestore(&ring->lock, flags);
 	}
 
+	pm_runtime_mark_last_busy(&bcm4377->pdev->dev);
+	pm_runtime_put_autosuspend(&bcm4377->pdev->dev);
 	return ret;
 }
 
@@ -1309,6 +1319,12 @@ static int bcm4377_hci_open(struct hci_dev *hdev)
 	struct bcm4377_data *bcm4377 = hci_get_drvdata(hdev);
 	int ret;
 
+	ret = pm_runtime_get_sync(&bcm4377->pdev->dev);
+	if (ret < 0) {
+		pm_runtime_put_noidle(&bcm4377->pdev->dev);
+		return ret;
+	}
+
 	dev_dbg(&bcm4377->pdev->dev, "creating rings\n");
 
 	ret = bcm4377_create_completion_ring(bcm4377,
@@ -1392,6 +1408,8 @@ static int bcm4377_hci_close(struct hci_dev *hdev)
 	bcm4377_destroy_completion_ring(bcm4377, &bcm4377->hci_acl_event_ring);
 	bcm4377_destroy_completion_ring(bcm4377, &bcm4377->hci_acl_ack_ring);
 
+	pm_runtime_put_sync_suspend(&bcm4377->pdev->dev);
+
 	return 0;
 }
 
@@ -2273,6 +2291,14 @@ static void bcm4377_hci_unregister_dev(void *data)
 	hci_unregister_dev(data);
 }
 
+static void bcm4377_pm_runtime_disable(void *data)
+{
+	struct pci_dev *pdev = data;
+
+	pm_runtime_dont_use_autosuspend(&pdev->dev);
+	pm_runtime_forbid(&pdev->dev);
+}
+
 static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	struct bcm4377_data *bcm4377;
@@ -2414,8 +2440,25 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	ret = hci_register_dev(hdev);
 	if (ret)
 		return ret;
-	return devm_add_action_or_reset(&pdev->dev, bcm4377_hci_unregister_dev,
-					hdev);
+	ret = devm_add_action_or_reset(&pdev->dev, bcm4377_hci_unregister_dev,
+				       hdev);
+	if (ret)
+		return ret;
+
+	ret = devm_add_action_or_reset(&pdev->dev, bcm4377_pm_runtime_disable,
+				       pdev);
+	if (ret)
+		return ret;
+
+	pm_runtime_set_autosuspend_delay(&pdev->dev, 2000);
+	pm_runtime_use_autosuspend(&pdev->dev);
+	/* pm_runtime_enable() already called by PCI bus core (pci/bus.c);
+	 * calling it again would cause "Unbalanced pm_runtime_enable!"
+	 * pm_runtime_irq_safe(&pdev->dev) is removed to avoid lock/timing issues in GNOME bluetooth. */
+	pm_runtime_mark_last_busy(&pdev->dev);
+	pm_runtime_put_autosuspend(&pdev->dev);
+
+	return 0;
 }
 
 static int bcm4377_suspend(struct device *dev)
@@ -2424,9 +2467,17 @@ static int bcm4377_suspend(struct device *dev)
 	struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev);
 	int ret;
 
+	ret = pm_runtime_get_sync(dev);
+	if (ret < 0) {
+		pm_runtime_put_noidle(dev);
+		return ret;
+	}
+
 	ret = hci_suspend_dev(bcm4377->hdev);
-	if (ret)
+	if (ret) {
+		pm_runtime_put_sync(dev);
 		return ret;
+	}
 
 	iowrite32(BCM4377_BAR0_SLEEP_CONTROL_QUIESCE,
 		  bcm4377->bar0 + BCM4377_BAR0_SLEEP_CONTROL);
@@ -2438,15 +2489,50 @@ static int bcm4377_resume(struct device *dev)
 {
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev);
+	int ret;
 
 	iowrite32(BCM4377_BAR0_SLEEP_CONTROL_UNQUIESCE,
 		  bcm4377->bar0 + BCM4377_BAR0_SLEEP_CONTROL);
 
-	return hci_resume_dev(bcm4377->hdev);
+	ret = hci_resume_dev(bcm4377->hdev);
+
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
+
+	return ret;
+}
+
+static int bcm4377_runtime_suspend(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev);
+
+	iowrite32(BCM4377_BAR0_SLEEP_CONTROL_QUIESCE,
+		  bcm4377->bar0 + BCM4377_BAR0_SLEEP_CONTROL);
+
+	pci_save_state(pdev);
+	return 0;
+}
+
+static int bcm4377_runtime_resume(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev);
+
+	iowrite32(BCM4377_BAR0_SLEEP_CONTROL_UNQUIESCE,
+		  bcm4377->bar0 + BCM4377_BAR0_SLEEP_CONTROL);
+
+	return 0;
 }
 
 static DEFINE_SIMPLE_DEV_PM_OPS(bcm4377_ops, bcm4377_suspend, bcm4377_resume);
 
+/* Re-define with runtime PM once callbacks are in place */
+static const struct dev_pm_ops bcm4377_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(bcm4377_suspend, bcm4377_resume)
+	SET_RUNTIME_PM_OPS(bcm4377_runtime_suspend, bcm4377_runtime_resume, NULL)
+};
+
 static const struct dmi_system_id bcm4377_dmi_board_table[] = {
 	{
 		.matches = {
@@ -2547,7 +2633,7 @@ static struct pci_driver bcm4377_pci_driver = {
 	.name = "hci_bcm4377",
 	.id_table = bcm4377_devid_table,
 	.probe = bcm4377_probe,
-	.driver.pm = &bcm4377_ops,
+	.driver.pm = &bcm4377_pm_ops,
 };
 module_pci_driver(bcm4377_pci_driver);
 
-- 
2.55.0


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

* RE: bluetooth: hci_bcm4377: Implement Runtime PM support
  2026-07-15 14:59 [PATCH] bluetooth: hci_bcm4377: Implement Runtime PM support gg582
@ 2026-07-15 15:07 ` bluez.test.bot
  0 siblings, 0 replies; 2+ messages in thread
From: bluez.test.bot @ 2026-07-15 15:07 UTC (permalink / raw)
  To: linux-bluetooth, gg582

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

This is an automated email and please do not reply to this email.

Dear Submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
While preparing the CI tests, the patches you submitted couldn't be applied to the current HEAD of the repository.

----- Output -----


Please resolve the issue and submit the patches again.


---
Regards,
Linux Bluetooth


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

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

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-15 14:59 [PATCH] bluetooth: hci_bcm4377: Implement Runtime PM support gg582
2026-07-15 15:07 ` bluez.test.bot

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