2015-09-23 16:18:06

by Frederic Danis

[permalink] [raw]
Subject: [PATCH v5 0/5] Bluetooth: hci_bcm: Add wake-up and PM runtime support

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

v4->v5:
- Add bt_warn to to unify Bluetooth traces in BT_WARN
- Change bcm_suspend_device/bcm_resume_device prototype to be usable directly
in SET_RUNTIME_PM_OPS. This allows to remove bcm_runtime_suspend/bcm_runtime_resume
which just call bcm_suspend_device/bcm_resume_device.
- Update commit message and add comment in hci_uart_tty_receive to explain
why spin_lock is not requested

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 | 171 +++++++++++++++++++++++++++++++-------
drivers/bluetooth/hci_ldisc.c | 8 +-
drivers/bluetooth/hci_uart.h | 1 -
include/net/bluetooth/bluetooth.h | 5 ++
net/bluetooth/lib.c | 16 ++++
5 files changed, 164 insertions(+), 37 deletions(-)

--
1.9.1



2015-09-24 14:35:51

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v5 0/5] Bluetooth: hci_bcm: Add wake-up and PM runtime support

Hi Fred,

> Add wake-up capabilities by retrieveing interruption used by BCM device in ACPI
> table.
> Add PM runtime support.
>
> v4->v5:
> - Add bt_warn to to unify Bluetooth traces in BT_WARN
> - Change bcm_suspend_device/bcm_resume_device prototype to be usable directly
> in SET_RUNTIME_PM_OPS. This allows to remove bcm_runtime_suspend/bcm_runtime_resume
> which just call bcm_suspend_device/bcm_resume_device.
> - Update commit message and add comment in hci_uart_tty_receive to explain
> why spin_lock is not requested
>
> 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 | 171 +++++++++++++++++++++++++++++++-------
> drivers/bluetooth/hci_ldisc.c | 8 +-
> drivers/bluetooth/hci_uart.h | 1 -
> include/net/bluetooth/bluetooth.h | 5 ++
> net/bluetooth/lib.c | 16 ++++
> 5 files changed, 164 insertions(+), 37 deletions(-)

all 5 patches have been applied to bluetooth-next tree.

Regards

Marcel


2015-09-23 16:18:11

by Frederic Danis

[permalink] [raw]
Subject: [PATCH v5 5/5] Bluetooth: hci_bcm: Add suspend/resume runtime PM functions

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

bcm_device_lock is used for system sleep functions as they can be
called at any time.
bcm_device_lock is not held for runtime suspend functions as this
is only enabled as long as platform device is opened.

Signed-off-by: Frederic Danis <[email protected]>
---
drivers/bluetooth/hci_bcm.c | 60 ++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 56 insertions(+), 4 deletions(-)

diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index fc5ca95..0c791ac 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);
+
+ if (bdev) {
+ pm_runtime_mark_last_busy(&bdev->pdev->dev);
+ pm_runtime_put_autosuspend(&bdev->pdev->dev);
+ }

- return skb_dequeue(&bcm->txq);
+ mutex_unlock(&bcm_device_lock);
+
+ return skb;
}

#ifdef CONFIG_PM
@@ -490,7 +534,8 @@ static int bcm_suspend(struct device *dev)
if (!bdev->hu)
goto unlock;

- bcm_suspend_device(dev);
+ if (pm_runtime_active(dev))
+ bcm_suspend_device(dev);

if (device_may_wakeup(&bdev->pdev->dev)) {
error = enable_irq_wake(bdev->irq);
@@ -530,6 +575,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
@@ -750,7 +799,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_suspend_device, bcm_resume_device, NULL)
+};

static struct platform_driver bcm_driver = {
.probe = bcm_probe,
--
1.9.1


2015-09-23 16:18:10

by Frederic Danis

[permalink] [raw]
Subject: [PATCH v5 4/5] Bluetooth: Remove useless rx_lock spinlock

rx_lock spinlock is only used in hci_uart_tty_receive() which is the
receive_buf ldisc callback.

hci_uart_tty_receive() is protected from re-entrance by its only
caller (flush_to_ldisc() in drivers/tty/tty_buffer.c) which held a
mutex (buf->lock) for this section.
This lock allows "safe use of the line discipline's receive_buf()
method by excluding the buffer work and any pending flush from using
the flip buffer." (comments from tty_buffer_lock_exclusive() in
drivers/tty/tty_buffer.c)

So, no need to double protect this resource with rx_lock.

Signed-off-by: Frederic Danis <[email protected]>
---
drivers/bluetooth/hci_ldisc.c | 8 +++-----
drivers/bluetooth/hci_uart.h | 1 -
2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 0d5a05a..ad66c69 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,14 @@ 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);
+ /* It does not need a lock here as it is already protected by a mutex in
+ * tty caller
+ */
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


2015-09-23 16:18:09

by Frederic Danis

[permalink] [raw]
Subject: [PATCH v5 3/5] Bluetooth: hci_bcm: Prepare PM runtime support

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.
These functions will be used for runtime management.

