linux-bluetooth.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/5] Bluetooth: hci_bcm: Add wake-up and PM runtime support
@ 2015-09-15  8:31 Frederic Danis
  2015-09-15  8:31 ` [PATCH v4 1/5] Bluetooth: Add BT_WARN and bt_dev_warn logging macros Frederic Danis
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Frederic Danis @ 2015-09-15  8:31 UTC (permalink / raw)
  To: linux-bluetooth

Add wake-up capabilities by retrieveing interruption used by BCM device in ACPI
table.
Add PM runtime support.

v3->v4:
- Add new BT_WARN and bt_dev_warn logging macros
- Use bt_dev_warn for T100 irq polarity fix
- Rename __bcm_suspend to bcm_suspend_device,
    and __bcm_resume to bcm_resume_device
- Remove useless rx_lock spinlock. It is only used in hci_uart_tty_receive() which
    is the receive_buf ldisc callback. This is already protected by flush_to_ldisc()
    in drivers/tty/tty_buffer.c.
    This allows to use mutex in bcm_recv() and call pm_runtime_* directly
- Remove pm_work Work queue which is now useless
- Delay auto-suspend only when reception of a packet is completed

v2->v3:
- Use DMI_EXACT_MATCH instead of DMI_MATCH
- Fix IRQ polarity for T100TA in driver_data of dmi_system_id struct
- Use dmi_first_match() instead of dmi_check_system()

v1->v2:
- Split 1st patch between general wake-up capability and T100TA IRQ fix
- Replace multiple "if ... else if" by switch in bcm_resource()
- Move code to limit number of #ifdef
- Use DMI info to restrict IRQ to T100TA
- Split 2nd patch to prepare PM runtime support in separated patch
- Tested with and without CONFIG_PM_SLEEP and CONFIG_PM.

Frederic Danis (5):
  Bluetooth: Add BT_WARN and bt_dev_warn logging macros
  Bluetooth: hci_bcm: Fix IRQ polarity for T100
  Bluetooth: hci_bcm: Prepare PM runtime support
  Bluetooth: Remove useless rx_lock spinlock
  Bluetooth: hci_bcm: Add suspend/resume runtime PM functions

 drivers/bluetooth/hci_bcm.c       | 189 +++++++++++++++++++++++++++++++-------
 drivers/bluetooth/hci_ldisc.c     |   5 -
 drivers/bluetooth/hci_uart.h      |   1 -
 include/net/bluetooth/bluetooth.h |   3 +
 4 files changed, 159 insertions(+), 39 deletions(-)

-- 
1.9.1


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

* [PATCH v4 1/5] Bluetooth: Add BT_WARN and bt_dev_warn logging macros
  2015-09-15  8:31 [PATCH v4 0/5] Bluetooth: hci_bcm: Add wake-up and PM runtime support Frederic Danis
@ 2015-09-15  8:31 ` Frederic Danis
  2015-09-16  2:47   ` Marcel Holtmann
  2015-09-15  8:31 ` [PATCH v4 2/5] Bluetooth: hci_bcm: Fix IRQ polarity for T100 Frederic Danis
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Frederic Danis @ 2015-09-15  8:31 UTC (permalink / raw)
  To: linux-bluetooth

Add warning logging macros to bluetooth subsystem logs.

Signed-off-by: Frederic Danis <frederic.danis@linux.intel.com>
---
 include/net/bluetooth/bluetooth.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index fcf2ae7..27a3f16 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -125,11 +125,14 @@ __printf(1, 2)
 void bt_err(const char *fmt, ...);
 
 #define BT_INFO(fmt, ...)	bt_info(fmt "\n", ##__VA_ARGS__)