Signed-off-by: Frederic Danis <[email protected]>
---
drivers/bluetooth/hci_bcm.c | 88 ++++++++++++++++++++++++++++++---------------
1 file changed, 60 insertions(+), 28 deletions(-)

diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
index 2cb5089..fc5ca95 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,24 +425,17 @@ static struct sk_buff *bcm_dequeue(struct hci_uart *hu)
return skb_dequeue(&bcm->txq);
}

-#ifdef CONFIG_PM_SLEEP
-/* Platform suspend callback */
-static int bcm_suspend(struct device *dev)
+#ifdef CONFIG_PM
+static int bcm_suspend_device(struct device *dev)
{
struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
- int error;

- bt_dev_dbg(bdev, "suspend: is_suspended %d", bdev->is_suspended);
-
- mutex_lock(&bcm_device_lock);
-
- if (!bdev->hu)
- goto unlock;
+ bt_dev_dbg(bdev, "");

- if (!bdev->is_suspended) {
+ if (!bdev->is_suspended && bdev->hu) {
hci_uart_set_flow_control(bdev->hu, true);

- /* Once this callback returns, driver suspends BT via GPIO */
+ /* Once this returns, driver suspends BT via GPIO */
bdev->is_suspended = true;
}

@@ -453,6 +446,52 @@ static int bcm_suspend(struct device *dev)
mdelay(15);
}

+ return 0;
+}
+
+static int bcm_resume_device(struct device *dev)
+{
+ struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
+
+ bt_dev_dbg(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);
+ }
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+/* Platform suspend callback */
+static int bcm_suspend(struct device *dev)
+{
+ struct bcm_device *bdev = platform_get_drvdata(to_platform_device(dev));
+ int error;
+
+ bt_dev_dbg(bdev, "suspend: is_suspended %d", bdev->is_suspended);
+
+ /* bcm_suspend can be called at any time as long as platform device is
+ * bound, so it should use bcm_device_lock to protect access to hci_uart
+ * and device_wake-up GPIO.
+ */
+ mutex_lock(&bcm_device_lock);
+
+ if (!bdev->hu)
+ goto unlock;
+
+ bcm_suspend_device(dev);
+
if (device_may_wakeup(&bdev->pdev->dev)) {
error = enable_irq_wake(bdev->irq);
if (!error)
@@ -472,6 +511,10 @@ static int bcm_resume(struct device *dev)

bt_dev_dbg(bdev, "resume: is_suspended %d", bdev->is_suspended);

+ /* bcm_resume can be called at any time as long as platform device is
+ * bound, so it should use bcm_device_lock to protect access to hci_uart
+ * and device_wake-up GPIO.
+ */
mutex_lock(&bcm_device_lock);

if (!bdev->hu)
@@ -482,18 +525,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(dev);

unlock:
mutex_unlock(&bcm_device_lock);
--
1.9.1


2015-09-23 16:18:08

by Frederic Danis

[permalink] [raw]
Subject: [PATCH v5 2/5] Bluetooth: hci_bcm: Fix IRQ polarity for T100

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

Signed-off-by: Frederic Danis <[email protected]>
---
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


2015-09-23 16:18:07

by Frederic Danis

[permalink] [raw]
Subject: [PATCH v5 1/5] Bluetooth: Add BT_WARN and bt_dev_warn logging macros

Add warning logging macros to bluetooth subsystem logs.

Signed-off-by: Frederic Danis <[email protected]>
---
include/net/bluetooth/bluetooth.h | 5 +++++
net/bluetooth/lib.c | 16 ++++++++++++++++
2 files changed, 21 insertions(+)

diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index f5ade85..c4defef 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -122,11 +122,14 @@ struct bt_voice {
__printf(1, 2)
void bt_info(const char *fmt, ...);
__printf(1, 2)
+void bt_warn(const char *fmt, ...);
+__printf(1, 2)
void bt_err(const char *fmt, ...);
__printf(1, 2)
void bt_err_ratelimited(const char *fmt, ...);

#define BT_INFO(fmt, ...) bt_info(fmt "\n", ##__VA_ARGS__)
+#define BT_WARN(fmt, ...) bt_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__)

@@ -134,6 +137,8 @@ void bt_err_ratelimited(const char *fmt, ...);

#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, ...) \
diff --git a/net/bluetooth/lib.c b/net/bluetooth/lib.c
index 8b4cdce..aa4cf64 100644
--- a/net/bluetooth/lib.c
+++ b/net/bluetooth/lib.c
@@ -151,6 +151,22 @@ void bt_info(const char *format, ...)
}
EXPORT_SYMBOL(bt_info);

+void bt_warn(const char *format, ...)
+{
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, format);
+
+ vaf.fmt = format;
+ vaf.va = &args;
+
+ pr_warn("%pV", &vaf);
+
+ va_end(args);
+}
+EXPORT_SYMBOL(bt_warn);
+
void bt_err(const char *format, ...)
{
struct va_format vaf;
--
1.9.1