+#define BT_WARN(fmt, ...)	pr_warn(fmt "\n", ##__VA_ARGS__)
 #define BT_ERR(fmt, ...)	bt_err(fmt "\n", ##__VA_ARGS__)
 #define BT_DBG(fmt, ...)	pr_debug(fmt "\n", ##__VA_ARGS__)
 
 #define bt_dev_info(hdev, fmt, ...)				\
 	BT_INFO("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
+#define bt_dev_warn(hdev, fmt, ...)				\
+	BT_WARN("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
 #define bt_dev_err(hdev, fmt, ...)				\
 	BT_ERR("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
 #define bt_dev_dbg(hdev, fmt, ...)				\
-- 
1.9.1


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

* [PATCH v4 2/5] Bluetooth: hci_bcm: Fix IRQ polarity for T100
  2015-09-15  8:31 [PATCH v4 0/5] Bluetooth: hci_bcm: Add wake-up and PM runtime support Frederic Danis
  2015-09-15  8:31 ` [PATCH v4 1/5] Bluetooth: Add BT_WARN and bt_dev_warn logging macros Frederic Danis
@ 2015-09-15  8:31 ` Frederic Danis
  2015-09-15  8:31 ` [PATCH v4 3/5] Bluetooth: hci_bcm: Prepare PM runtime support Frederic Danis
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Frederic Danis @ 2015-09-15  8:31 UTC (permalink / raw)
  To: linux-bluetooth

ACPI table for BCM2E39 of T100TA is not correct.
Set correct irq_polarity for this device.

Signed-off-by: Frederic Danis <frederic.danis@linux.intel.com>
---
 drivers/bluetooth/hci_bcm.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index f306541..2cb5089 100644
--- a/drivers/bluetooth/hci_bcm.c
+++ b/drivers/bluetooth/hci_bcm.c
@@ -32,6 +32,7 @@
 #include <linux/gpio/consumer.h>
 #include <linux/tty.h>
 #include <linux/interrupt.h>
+#include <linux/dmi.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -513,6 +514,22 @@ static const struct acpi_gpio_mapping acpi_bcm_default_gpios[] = {
 };
 
 #ifdef CONFIG_ACPI
+static u8 acpi_active_low = ACPI_ACTIVE_LOW;
+
+/* IRQ polarity of some chipsets are not defined correctly in ACPI table. */
+static const struct dmi_system_id bcm_wrong_irq_dmi_table[] = {
+	{
+		.ident = "Asus T100TA",
+		.matches = {
+			DMI_EXACT_MATCH(DMI_SYS_VENDOR,
+					"ASUSTeK COMPUTER INC."),
+			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
+		},
+		.driver_data = &acpi_active_low,
+	},
+	{ }
+};
+
 static int bcm_resource(struct acpi_resource *ares, void *data)
 {
 	struct bcm_device *dev = data;
@@ -552,6 +569,7 @@ static int bcm_acpi_probe(struct bcm_device *dev)
 	const struct acpi_device_id *id;
 	struct acpi_device *adev;
 	LIST_HEAD(resources);
+	const struct dmi_system_id *dmi_id;
 	int ret;
 
 	id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
@@ -608,6 +626,13 @@ static int bcm_acpi_probe(struct bcm_device *dev)
 
 	acpi_dev_get_resources(adev, &resources, bcm_resource, dev);
 
+	dmi_id = dmi_first_match(bcm_wrong_irq_dmi_table);
+	if (dmi_id) {
+		bt_dev_warn(dev, "%s: Overwriting IRQ polarity to active low",
+			    dmi_id->ident);
+		dev->irq_polarity = *(u8 *)dmi_id->driver_data;
+	}
+
 	return 0;
 }
 #else
-- 
1.9.1


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

* [PATCH v4 3/5] Bluetooth: hci_bcm: Prepare PM runtime support
  2015-09-15  8:31 [PATCH v4 0/5] Bluetooth: hci_bcm: Add wake-up and PM runtime support Frederic Danis
  2015-09-15  8:31 ` [PATCH v4 1/5] Bluetooth: Add BT_WARN and bt_dev_warn logging macros Frederic Danis
  2015-09-15  8:31 ` [PATCH v4 2/5] Bluetooth: hci_bcm: Fix IRQ polarity for T100 Frederic Danis
@ 2015-09-15  8:31 ` Frederic Danis
  2015-09-15  8:31 ` [PATCH v4 4/5] Bluetooth: Remove useless rx_lock spinlock Frederic Danis
  2015-09-15  8:31 ` [PATCH v4 5/5] Bluetooth: hci_bcm: Add suspend/resume runtime PM functions Frederic Danis
  4 siblings, 0 replies; 9+ messages in thread
From: Frederic Danis @ 2015-09-15  8:31 UTC (permalink / raw)
  To: linux-bluetooth

Change some CONFIG_PM_SLEEP to CONFIG_PM as hu and is_suspended parameters
will be used during PM runtime callbacks.

Add bcm_suspend_device() and bcm_resume_device() which performs link
management for PM callbacks.

Signed-off-by: Frederic Danis <frederic.danis@linux.intel.com>
---
 drivers/bluetooth/hci_bcm.c | 80 +++++++++++++++++++++++++++------------------
 1 file changed, 49 insertions(+), 31 deletions(-)

diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index 2cb5089..6e97f21 100644
--- a/drivers/bluetooth/hci_bcm.c
+++ b/drivers/bluetooth/hci_bcm.c
@@ -56,7 +56,7 @@ struct bcm_device {
 	int			irq;
 	u8			irq_polarity;
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
 	struct hci_uart		*hu;
 	bool			is_suspended; /* suspend/resume flag */
 #endif
@@ -153,7 +153,7 @@ static int bcm_gpio_set_power(struct bcm_device *dev, bool powered)
 	return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
 static irqreturn_t bcm_host_wake(int irq, void *data)
 {
 	struct bcm_device *bdev = data;
@@ -259,7 +259,7 @@ static int bcm_open(struct hci_uart *hu)
 		if (hu->tty->dev->parent == dev->pdev->dev.parent) {
 			bcm->dev = dev;
 			hu->init_speed = dev->init_speed;
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
 			dev->hu = hu;
 #endif
 			bcm_gpio_set_power(bcm->dev, true);
@@ -283,7 +283,7 @@ static int bcm_close(struct hci_uart *hu)
 	mutex_lock(&bcm_device_lock);
 	if (bcm_device_exists(bdev)) {
 		bcm_gpio_set_power(bdev, false);
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
 		if (device_can_wakeup(&bdev->pdev->dev)) {
 			devm_free_irq(&bdev->pdev->dev, bdev->irq, bdev);
 			device_init_wakeup(&bdev->pdev->dev, false);
@@ -425,8 +425,46 @@ static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
 	return skb_dequeue(&bcm->txq);
 }
 
+#ifdef CONFIG_PM
+static void bcm_suspend_device(struct bcm_device *bdev)
+{
+	if (!bdev->is_suspended && bdev->hu) {
+		hci_uart_set_flow_control(bdev->hu, true);
+
+		/* Once this returns, driver suspends BT via GPIO */
+		bdev->is_suspended = true;
+	}
+
+	/* Suspend the device */
+	if (bdev->device_wakeup) {
+		gpiod_set_value(bdev->device_wakeup, false);
+		bt_dev_dbg(bdev, "suspend, delaying 15 ms");
+		mdelay(15);
+	}
+}
+
+static void bcm_resume_device(struct bcm_device *bdev)
+{
+	if (bdev->device_wakeup) {
+		gpiod_set_value(bdev->device_wakeup, true);
+		bt_dev_dbg(bdev, "resume, delaying 15 ms");
+		mdelay(15);
+	}
+
+	/* When this executes, the device has woken up already */
+	if (bdev->is_suspended && bdev->hu) {
+		bdev->is_suspended = false;
+
+		hci_uart_set_flow_control(bdev->hu, false);
+	}
+}
+#endif
+
 #ifdef CONFIG_PM_SLEEP
-/* Platform suspend callback */
+/* Platform suspend callback
+ * This can be called at any time, so it should use bcm_device_lock to protect
+ * bcm_suspend_device() to access hci_uart and device_wake-up GPIO.
+ */
 static int bcm_suspend(struct device *dev)
 {
 	struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
@@ -439,19 +477,7 @@ static int bcm_suspend(struct device *dev)
 	if (!bdev->hu)
 		goto unlock;
 
-	if (!bdev->is_suspended) {
-		hci_uart_set_flow_control(bdev->hu, true);
-
-		/* Once this callback returns, driver suspends BT via GPIO */
-		bdev->is_suspended = true;
-	}
-
-	/* Suspend the device */
-	if (bdev->device_wakeup) {
-		gpiod_set_value(bdev->device_wakeup, false);
-		bt_dev_dbg(bdev, "suspend, delaying 15 ms");
-		mdelay(15);
-	}
+	bcm_suspend_device(bdev);
 
 	if (device_may_wakeup(&bdev->pdev->dev)) {
 		error = enable_irq_wake(bdev->irq);
@@ -465,7 +491,10 @@ unlock:
 	return 0;
 }
 
-/* Platform resume callback */
+/* Platform resume callback
+ * This can be called at any time, so it should use bcm_device_lock to protect
+ * bcm_resume_device() to access hci_uart and device_wake-up GPIO.
+ */
 static int bcm_resume(struct device *dev)
 {
 	struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
@@ -482,18 +511,7 @@ static int bcm_resume(struct device *dev)
 		bt_dev_dbg(bdev, "BCM irq: disabled");
 	}
 
-	if (bdev->device_wakeup) {
-		gpiod_set_value(bdev->device_wakeup, true);
-		bt_dev_dbg(bdev, "resume, delaying 15 ms");
-		mdelay(15);
-	}
-
-	/* When this callback executes, the device has woken up already */
-	if (bdev->is_suspended) {
-		bdev->is_suspended = false;
-
-		hci_uart_set_flow_control(bdev->hu, false);
-	}
+	bcm_resume_device(bdev);
 
 unlock:
 	mutex_unlock(&bcm_device_lock);
-- 
1.9.1


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

* [PATCH v4 4/5] Bluetooth: Remove useless rx_lock spinlock
  2015-09-15  8:31 [PATCH v4 0/5] Bluetooth: hci_bcm: Add wake-up and PM runtime support Frederic Danis
                   ` (2 preceding siblings ...)
  2015-09-15  8:31 ` [PATCH v4 3/5] Bluetooth: hci_bcm: Prepare PM runtime support Frederic Danis
@ 2015-09-15  8:31 ` Frederic Danis
  2015-09-16  2:59   ` Marcel Holtmann
  2015-09-15  8:31 ` [PATCH v4 5/5] Bluetooth: hci_bcm: Add suspend/resume runtime PM functions Frederic Danis
  4 siblings, 1 reply; 9+ messages in thread
From: Frederic Danis @ 2015-09-15  8:31 UTC (permalink / raw)
  To: linux-bluetooth

rx_lock spinlock is only used in hci_uart_tty_receive() which is the
receive_buf ldisc callback.
In drivers/tty/tty_buffer.c we can see that flush_to_ldisc (work) locks
a mutex (&buf->lock) and push the data to ldisc via receive_buf.

Signed-off-by: Frederic Danis <frederic.danis@linux.intel.com>
---
 drivers/bluetooth/hci_ldisc.c | 5 -----
 drivers/bluetooth/hci_uart.h  | 1 -
 2 files changed, 6 deletions(-)

diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 0d5a05a..dbb0a78 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -470,8 +470,6 @@ static int hci_uart_tty_open(struct tty_struct *tty)
 	INIT_WORK(&hu->init_ready, hci_uart_init_work);
 	INIT_WORK(&hu->write_work, hci_uart_write_work);
 
-	spin_lock_init(&hu->rx_lock);
-
 	/* Flush any pending characters in the driver and line discipline. */
 
 	/* FIXME: why is this needed. Note don't use ldisc_ref here as the
@@ -569,14 +567,11 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
 	if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
 		return;
 
-	spin_lock(&hu->rx_lock);
 	hu->proto->recv(hu, data, count);
 
 	if (hu->hdev)
 		hu->hdev->stat.byte_rx += count;
 
-	spin_unlock(&hu->rx_lock);
-
 	tty_unthrottle(tty);
 }
 
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 495b9ef..2f7bb35 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -85,7 +85,6 @@ struct hci_uart {
 
 	struct sk_buff		*tx_skb;
 	unsigned long		tx_state;
-	spinlock_t		rx_lock;
 
 	unsigned int init_speed;
 	unsigned int oper_speed;
-- 
1.9.1


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

* [PATCH v4 5/5] Bluetooth: hci_bcm: Add suspend/resume runtime PM functions
  2015-09-15  8:31 [PATCH v4 0/5] Bluetooth: hci_bcm: Add wake-up and PM runtime support Frederic Danis
                   ` (3 preceding siblings ...)
  2015-09-15  8:31 ` [PATCH v4 4/5] Bluetooth: Remove useless rx_lock spinlock Frederic Danis
@ 2015-09-15  8:31 ` Frederic Danis
  2015-09-16  2:58   ` Marcel Holtmann
  4 siblings, 1 reply; 9+ messages in thread
From: Frederic Danis @ 2015-09-15  8:31 UTC (permalink / raw)
  To: linux-bluetooth

Adds autosuspend runtime functionality to BCM UART driver.
Autosuspend is enabled at end of bcm_setup.

Signed-off-by: Frederic Danis <frederic.danis@linux.intel.com>
---
 drivers/bluetooth/hci_bcm.c | 88 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 84 insertions(+), 4 deletions(-)

diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index 6e97f21..eec25a7 100644
--- a/drivers/bluetooth/hci_bcm.c
+++ b/drivers/bluetooth/hci_bcm.c
@@ -33,6 +33,7 @@
 #include <linux/tty.h>
 #include <linux/interrupt.h>
 #include <linux/dmi.h>
+#include <linux/pm_runtime.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -40,6 +41,8 @@
 #include "btbcm.h"
 #include "hci_uart.h"
 
+#define BCM_AUTOSUSPEND_DELAY	5000 /* default autosleep delay */
+
 struct bcm_device {
 	struct list_head	list;
 
@@ -160,6 +163,10 @@ static irqreturn_t bcm_host_wake(int irq, void *data)
 
 	bt_dev_dbg(bdev, "Host wake IRQ");
 
+	pm_runtime_get(&bdev->pdev->dev);
+	pm_runtime_mark_last_busy(&bdev->pdev->dev);
+	pm_runtime_put_autosuspend(&bdev->pdev->dev);
+
 	return IRQ_HANDLED;
 }
 
@@ -183,6 +190,12 @@ static int bcm_request_irq(struct bcm_data *bcm)
 			goto unlock;
 
 		device_init_wakeup(&bdev->pdev->dev, true);
+
+		pm_runtime_set_autosuspend_delay(&bdev->pdev->dev,
+						 BCM_AUTOSUSPEND_DELAY);
+		pm_runtime_use_autosuspend(&bdev->pdev->dev);
+		pm_runtime_set_active(&bdev->pdev->dev);
+		pm_runtime_enable(&bdev->pdev->dev);
 	}
 
 unlock:
@@ -198,7 +211,7 @@ static const struct bcm_set_sleep_mode default_sleep_params = {
 	.bt_wake_active = 1,	/* BT_WAKE active mode: 1 = high, 0 = low */
 	.host_wake_active = 0,	/* HOST_WAKE active mode: 1 = high, 0 = low */
 	.allow_host_sleep = 1,	/* Allow host sleep in SCO flag */
-	.combine_modes = 0,	/* Combine sleep and LPM flag */
+	.combine_modes = 1,	/* Combine sleep and LPM flag */
 	.tristate_control = 0,	/* Allow tri-state control of UART tx flag */
 	/* Irrelevant USB flags */
 	.usb_auto_sleep = 0,
@@ -284,6 +297,9 @@ static int bcm_close(struct hci_uart *hu)
 	if (bcm_device_exists(bdev)) {
 		bcm_gpio_set_power(bdev, false);
 #ifdef CONFIG_PM
+		pm_runtime_disable(&bdev->pdev->dev);
+		pm_runtime_set_suspended(&bdev->pdev->dev);
+
 		if (device_can_wakeup(&bdev->pdev->dev)) {
 			devm_free_irq(&bdev->pdev->dev, bdev->irq, bdev);
 			device_init_wakeup(&bdev->pdev->dev, false);
@@ -400,6 +416,15 @@ static int bcm_recv(struct hci_uart *hu, const void *data, int count)
 		bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);
 		bcm->rx_skb = NULL;
 		return err;
+	} else if (!bcm->rx_skb) {
+		/* Delay auto-suspend when receiving completed packet */
+		mutex_lock(&bcm_device_lock);
+		if (bcm->dev && bcm_device_exists(bcm->dev)) {
+			pm_runtime_get(&bcm->dev->pdev->dev);
+			pm_runtime_mark_last_busy(&bcm->dev->pdev->dev);
+			pm_runtime_put_autosuspend(&bcm->dev->pdev->dev);
+		}
+		mutex_unlock(&bcm_device_lock);
 	}
 
 	return count;
@@ -421,8 +446,27 @@ static int bcm_enqueue(struct hci_uart *hu, struct sk_buff *skb)
 static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
 {
 	struct bcm_data *bcm = hu->priv;
+	struct sk_buff *skb = NULL;
+	struct bcm_device *bdev = NULL;
+
+	mutex_lock(&bcm_device_lock);
+
+	if (bcm_device_exists(bcm->dev)) {
+		bdev = bcm->dev;
+		pm_runtime_get_sync(&bdev->pdev->dev);
+		/* Shall be resumed here */
+	}
+
+	skb = skb_dequeue(&bcm->txq);
 
-	return skb_dequeue(&bcm->txq);
+	if (bdev) {
+		pm_runtime_mark_last_busy(&bdev->pdev->dev);
+		pm_runtime_put_autosuspend(&bdev->pdev->dev);
+	}
+
+	mutex_unlock(&bcm_device_lock);
+
+	return skb;
 }
 
 #ifdef CONFIG_PM
@@ -458,6 +502,34 @@ static void bcm_resume_device(struct bcm_device *bdev)
 		hci_uart_set_flow_control(bdev->hu, false);
 	}
 }
+
+static int bcm_runtime_suspend(struct device *dev)
+{
+	struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
+
+	bt_dev_dbg(bdev, "");
+
+	/* bcm_device_lock held is not required here as bcm_runtime_suspend
+	 * is only called when device is attached.
+	 */
+	bcm_suspend_device(bdev);
+
+	return 0;
+}
+
+static int bcm_runtime_resume(struct device *dev)
+{
+	struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
+
+	bt_dev_dbg(bdev, "");
+
+	/* bcm_device_lock held is not required here as bcm_runtime_resume
+	 * is only called when device is attached.
+	 */
+	bcm_resume_device(bdev);
+
+	return 0;
+}
 #endif
 
 #ifdef CONFIG_PM_SLEEP
@@ -477,7 +549,8 @@ static int bcm_suspend(struct device *dev)
 	if (!bdev->hu)
 		goto unlock;
 
-	bcm_suspend_device(bdev);
+	if (pm_runtime_active(dev))
+		bcm_suspend_device(bdev);
 
 	if (device_may_wakeup(&bdev->pdev->dev)) {
 		error = enable_irq_wake(bdev->irq);
@@ -516,6 +589,10 @@ static int bcm_resume(struct device *dev)
 unlock:
 	mutex_unlock(&bcm_device_lock);
 
+	pm_runtime_disable(dev);
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+
 	return 0;
 }
 #endif
@@ -736,7 +813,10 @@ MODULE_DEVICE_TABLE(acpi, bcm_acpi_match);
 #endif
 
 /* Platform suspend and resume callbacks */
-static SIMPLE_DEV_PM_OPS(bcm_pm_ops, bcm_suspend, bcm_resume);
+static const struct dev_pm_ops bcm_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(bcm_suspend, bcm_resume)
+	SET_RUNTIME_PM_OPS(bcm_runtime_suspend, bcm_runtime_resume, NULL)
+};
 
 static struct platform_driver bcm_driver = {
 	.probe = bcm_probe,
-- 
1.9.1


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

* Re: [PATCH v4 1/5] Bluetooth: Add BT_WARN and bt_dev_warn logging macros
  2015-09-15  8:31 ` [PATCH v4 1/5] Bluetooth: Add BT_WARN and bt_dev_warn logging macros Frederic Danis
@ 2015-09-16  2:47   ` Marcel Holtmann
  0 siblings, 0 replies; 9+ messages in thread
From: Marcel Holtmann @ 2015-09-16  2:47 UTC (permalink / raw)
  To: Frederic Danis; +Cc: linux-bluetooth

Hi Fred,

> Add warning logging macros to bluetooth subsystem logs.
> 
> Signed-off-by: Frederic Danis <frederic.danis@linux.intel.com>
> ---
> include/net/bluetooth/bluetooth.h | 3 +++
> 1 file changed, 3 insertions(+)
> 
> diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
> index fcf2ae7..27a3f16 100644
> --- a/include/net/bluetooth/bluetooth.h
> +++ b/include/net/bluetooth/bluetooth.h
> @@ -125,11 +125,14 @@ __printf(1, 2)
> void bt_err(const char *fmt, ...);
> 
> #define BT_INFO(fmt, ...)	bt_info(fmt "\n", ##__VA_ARGS__)
> +#define BT_WARN(fmt, ...)	pr_warn(fmt "\n", ##__VA_ARGS__)

any reason why you didn't create a bt_warn instead here? That why we have the proper pr_fmt set with the Bluetooth: prefix.

> #define BT_ERR(fmt, ...)	bt_err(fmt "\n", ##__VA_ARGS__)
> #define BT_DBG(fmt, ...)	pr_debug(fmt "\n", ##__VA_ARGS__)
> 
> #define bt_dev_info(hdev, fmt, ...)				\
> 	BT_INFO("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
> +#define bt_dev_warn(hdev, fmt, ...)				\
> +	BT_WARN("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
> #define bt_dev_err(hdev, fmt, ...)				\
> 	BT_ERR("%s: " fmt, (hdev)->name, ##__VA_ARGS__)
> #define bt_dev_dbg(hdev, fmt, ...)				\

Regards

Marcel


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

* Re: [PATCH v4 5/5] Bluetooth: hci_bcm: Add suspend/resume runtime PM functions
  2015-09-15  8:31 ` [PATCH v4 5/5] Bluetooth: hci_bcm: Add suspend/resume runtime PM functions Frederic Danis
@ 2015-09-16  2:58   ` Marcel Holtmann
  0 siblings, 0 replies; 9+ messages in thread
From: Marcel Holtmann @ 2015-09-16  2:58 UTC (permalink / raw)
  To: Frederic Danis; +Cc: linux-bluetooth

Hi Fred,

> Adds autosuspend runtime functionality to BCM UART driver.
> Autosuspend is enabled at end of bcm_setup.
> 
> Signed-off-by: Frederic Danis <frederic.danis@linux.intel.com>
> ---
> drivers/bluetooth/hci_bcm.c | 88 ++++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 84 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
> index 6e97f21..eec25a7 100644
> --- a/drivers/bluetooth/hci_bcm.c
> +++ b/drivers/bluetooth/hci_bcm.c
> @@ -33,6 +33,7 @@
> #include <linux/tty.h>
> #include <linux/interrupt.h>
> #include <linux/dmi.h>
> +#include <linux/pm_runtime.h>
> 
> #include <net/bluetooth/bluetooth.h>
> #include <net/bluetooth/hci_core.h>
> @@ -40,6 +41,8 @@
> #include "btbcm.h"
> #include "hci_uart.h"
> 
> +#define BCM_AUTOSUSPEND_DELAY	5000 /* default autosleep delay */
> +
> struct bcm_device {
> 	struct list_head	list;
> 
> @@ -160,6 +163,10 @@ static irqreturn_t bcm_host_wake(int irq, void *data)
> 
> 	bt_dev_dbg(bdev, "Host wake IRQ");
> 
> +	pm_runtime_get(&bdev->pdev->dev);
> +	pm_runtime_mark_last_busy(&bdev->pdev->dev);
> +	pm_runtime_put_autosuspend(&bdev->pdev->dev);
> +
> 	return IRQ_HANDLED;
> }
> 
> @@ -183,6 +190,12 @@ static int bcm_request_irq(struct bcm_data *bcm)
> 			goto unlock;
> 
> 		device_init_wakeup(&bdev->pdev->dev, true);
> +
> +		pm_runtime_set_autosuspend_delay(&bdev->pdev->dev,
> +						 BCM_AUTOSUSPEND_DELAY);
> +		pm_runtime_use_autosuspend(&bdev->pdev->dev);
> +		pm_runtime_set_active(&bdev->pdev->dev);
> +		pm_runtime_enable(&bdev->pdev->dev);
> 	}
> 
> unlock:
> @@ -198,7 +211,7 @@ static const struct bcm_set_sleep_mode default_sleep_params = {
> 	.bt_wake_active = 1,	/* BT_WAKE active mode: 1 = high, 0 = low */
> 	.host_wake_active = 0,	/* HOST_WAKE active mode: 1 = high, 0 = low */
> 	.allow_host_sleep = 1,	/* Allow host sleep in SCO flag */
> -	.combine_modes = 0,	/* Combine sleep and LPM flag */
> +	.combine_modes = 1,	/* Combine sleep and LPM flag */
> 	.tristate_control = 0,	/* Allow tri-state control of UART tx flag */
> 	/* Irrelevant USB flags */
> 	.usb_auto_sleep = 0,
> @@ -284,6 +297,9 @@ static int bcm_close(struct hci_uart *hu)
> 	if (bcm_device_exists(bdev)) {
> 		bcm_gpio_set_power(bdev, false);
> #ifdef CONFIG_PM
> +		pm_runtime_disable(&bdev->pdev->dev);
> +		pm_runtime_set_suspended(&bdev->pdev->dev);
> +
> 		if (device_can_wakeup(&bdev->pdev->dev)) {
> 			devm_free_irq(&bdev->pdev->dev, bdev->irq, bdev);
> 			device_init_wakeup(&bdev->pdev->dev, false);
> @@ -400,6 +416,15 @@ static int bcm_recv(struct hci_uart *hu, const void *data, int count)
> 		bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);
> 		bcm->rx_skb = NULL;
> 		return err;
> +	} else if (!bcm->rx_skb) {
> +		/* Delay auto-suspend when receiving completed packet */
> +		mutex_lock(&bcm_device_lock);
> +		if (bcm->dev && bcm_device_exists(bcm->dev)) {
> +			pm_runtime_get(&bcm->dev->pdev->dev);
> +			pm_runtime_mark_last_busy(&bcm->dev->pdev->dev);
> +			pm_runtime_put_autosuspend(&bcm->dev->pdev->dev);
> +		}
> +		mutex_unlock(&bcm_device_lock);
> 	}
> 
> 	return count;
> @@ -421,8 +446,27 @@ static int bcm_enqueue(struct hci_uart *hu, struct sk_buff *skb)
> static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
> {
> 	struct bcm_data *bcm = hu->priv;
> +	struct sk_buff *skb = NULL;
> +	struct bcm_device *bdev = NULL;
> +
> +	mutex_lock(&bcm_device_lock);
> +
> +	if (bcm_device_exists(bcm->dev)) {
> +		bdev = bcm->dev;
> +		pm_runtime_get_sync(&bdev->pdev->dev);
> +		/* Shall be resumed here */
> +	}
> +
> +	skb = skb_dequeue(&bcm->txq);
> 
> -	return skb_dequeue(&bcm->txq);
> +	if (bdev) {
> +		pm_runtime_mark_last_busy(&bdev->pdev->dev);
> +		pm_runtime_put_autosuspend(&bdev->pdev->dev);
> +	}
> +
> +	mutex_unlock(&bcm_device_lock);
> +
> +	return skb;
> }
> 
> #ifdef CONFIG_PM
> @@ -458,6 +502,34 @@ static void bcm_resume_device(struct bcm_device *bdev)
> 		hci_uart_set_flow_control(bdev->hu, false);
> 	}
> }
> +
> +static int bcm_runtime_suspend(struct device *dev)
> +{
> +	struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
> +
> +	bt_dev_dbg(bdev, "");
> +
> +	/* bcm_device_lock held is not required here as bcm_runtime_suspend
> +	 * is only called when device is attached.
> +	 */
> +	bcm_suspend_device(bdev);
> +
> +	return 0;
> +}
> +
> +static int bcm_runtime_resume(struct device *dev)
> +{
> +	struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
> +
> +	bt_dev_dbg(bdev, "");
> +
> +	/* bcm_device_lock held is not required here as bcm_runtime_resume
> +	 * is only called when device is attached.
> +	 */
> +	bcm_resume_device(bdev);
> +
> +	return 0;
> +}

why are we having these two wrappers? They do nothing except adding a comment.

I rather get rid of them and put a proper comment in the bcm_suspend and bcm_resume functions that a lock needs to be held in this case. And in addition add text about the looking to the commit message.

Regards

Marcel


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

* Re: [PATCH v4 4/5] Bluetooth: Remove useless rx_lock spinlock
  2015-09-15  8:31 ` [PATCH v4 4/5] Bluetooth: Remove useless rx_lock spinlock Frederic Danis
@ 2015-09-16  2:59   ` Marcel Holtmann
  0 siblings, 0 replies; 9+ messages in thread
From: Marcel Holtmann @ 2015-09-16  2:59 UTC (permalink / raw)
  To: Frederic Danis; +Cc: linux-bluetooth

Hi Fred,

> rx_lock spinlock is only used in hci_uart_tty_receive() which is the
> receive_buf ldisc callback.
> In drivers/tty/tty_buffer.c we can see that flush_to_ldisc (work) locks
> a mutex (&buf->lock) and push the data to ldisc via receive_buf.

please be a bit more verbose why this is correct.

> 
> Signed-off-by: Frederic Danis <frederic.danis@linux.intel.com>
> ---
> drivers/bluetooth/hci_ldisc.c | 5 -----
> drivers/bluetooth/hci_uart.h  | 1 -
> 2 files changed, 6 deletions(-)
> 
> diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
> index 0d5a05a..dbb0a78 100644
> --- a/drivers/bluetooth/hci_ldisc.c
> +++ b/drivers/bluetooth/hci_ldisc.c
> @@ -470,8 +470,6 @@ static int hci_uart_tty_open(struct tty_struct *tty)
> 	INIT_WORK(&hu->init_ready, hci_uart_init_work);
> 	INIT_WORK(&hu->write_work, hci_uart_write_work);
> 
> -	spin_lock_init(&hu->rx_lock);
> -
> 	/* Flush any pending characters in the driver and line discipline. */
> 
> 	/* FIXME: why is this needed. Note don't use ldisc_ref here as the
> @@ -569,14 +567,11 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
> 	if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
> 		return;
> 
> -	spin_lock(&hu->rx_lock);

And here I would add a comment why we do not need the lock.

> 	hu->proto->recv(hu, data, count);
> 
> 	if (hu->hdev)
> 		hu->hdev->stat.byte_rx += count;
> 
> -	spin_unlock(&hu->rx_lock);
> -
> 	tty_unthrottle(tty);
> }
> 
> diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
> index 495b9ef..2f7bb35 100644
> --- a/drivers/bluetooth/hci_uart.h
> +++ b/drivers/bluetooth/hci_uart.h
> @@ -85,7 +85,6 @@ struct hci_uart {
> 
> 	struct sk_buff		*tx_skb;
> 	unsigned long		tx_state;
> -	spinlock_t		rx_lock;
> 
> 	unsigned int init_speed;
> 	unsigned int oper_speed;

Regards

Marcel


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

end of thread, other threads:[~2015-09-16  2:59 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-09-15  8:31 [PATCH v4 0/5] Bluetooth: hci_bcm: Add wake-up and PM runtime support Frederic Danis
2015-09-15  8:31 ` [PATCH v4 1/5] Bluetooth: Add BT_WARN and bt_dev_warn logging macros Frederic Danis
2015-09-16  2:47   ` Marcel Holtmann
2015-09-15  8:31 ` [PATCH v4 2/5] Bluetooth: hci_bcm: Fix IRQ polarity for T100 Frederic Danis
2015-09-15  8:31 ` [PATCH v4 3/5] Bluetooth: hci_bcm: Prepare PM runtime support Frederic Danis
2015-09-15  8:31 ` [PATCH v4 4/5] Bluetooth: Remove useless rx_lock spinlock Frederic Danis
2015-09-16  2:59   ` Marcel Holtmann
2015-09-15  8:31 ` [PATCH v4 5/5] Bluetooth: hci_bcm: Add suspend/resume runtime PM functions Frederic Danis
2015-09-16  2:58   ` Marcel Holtmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).