From 89a0b8b98f49ae34886e67624208c2898e1e4d7f Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Sat, 8 Jan 2022 21:21:45 -0800 Subject: [PATCH 01/30] Bluetooth: hci_sync: Fix compilation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the following warning: net/bluetooth/hci_sync.c:5143:5: warning: no previous prototype for ‘hci_le_ext_create_conn_sync’ [-Wmissing-prototypes] Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_sync.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 0feb68f125456..2fe8c60dc62bc 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -5140,8 +5140,8 @@ static void set_ext_conn_params(struct hci_conn *conn, p->max_ce_len = cpu_to_le16(0x0000); } -int hci_le_ext_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn, - u8 own_addr_type) +static int hci_le_ext_create_conn_sync(struct hci_dev *hdev, + struct hci_conn *conn, u8 own_addr_type) { struct hci_cp_le_ext_create_conn *cp; struct hci_cp_le_ext_conn_param *p; From 4b6858797229fc787d1b737cace469ad146aaaf0 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 10 Jan 2022 03:23:57 +0800 Subject: [PATCH 02/30] Bluetooth: btmtksdio: rename btsdio_mtk_reg_read Using "btmtksdio" as the prefix instead of "btsdio" Signed-off-by: Sean Wang Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmtksdio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index b5ea8d3bffaa7..891e34b50e449 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -797,7 +797,7 @@ static int mt79xx_setup(struct hci_dev *hdev, const char *fwname) return err; } -static int btsdio_mtk_reg_read(struct hci_dev *hdev, u32 reg, u32 *val) +static int btmtksdio_mtk_reg_read(struct hci_dev *hdev, u32 reg, u32 *val) { struct btmtk_hci_wmt_params wmt_params; struct reg_read_cmd { @@ -844,13 +844,13 @@ static int btmtksdio_setup(struct hci_dev *hdev) switch (bdev->data->chipid) { case 0x7921: - err = btsdio_mtk_reg_read(hdev, 0x70010200, &dev_id); + err = btmtksdio_mtk_reg_read(hdev, 0x70010200, &dev_id); if (err < 0) { bt_dev_err(hdev, "Failed to get device id (%d)", err); return err; } - err = btsdio_mtk_reg_read(hdev, 0x80021004, &fw_version); + err = btmtksdio_mtk_reg_read(hdev, 0x80021004, &fw_version); if (err < 0) { bt_dev_err(hdev, "Failed to get fw version (%d)", err); return err; From ce64b3e949195768361b0e4111e0837e5e46930d Mon Sep 17 00:00:00 2001 From: Mark Chen Date: Mon, 10 Jan 2022 03:23:58 +0800 Subject: [PATCH 03/30] Bluetooth: mt7921s: Support wake on bluetooth Enable wake on bluetooth on mt7921s that can be supported since the firmware with version 20211129211059 was added, and the patch would not cause any harm even when the old firmware is applied. The patch was tested by setting up an HID or HOGP profile to connect a Bluetooth keyboard and mouse, then putting the system to suspend, then trying to wake up the system by moving the Bluetooth keyboard or mouse, and then checking if the system can wake up and be brought back to the normal state. Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Mark Chen Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmtk.h | 8 ++++++++ drivers/bluetooth/btmtksdio.c | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h index 6e7b0c7567c0f..2be1d2680ad88 100644 --- a/drivers/bluetooth/btmtk.h +++ b/drivers/bluetooth/btmtk.h @@ -68,6 +68,14 @@ struct btmtk_tci_sleep { u8 time_compensation; } __packed; +struct btmtk_wakeon { + u8 mode; + u8 gpo; + u8 active_high; + __le16 enable_delay; + __le16 wakeup_delay; +} __packed; + struct btmtk_hci_wmt_params { u8 op; u8 flag; diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 891e34b50e449..a8273874e29fb 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -958,6 +958,32 @@ static int btmtksdio_send_frame(struct hci_dev *hdev, struct sk_buff *skb) return 0; } +static bool btmtksdio_sdio_wakeup(struct hci_dev *hdev) +{ + struct btmtksdio_dev *bdev = hci_get_drvdata(hdev); + bool may_wakeup = device_may_wakeup(bdev->dev); + const struct btmtk_wakeon bt_awake = { + .mode = 0x1, + .gpo = 0, + .active_high = 0x1, + .enable_delay = cpu_to_le16(0xc80), + .wakeup_delay = cpu_to_le16(0x20), + }; + + if (may_wakeup && bdev->data->chipid == 0x7921) { + struct sk_buff *skb; + + skb = __hci_cmd_sync(hdev, 0xfc27, sizeof(bt_awake), + &bt_awake, HCI_CMD_TIMEOUT); + if (IS_ERR(skb)) + may_wakeup = false; + + kfree_skb(skb); + } + + return may_wakeup; +} + static int btmtksdio_probe(struct sdio_func *func, const struct sdio_device_id *id) { @@ -997,6 +1023,7 @@ static int btmtksdio_probe(struct sdio_func *func, hdev->setup = btmtksdio_setup; hdev->shutdown = btmtksdio_shutdown; hdev->send = btmtksdio_send_frame; + hdev->wakeup = btmtksdio_sdio_wakeup; hdev->set_bdaddr = btmtk_set_bdaddr; SET_HCIDEV_DEV(hdev, &func->dev); @@ -1032,7 +1059,11 @@ static int btmtksdio_probe(struct sdio_func *func, */ pm_runtime_put_noidle(bdev->dev); - return 0; + err = device_init_wakeup(bdev->dev, true); + if (err) + bt_dev_err(hdev, "failed to initialize device wakeup"); + + return err; } static void btmtksdio_remove(struct sdio_func *func) From 191c872308f6a175324bc33807852b10363066cb Mon Sep 17 00:00:00 2001 From: Mark Chen Date: Mon, 10 Jan 2022 03:23:59 +0800 Subject: [PATCH 04/30] Bluetooth: mt7921s: Enable SCO over I2S The driver has to issue the specific command to enable Bluetooth SCO over the I2S/PCM interface on mt7921s, that is supported since the firmware with version 20211222191101 was added, and the patch would not cause any harm even when the old firmware is applied. The SCO profile with the patch was tested by setting up a VOIP application, connected to HFP device, checked telephony function can work normally. Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Mark Chen Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmtk.h | 20 +++++++++++ drivers/bluetooth/btmtksdio.c | 68 +++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h index 2be1d2680ad88..fc57ef09d1326 100644 --- a/drivers/bluetooth/btmtk.h +++ b/drivers/bluetooth/btmtk.h @@ -7,8 +7,12 @@ #define HCI_WMT_MAX_EVENT_SIZE 64 +#define BTMTK_WMT_REG_WRITE 0x1 #define BTMTK_WMT_REG_READ 0x2 +#define MT7921_PINMUX_0 0x70005050 +#define MT7921_PINMUX_1 0x70005054 + enum { BTMTK_WMT_PATCH_DWNLD = 0x1, BTMTK_WMT_TEST = 0x2, @@ -76,6 +80,22 @@ struct btmtk_wakeon { __le16 wakeup_delay; } __packed; +struct btmtk_sco { + u8 clock_config; + u8 transmit_format_config; + u8 channel_format_config; + u8 channel_select_config; +} __packed; + +struct reg_write_cmd { + u8 type; + u8 rsv; + u8 num; + __le32 addr; + __le32 data; + __le32 mask; +} __packed; + struct btmtk_hci_wmt_params { u8 op; u8 flag; diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index a8273874e29fb..a41b5f65e7a9b 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -830,6 +830,66 @@ static int btmtksdio_mtk_reg_read(struct hci_dev *hdev, u32 reg, u32 *val) return err; } +static int btmtksdio_mtk_reg_write(struct hci_dev *hdev, u32 reg, u32 val, u32 mask) +{ + struct btmtk_hci_wmt_params wmt_params; + const struct reg_write_cmd reg_write = { + .type = 1, + .num = 1, + .addr = cpu_to_le32(reg), + .data = cpu_to_le32(val), + .mask = cpu_to_le32(mask), + }; + int err, status; + + wmt_params.op = BTMTK_WMT_REGISTER; + wmt_params.flag = BTMTK_WMT_REG_WRITE; + wmt_params.dlen = sizeof(reg_write); + wmt_params.data = ®_write; + wmt_params.status = &status; + + err = mtk_hci_wmt_sync(hdev, &wmt_params); + if (err < 0) + bt_dev_err(hdev, "Failed to write reg (%d)", err); + + return err; +} + +static int btmtksdio_sco_setting(struct hci_dev *hdev) +{ + const struct btmtk_sco sco_setting = { + .clock_config = 0x49, + .channel_format_config = 0x80, + }; + struct sk_buff *skb; + u32 val; + int err; + + /* Enable SCO over I2S/PCM for MediaTek chipset */ + skb = __hci_cmd_sync(hdev, 0xfc72, sizeof(sco_setting), + &sco_setting, HCI_CMD_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + kfree_skb(skb); + + err = btmtksdio_mtk_reg_read(hdev, MT7921_PINMUX_0, &val); + if (err < 0) + return err; + + val |= 0x11000000; + err = btmtksdio_mtk_reg_write(hdev, MT7921_PINMUX_0, val, ~0); + if (err < 0) + return err; + + err = btmtksdio_mtk_reg_read(hdev, MT7921_PINMUX_1, &val); + if (err < 0) + return err; + + val |= 0x00000101; + return btmtksdio_mtk_reg_write(hdev, MT7921_PINMUX_1, val, ~0); +} + static int btmtksdio_setup(struct hci_dev *hdev) { struct btmtksdio_dev *bdev = hci_get_drvdata(hdev); @@ -862,6 +922,14 @@ static int btmtksdio_setup(struct hci_dev *hdev) err = mt79xx_setup(hdev, fwname); if (err < 0) return err; + + /* Enable SCO over I2S/PCM */ + err = btmtksdio_sco_setting(hdev); + if (err < 0) { + bt_dev_err(hdev, "Failed to enable SCO setting (%d)", err); + return err; + } + break; case 0x7663: case 0x7668: From 5677bcf6d8ff645d90c422ab035030c6aeec9296 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 10 Jan 2022 03:24:00 +0800 Subject: [PATCH 05/30] Bluetooth: btmtksdio: move struct reg_read_cmd to common file move struct reg_read_cmd to btmtk.h to allow other mtk drivers refer to. Signed-off-by: Sean Wang Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmtk.h | 7 +++++++ drivers/bluetooth/btmtksdio.c | 7 +------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/bluetooth/btmtk.h b/drivers/bluetooth/btmtk.h index fc57ef09d1326..fb76d9765ce06 100644 --- a/drivers/bluetooth/btmtk.h +++ b/drivers/bluetooth/btmtk.h @@ -87,6 +87,13 @@ struct btmtk_sco { u8 channel_select_config; } __packed; +struct reg_read_cmd { + u8 type; + u8 rsv; + u8 num; + __le32 addr; +} __packed; + struct reg_write_cmd { u8 type; u8 rsv; diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index a41b5f65e7a9b..d82ba9d71fb8d 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -800,12 +800,7 @@ static int mt79xx_setup(struct hci_dev *hdev, const char *fwname) static int btmtksdio_mtk_reg_read(struct hci_dev *hdev, u32 reg, u32 *val) { struct btmtk_hci_wmt_params wmt_params; - struct reg_read_cmd { - u8 type; - u8 rsv; - u8 num; - __le32 addr; - } __packed reg_read = { + struct reg_read_cmd reg_read = { .type = 1, .num = 1, }; From 386f626adda81d224f7229e31ebdefcd616b2ff2 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 10 Jan 2022 03:24:01 +0800 Subject: [PATCH 06/30] Bluetooth: btmtksdio: clean up inconsistent error message in btmtksdio_mtk_reg_read Have "..reg (%d)" to be consistent with the other similar error messages. Signed-off-by: Sean Wang Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmtksdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index d82ba9d71fb8d..25fb9c79b1f42 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -816,7 +816,7 @@ static int btmtksdio_mtk_reg_read(struct hci_dev *hdev, u32 reg, u32 *val) err = mtk_hci_wmt_sync(hdev, &wmt_params); if (err < 0) { - bt_dev_err(hdev, "Failed to read reg(%d)", err); + bt_dev_err(hdev, "Failed to read reg (%d)", err); return err; } From c07ba878ca199a6089cdb323bf526adbeeb4201f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 11 Jan 2022 10:23:19 +0300 Subject: [PATCH 07/30] Bluetooth: hci_sync: unlock on error in hci_inquiry_result_with_rssi_evt() Add unlocks to two error paths in hci_inquiry_result_with_rssi_evt(). Fixes: fee645033e2c ("Bluetooth: hci_event: Use skb_pull_data when processing inquiry results") Signed-off-by: Dan Carpenter Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_event.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index fc30f4c03d292..05997dff56662 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4534,7 +4534,7 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, void *edata, if (!info) { bt_dev_err(hdev, "Malformed HCI Event: 0x%2.2x", HCI_EV_INQUIRY_RESULT_WITH_RSSI); - return; + goto unlock; } bacpy(&data.bdaddr, &info->bdaddr); @@ -4565,7 +4565,7 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, void *edata, if (!info) { bt_dev_err(hdev, "Malformed HCI Event: 0x%2.2x", HCI_EV_INQUIRY_RESULT_WITH_RSSI); - return; + goto unlock; } bacpy(&data.bdaddr, &info->bdaddr); @@ -4587,7 +4587,7 @@ static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, void *edata, bt_dev_err(hdev, "Malformed HCI Event: 0x%2.2x", HCI_EV_INQUIRY_RESULT_WITH_RSSI); } - +unlock: hci_dev_unlock(hdev); } From 3afee2118132e93e5f6fa636dfde86201a860ab3 Mon Sep 17 00:00:00 2001 From: Soenke Huster Date: Fri, 14 Jan 2022 17:44:02 +0100 Subject: [PATCH 08/30] Bluetooth: fix null ptr deref on hci_sync_conn_complete_evt This event is just specified for SCO and eSCO link types. On the reception of a HCI_Synchronous_Connection_Complete for a BDADDR of an existing LE connection, LE link type and a status that triggers the second case of the packet processing a NULL pointer dereference happens, as conn->link is NULL. Signed-off-by: Soenke Huster Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/hci_event.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 05997dff56662..681c623aa3806 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4661,6 +4661,19 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, void *data, struct hci_ev_sync_conn_complete *ev = data; struct hci_conn *conn; + switch (ev->link_type) { + case SCO_LINK: + case ESCO_LINK: + break; + default: + /* As per Core 5.3 Vol 4 Part E 7.7.35 (p.2219), Link_Type + * for HCI_Synchronous_Connection_Complete is limited to + * either SCO or eSCO + */ + bt_dev_err(hdev, "Ignoring connect complete event for invalid link type"); + return; + } + bt_dev_dbg(hdev, "status 0x%2.2x", ev->status); hci_dev_lock(hdev); From 3368aa357f3ba133ae65fc26c04d24a1447a3903 Mon Sep 17 00:00:00 2001 From: Manish Mandlik Date: Tue, 11 Jan 2022 08:14:25 -0800 Subject: [PATCH 09/30] Bluetooth: msft: Handle MSFT Monitor Device Event Whenever the controller starts/stops monitoring a bt device, it sends MSFT Monitor Device event. Add handler to read this vendor event. Test performed: - Verified by logs that the MSFT Monitor Device event is received from the controller whenever it starts/stops monitoring a device. Signed-off-by: Manish Mandlik Reviewed-by: Miao-chen Chou Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 11 +++ net/bluetooth/hci_core.c | 1 + net/bluetooth/msft.c | 158 +++++++++++++++++++++++++++++-- 3 files changed, 162 insertions(+), 8 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 586f69d084a2a..639fb9f57ae75 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -258,6 +258,15 @@ struct adv_info { #define HCI_ADV_TX_POWER_NO_PREFERENCE 0x7F +struct monitored_device { + struct list_head list; + + bdaddr_t bdaddr; + __u8 addr_type; + __u16 handle; + bool notified; +}; + struct adv_pattern { struct list_head list; __u8 ad_type; @@ -591,6 +600,8 @@ struct hci_dev { struct delayed_work interleave_scan; + struct list_head monitored_devices; + #if IS_ENABLED(CONFIG_BT_LEDS) struct led_trigger *power_led; #endif diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2b7bd3655b076..14c2da9d33ff4 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2503,6 +2503,7 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv) INIT_LIST_HEAD(&hdev->conn_hash.list); INIT_LIST_HEAD(&hdev->adv_instances); INIT_LIST_HEAD(&hdev->blocked_keys); + INIT_LIST_HEAD(&hdev->monitored_devices); INIT_LIST_HEAD(&hdev->local_codecs); INIT_WORK(&hdev->rx_work, hci_rx_work); diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c index 6a943634b31a2..213eab2f085a3 100644 --- a/net/bluetooth/msft.c +++ b/net/bluetooth/msft.c @@ -80,6 +80,14 @@ struct msft_rp_le_set_advertisement_filter_enable { __u8 sub_opcode; } __packed; +#define MSFT_EV_LE_MONITOR_DEVICE 0x02 +struct msft_ev_le_monitor_device { + __u8 addr_type; + bdaddr_t bdaddr; + __u8 monitor_handle; + __u8 monitor_state; +} __packed; + struct msft_monitor_advertisement_handle_data { __u8 msft_handle; __u16 mgmt_handle; @@ -204,6 +212,30 @@ static struct msft_monitor_advertisement_handle_data *msft_find_handle_data return NULL; } +/* This function requires the caller holds hdev->lock */ +static int msft_monitor_device_del(struct hci_dev *hdev, __u16 mgmt_handle, + bdaddr_t *bdaddr, __u8 addr_type) +{ + struct monitored_device *dev, *tmp; + int count = 0; + + list_for_each_entry_safe(dev, tmp, &hdev->monitored_devices, list) { + /* mgmt_handle == 0 indicates remove all devices, whereas, + * bdaddr == NULL indicates remove all devices matching the + * mgmt_handle. + */ + if ((!mgmt_handle || dev->handle == mgmt_handle) && + (!bdaddr || (!bacmp(bdaddr, &dev->bdaddr) && + addr_type == dev->addr_type))) { + list_del(&dev->list); + kfree(dev); + count++; + } + } + + return count; +} + static void msft_le_monitor_advertisement_cb(struct hci_dev *hdev, u8 status, u16 opcode, struct sk_buff *skb) @@ -294,6 +326,10 @@ static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev, if (monitor && !msft->suspending) hci_free_adv_monitor(hdev, monitor); + /* Clear any monitored devices by this Adv Monitor */ + msft_monitor_device_del(hdev, handle_data->mgmt_handle, NULL, + 0); + list_del(&handle_data->list); kfree(handle_data); } @@ -557,6 +593,13 @@ void msft_do_close(struct hci_dev *hdev) list_del(&handle_data->list); kfree(handle_data); } + + hci_dev_lock(hdev); + + /* Clear any devices that are being monitored */ + msft_monitor_device_del(hdev, 0, NULL, 0); + + hci_dev_unlock(hdev); } void msft_register(struct hci_dev *hdev) @@ -590,10 +633,97 @@ void msft_unregister(struct hci_dev *hdev) kfree(msft); } +/* This function requires the caller holds hdev->lock */ +static void msft_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, + __u8 addr_type, __u16 mgmt_handle) +{ + struct monitored_device *dev; + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + bt_dev_err(hdev, "MSFT vendor event %u: no memory", + MSFT_EV_LE_MONITOR_DEVICE); + return; + } + + bacpy(&dev->bdaddr, bdaddr); + dev->addr_type = addr_type; + dev->handle = mgmt_handle; + dev->notified = false; + + INIT_LIST_HEAD(&dev->list); + list_add(&dev->list, &hdev->monitored_devices); +} + +/* This function requires the caller holds hdev->lock */ +static void msft_device_lost(struct hci_dev *hdev, bdaddr_t *bdaddr, + __u8 addr_type, __u16 mgmt_handle) +{ + if (!msft_monitor_device_del(hdev, mgmt_handle, bdaddr, addr_type)) { + bt_dev_err(hdev, "MSFT vendor event %u: dev %pMR not in list", + MSFT_EV_LE_MONITOR_DEVICE, bdaddr); + } +} + +static void *msft_skb_pull(struct hci_dev *hdev, struct sk_buff *skb, + u8 ev, size_t len) +{ + void *data; + + data = skb_pull_data(skb, len); + if (!data) + bt_dev_err(hdev, "Malformed MSFT vendor event: 0x%02x", ev); + + return data; +} + +/* This function requires the caller holds hdev->lock */ +static void msft_monitor_device_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct msft_ev_le_monitor_device *ev; + struct msft_monitor_advertisement_handle_data *handle_data; + u8 addr_type; + + ev = msft_skb_pull(hdev, skb, MSFT_EV_LE_MONITOR_DEVICE, sizeof(*ev)); + if (!ev) + return; + + bt_dev_dbg(hdev, + "MSFT vendor event 0x%02x: handle 0x%04x state %d addr %pMR", + MSFT_EV_LE_MONITOR_DEVICE, ev->monitor_handle, + ev->monitor_state, &ev->bdaddr); + + handle_data = msft_find_handle_data(hdev, ev->monitor_handle, false); + + switch (ev->addr_type) { + case ADDR_LE_DEV_PUBLIC: + addr_type = BDADDR_LE_PUBLIC; + break; + + case ADDR_LE_DEV_RANDOM: + addr_type = BDADDR_LE_RANDOM; + break; + + default: + bt_dev_err(hdev, + "MSFT vendor event 0x%02x: unknown addr type 0x%02x", + MSFT_EV_LE_MONITOR_DEVICE, ev->addr_type); + return; + } + + if (ev->monitor_state) + msft_device_found(hdev, &ev->bdaddr, addr_type, + handle_data->mgmt_handle); + else + msft_device_lost(hdev, &ev->bdaddr, addr_type, + handle_data->mgmt_handle); +} + void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb) { struct msft_data *msft = hdev->msft_data; - u8 event; + u8 *evt_prefix; + u8 *evt; if (!msft) return; @@ -602,13 +732,12 @@ void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb) * matches, and otherwise just return. */ if (msft->evt_prefix_len > 0) { - if (skb->len < msft->evt_prefix_len) + evt_prefix = msft_skb_pull(hdev, skb, 0, msft->evt_prefix_len); + if (!evt_prefix) return; - if (memcmp(skb->data, msft->evt_prefix, msft->evt_prefix_len)) + if (memcmp(evt_prefix, msft->evt_prefix, msft->evt_prefix_len)) return; - - skb_pull(skb, msft->evt_prefix_len); } /* Every event starts at least with an event code and the rest of @@ -617,10 +746,23 @@ void msft_vendor_evt(struct hci_dev *hdev, void *data, struct sk_buff *skb) if (skb->len < 1) return; - event = *skb->data; - skb_pull(skb, 1); + evt = msft_skb_pull(hdev, skb, 0, sizeof(*evt)); + if (!evt) + return; + + hci_dev_lock(hdev); + + switch (*evt) { + case MSFT_EV_LE_MONITOR_DEVICE: + msft_monitor_device_evt(hdev, skb); + break; - bt_dev_dbg(hdev, "MSFT vendor event %u", event); + default: + bt_dev_dbg(hdev, "MSFT vendor event 0x%02x", *evt); + break; + } + + hci_dev_unlock(hdev); } __u64 msft_get_features(struct hci_dev *hdev) From 8d7f167752c3e4c45a39e76ffa6f7209413d3fa6 Mon Sep 17 00:00:00 2001 From: Manish Mandlik Date: Tue, 11 Jan 2022 08:14:26 -0800 Subject: [PATCH 10/30] Bluetooth: mgmt: Add MGMT Adv Monitor Device Found/Lost events This patch introduces two new MGMT events for notifying the bluetoothd whenever the controller starts/stops monitoring a device. Test performed: - Verified by logs that the MSFT Monitor Device is received from the controller and the bluetoothd is notified whenever the controller starts/stops monitoring a device. Signed-off-by: Manish Mandlik Reviewed-by: Miao-chen Chou Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 3 + include/net/bluetooth/mgmt.h | 16 +++++ net/bluetooth/mgmt.c | 115 +++++++++++++++++++++++++++++-- net/bluetooth/msft.c | 20 ++++-- 4 files changed, 144 insertions(+), 10 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 639fb9f57ae75..21eadb113a31a 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -601,6 +601,7 @@ struct hci_dev { struct delayed_work interleave_scan; struct list_head monitored_devices; + bool advmon_pend_notify; #if IS_ENABLED(CONFIG_BT_LEDS) struct led_trigger *power_led; @@ -1858,6 +1859,8 @@ void mgmt_adv_monitor_removed(struct hci_dev *hdev, u16 handle); int mgmt_phy_configuration_changed(struct hci_dev *hdev, struct sock *skip); int mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev, u8 status); int mgmt_remove_adv_monitor_complete(struct hci_dev *hdev, u8 status); +void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle, + bdaddr_t *bdaddr, u8 addr_type); u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, u16 to_multiplier); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 107b25deae683..99266f7aebdc9 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -1104,3 +1104,19 @@ struct mgmt_ev_controller_resume { #define MGMT_WAKE_REASON_NON_BT_WAKE 0x0 #define MGMT_WAKE_REASON_UNEXPECTED 0x1 #define MGMT_WAKE_REASON_REMOTE_WAKE 0x2 + +#define MGMT_EV_ADV_MONITOR_DEVICE_FOUND 0x002f +struct mgmt_ev_adv_monitor_device_found { + __le16 monitor_handle; + struct mgmt_addr_info addr; + __s8 rssi; + __le32 flags; + __le16 eir_len; + __u8 eir[0]; +} __packed; + +#define MGMT_EV_ADV_MONITOR_DEVICE_LOST 0x0030 +struct mgmt_ev_adv_monitor_device_lost { + __le16 monitor_handle; + struct mgmt_addr_info addr; +} __packed; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 37087cf7dc5af..08d6494f1b34e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -174,6 +174,8 @@ static const u16 mgmt_events[] = { MGMT_EV_ADV_MONITOR_REMOVED, MGMT_EV_CONTROLLER_SUSPEND, MGMT_EV_CONTROLLER_RESUME, + MGMT_EV_ADV_MONITOR_DEVICE_FOUND, + MGMT_EV_ADV_MONITOR_DEVICE_LOST, }; static const u16 mgmt_untrusted_commands[] = { @@ -9589,12 +9591,116 @@ static bool is_filter_match(struct hci_dev *hdev, s8 rssi, u8 *eir, return true; } +void mgmt_adv_monitor_device_lost(struct hci_dev *hdev, u16 handle, + bdaddr_t *bdaddr, u8 addr_type) +{ + struct mgmt_ev_adv_monitor_device_lost ev; + + ev.monitor_handle = cpu_to_le16(handle); + bacpy(&ev.addr.bdaddr, bdaddr); + ev.addr.type = addr_type; + + mgmt_event(MGMT_EV_ADV_MONITOR_DEVICE_LOST, hdev, &ev, sizeof(ev), + NULL); +} + +static void mgmt_adv_monitor_device_found(struct hci_dev *hdev, + bdaddr_t *bdaddr, bool report_device, + struct sk_buff *skb, + struct sock *skip_sk) +{ + struct sk_buff *advmon_skb; + size_t advmon_skb_len; + __le16 *monitor_handle; + struct monitored_device *dev, *tmp; + bool matched = false; + bool notify = false; + + /* We have received the Advertisement Report because: + * 1. the kernel has initiated active discovery + * 2. if not, we have pend_le_reports > 0 in which case we are doing + * passive scanning + * 3. if none of the above is true, we have one or more active + * Advertisement Monitor + * + * For case 1 and 2, report all advertisements via MGMT_EV_DEVICE_FOUND + * and report ONLY one advertisement per device for the matched Monitor + * via MGMT_EV_ADV_MONITOR_DEVICE_FOUND event. + * + * For case 3, since we are not active scanning and all advertisements + * received are due to a matched Advertisement Monitor, report all + * advertisements ONLY via MGMT_EV_ADV_MONITOR_DEVICE_FOUND event. + */ + if (report_device && !hdev->advmon_pend_notify) { + mgmt_event_skb(skb, skip_sk); + return; + } + + advmon_skb_len = (sizeof(struct mgmt_ev_adv_monitor_device_found) - + sizeof(struct mgmt_ev_device_found)) + skb->len; + advmon_skb = mgmt_alloc_skb(hdev, MGMT_EV_ADV_MONITOR_DEVICE_FOUND, + advmon_skb_len); + if (!advmon_skb) { + if (report_device) + mgmt_event_skb(skb, skip_sk); + else + kfree_skb(skb); + return; + } + + /* ADV_MONITOR_DEVICE_FOUND is similar to DEVICE_FOUND event except + * that it also has 'monitor_handle'. Make a copy of DEVICE_FOUND and + * store monitor_handle of the matched monitor. + */ + monitor_handle = skb_put(advmon_skb, sizeof(*monitor_handle)); + skb_put_data(advmon_skb, skb->data, skb->len); + + hdev->advmon_pend_notify = false; + + list_for_each_entry_safe(dev, tmp, &hdev->monitored_devices, list) { + if (!bacmp(&dev->bdaddr, bdaddr)) { + matched = true; + + if (!dev->notified) { + *monitor_handle = cpu_to_le16(dev->handle); + notify = true; + dev->notified = true; + } + } + + if (!dev->notified) + hdev->advmon_pend_notify = true; + } + + if (!report_device && + ((matched && !notify) || !msft_monitor_supported(hdev))) { + /* Handle 0 indicates that we are not active scanning and this + * is a subsequent advertisement report for an already matched + * Advertisement Monitor or the controller offloading support + * is not available. + */ + *monitor_handle = 0; + notify = true; + } + + if (report_device) + mgmt_event_skb(skb, skip_sk); + else + kfree_skb(skb); + + if (notify) + mgmt_event_skb(advmon_skb, skip_sk); + else + kfree_skb(advmon_skb); +} + void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 *dev_class, s8 rssi, u32 flags, u8 *eir, u16 eir_len, u8 *scan_rsp, u8 scan_rsp_len) { struct sk_buff *skb; struct mgmt_ev_device_found *ev; + bool report_device = hci_discovery_active(hdev); /* Don't send events for a non-kernel initiated discovery. With * LE one exception is if we have pend_le_reports > 0 in which @@ -9603,11 +9709,10 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, if (!hci_discovery_active(hdev)) { if (link_type == ACL_LINK) return; - if (link_type == LE_LINK && - list_empty(&hdev->pend_le_reports) && - !hci_is_adv_monitoring(hdev)) { + if (link_type == LE_LINK && !list_empty(&hdev->pend_le_reports)) + report_device = true; + else if (!hci_is_adv_monitoring(hdev)) return; - } } if (hdev->discovery.result_filtering) { @@ -9672,7 +9777,7 @@ void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, ev->eir_len = cpu_to_le16(eir_len + scan_rsp_len); - mgmt_event_skb(skb, NULL); + mgmt_adv_monitor_device_found(hdev, bdaddr, report_device, skb, NULL); } void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c index 213eab2f085a3..4845408558636 100644 --- a/net/bluetooth/msft.c +++ b/net/bluetooth/msft.c @@ -214,7 +214,8 @@ static struct msft_monitor_advertisement_handle_data *msft_find_handle_data /* This function requires the caller holds hdev->lock */ static int msft_monitor_device_del(struct hci_dev *hdev, __u16 mgmt_handle, - bdaddr_t *bdaddr, __u8 addr_type) + bdaddr_t *bdaddr, __u8 addr_type, + bool notify) { struct monitored_device *dev, *tmp; int count = 0; @@ -227,6 +228,12 @@ static int msft_monitor_device_del(struct hci_dev *hdev, __u16 mgmt_handle, if ((!mgmt_handle || dev->handle == mgmt_handle) && (!bdaddr || (!bacmp(bdaddr, &dev->bdaddr) && addr_type == dev->addr_type))) { + if (notify && dev->notified) { + mgmt_adv_monitor_device_lost(hdev, dev->handle, + &dev->bdaddr, + dev->addr_type); + } + list_del(&dev->list); kfree(dev); count++; @@ -328,7 +335,7 @@ static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev, /* Clear any monitored devices by this Adv Monitor */ msft_monitor_device_del(hdev, handle_data->mgmt_handle, NULL, - 0); + 0, false); list_del(&handle_data->list); kfree(handle_data); @@ -596,8 +603,9 @@ void msft_do_close(struct hci_dev *hdev) hci_dev_lock(hdev); - /* Clear any devices that are being monitored */ - msft_monitor_device_del(hdev, 0, NULL, 0); + /* Clear any devices that are being monitored and notify device lost */ + hdev->advmon_pend_notify = false; + msft_monitor_device_del(hdev, 0, NULL, 0, true); hci_dev_unlock(hdev); } @@ -653,13 +661,15 @@ static void msft_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, INIT_LIST_HEAD(&dev->list); list_add(&dev->list, &hdev->monitored_devices); + hdev->advmon_pend_notify = true; } /* This function requires the caller holds hdev->lock */ static void msft_device_lost(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 addr_type, __u16 mgmt_handle) { - if (!msft_monitor_device_del(hdev, mgmt_handle, bdaddr, addr_type)) { + if (!msft_monitor_device_del(hdev, mgmt_handle, bdaddr, addr_type, + true)) { bt_dev_err(hdev, "MSFT vendor event %u: dev %pMR not in list", MSFT_EV_LE_MONITOR_DEVICE, bdaddr); } From 55235304c2560d4a94ccfff2a47ea927b4114064 Mon Sep 17 00:00:00 2001 From: Tedd Ho-Jeong An Date: Thu, 20 Jan 2022 11:44:18 -0800 Subject: [PATCH 11/30] Bluetooth: btintel: Fix WBS setting for Intel legacy ROM products This patch adds the flag to identify the Intel legacy ROM products that don't support WBS like WP and StP. Fixes: 3df4dfbec0f29 ("Bluetooth: btintel: Move hci quirks to setup routine") Signed-off-by: Tedd Ho-Jeong An Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btintel.c | 11 ++++++++--- drivers/bluetooth/btintel.h | 1 + drivers/bluetooth/btusb.c | 6 ++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 1a4f8b227eac0..06514ed660229 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -2428,10 +2428,15 @@ static int btintel_setup_combined(struct hci_dev *hdev) /* Apply the device specific HCI quirks * - * WBS for SdP - SdP and Stp have a same hw_varaint but - * different fw_variant + * WBS for SdP - For the Legacy ROM products, only SdP + * supports the WBS. But the version information is not + * enough to use here because the StP2 and SdP have same + * hw_variant and fw_variant. So, this flag is set by + * the transport driver (btusb) based on the HW info + * (idProduct) */ - if (ver.hw_variant == 0x08 && ver.fw_variant == 0x22) + if (!btintel_test_flag(hdev, + INTEL_ROM_LEGACY_NO_WBS_SUPPORT)) set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks); diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index c9b24e9299e2a..e0060e58573c3 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -152,6 +152,7 @@ enum { INTEL_BROKEN_INITIAL_NCMD, INTEL_BROKEN_SHUTDOWN_LED, INTEL_ROM_LEGACY, + INTEL_ROM_LEGACY_NO_WBS_SUPPORT, __INTEL_NUM_FLAGS, }; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c30d131da7847..cbd0eaa05e174 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -62,6 +62,7 @@ static struct usb_driver btusb_driver; #define BTUSB_QCA_WCN6855 0x1000000 #define BTUSB_INTEL_BROKEN_SHUTDOWN_LED 0x2000000 #define BTUSB_INTEL_BROKEN_INITIAL_NCMD 0x4000000 +#define BTUSB_INTEL_NO_WBS_SUPPORT 0x8000000 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -385,9 +386,11 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x8087, 0x0033), .driver_info = BTUSB_INTEL_COMBINED }, { USB_DEVICE(0x8087, 0x07da), .driver_info = BTUSB_CSR }, { USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL_COMBINED | + BTUSB_INTEL_NO_WBS_SUPPORT | BTUSB_INTEL_BROKEN_INITIAL_NCMD | BTUSB_INTEL_BROKEN_SHUTDOWN_LED }, { USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL_COMBINED | + BTUSB_INTEL_NO_WBS_SUPPORT | BTUSB_INTEL_BROKEN_SHUTDOWN_LED }, { USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_COMBINED }, { USB_DEVICE(0x8087, 0x0aa7), .driver_info = BTUSB_INTEL_COMBINED | @@ -3737,6 +3740,9 @@ static int btusb_probe(struct usb_interface *intf, hdev->send = btusb_send_frame_intel; hdev->cmd_timeout = btusb_intel_cmd_timeout; + if (id->driver_info & BTUSB_INTEL_NO_WBS_SUPPORT) + btintel_set_flag(hdev, INTEL_ROM_LEGACY_NO_WBS_SUPPORT); + if (id->driver_info & BTUSB_INTEL_BROKEN_INITIAL_NCMD) btintel_set_flag(hdev, INTEL_BROKEN_INITIAL_NCMD); From 2e7b4a328ed6ea57d22853939e69bc86c560996d Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 19 Jan 2022 14:18:37 -0600 Subject: [PATCH 12/30] Bluetooth: btusb: Add one more Bluetooth part for the Realtek RTL8852AE This Realtek device has both wifi and BT components. The latter reports a USB ID of 0bda:2852, which is not in the table. BT device description in /sys/kernel/debug/usb/devices contains the following entries: T: Bus=01 Lev=01 Prnt=01 Port=03 Cnt=02 Dev#= 3 Spd=12 MxCh= 0 D: Ver= 1.00 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0bda ProdID=2852 Rev= 0.00 S: Manufacturer=Realtek S: Product=Bluetooth Radio S: SerialNumber=00e04c000001 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=500mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms The missing USB_ID was reported by user trius65 at https://github.com/lwfinger/rtw89/issues/122 Signed-off-by: Larry Finger Cc: stable@vger.kernel.org Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index cbd0eaa05e174..06effcae0e3fd 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -408,6 +408,8 @@ static const struct usb_device_id blacklist_table[] = { BTUSB_WIDEBAND_SPEECH }, /* Realtek 8852AE Bluetooth devices */ + { USB_DEVICE(0x0bda, 0x2852), .driver_info = BTUSB_REALTEK | + BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0bda, 0xc852), .driver_info = BTUSB_REALTEK | BTUSB_WIDEBAND_SPEECH }, { USB_DEVICE(0x0bda, 0x385a), .driver_info = BTUSB_REALTEK | From aa17e8ce1c20619af46fc2b472aa2d1c5e50c3cc Mon Sep 17 00:00:00 2001 From: Ismael Ferreras Morezuelas Date: Tue, 18 Jan 2022 09:04:19 +0100 Subject: [PATCH 13/30] Bluetooth: btusb: Whitespace fixes for btusb_setup_csr() Properly align the list items of the quirk for readability. No functional changes intended. Trivial stuff. Fixes: 0671c0662383e ("Bluetooth: btusb: Add workaround for remote-wakeup issues with Barrot 8041a02 fake CSR controllers") Signed-off-by: Ismael Ferreras Morezuelas Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 06effcae0e3fd..aefa0ee293f36 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -2062,10 +2062,10 @@ static int btusb_setup_csr(struct hci_dev *hdev) * These controllers are really messed-up. * * 1. Their bulk RX endpoint will never report any data unless - * the device was suspended at least once (yes, really). + * the device was suspended at least once (yes, really). * 2. They will not wakeup when autosuspended and receiving data - * on their bulk RX endpoint from e.g. a keyboard or mouse - * (IOW remote-wakeup support is broken for the bulk endpoint). + * on their bulk RX endpoint from e.g. a keyboard or mouse + * (IOW remote-wakeup support is broken for the bulk endpoint). * * To fix 1. enable runtime-suspend, force-suspend the * HCI and then wake-it up by disabling runtime-suspend. From a86974f75e8806bc357a9be02f9bde083f40b4ae Mon Sep 17 00:00:00 2001 From: Tedd Ho-Jeong An Date: Fri, 14 Jan 2022 17:03:29 -0800 Subject: [PATCH 14/30] Bluetooth: Remove kernel-doc style comment block This patch changes the kernel-doc style comment block to common comment block. These files don't support kernel-doc style so no need to use the kernel-doc style. Also, they cause the warning when W=1 option is used as below. drivers/bluetooth/hci_ll.c:518: warning: Function parameter or member 'lldev' not described in 'download_firmware' drivers/bluetooth/btmrvl_debugfs.c:29: warning: cannot understand function prototype: 'struct btmrvl_debugfs_data ' drivers/bluetooth/btmrvl_sdio.c:36: warning: expecting prototype for Marvell BT-over-SDIO driver(). Prototype was for VERSION() instead Signed-off-by: Tedd Ho-Jeong An Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_debugfs.c | 2 +- drivers/bluetooth/btmrvl_sdio.c | 2 +- drivers/bluetooth/hci_ll.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/btmrvl_debugfs.c b/drivers/bluetooth/btmrvl_debugfs.c index c4867576be008..db35b917aecfc 100644 --- a/drivers/bluetooth/btmrvl_debugfs.c +++ b/drivers/bluetooth/btmrvl_debugfs.c @@ -1,4 +1,4 @@ -/** +/* * Marvell Bluetooth driver: debugfs related functions * * Copyright (C) 2009, Marvell International Ltd. diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 68378b42ea7fd..b8ef66f89fc10 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -1,4 +1,4 @@ -/** +/* * Marvell BT-over-SDIO driver: SDIO interface related functions. * * Copyright (C) 2009, Marvell International Ltd. diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index eb1e736efeebb..4eb420a9ed04e 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -509,7 +509,7 @@ static int send_command_from_firmware(struct ll_device *lldev, return 0; } -/** +/* * download_firmware - * internal function which parses through the .bts firmware * script file intreprets SEND, DELAY actions only as of now From 9d7cbe2b9cf5f650067df4f402fdd799d4bbb4e1 Mon Sep 17 00:00:00 2001 From: Pavel Skripkin Date: Thu, 13 Jan 2022 16:27:04 +0300 Subject: [PATCH 15/30] Bluetooth: hci_serdev: call init_rwsem() before p->open() kvartet reported, that hci_uart_tx_wakeup() uses uninitialized rwsem. The problem was in wrong place for percpu_init_rwsem() call. hci_uart_proto::open() may register a timer whose callback may call hci_uart_tx_wakeup(). There is a chance, that hci_uart_register_device() thread won't be fast enough to call percpu_init_rwsem(). Fix it my moving percpu_init_rwsem() call before p->open(). INFO: trying to register non-static key. The code is fine but needs lockdep annotation, or maybe you didn't initialize this object before use? turning off the locking correctness validator. CPU: 2 PID: 18524 Comm: syz-executor.5 Not tainted 5.16.0-rc6 #9 ... Call Trace: __dump_stack lib/dump_stack.c:88 [inline] dump_stack_lvl+0xcd/0x134 lib/dump_stack.c:106 assign_lock_key kernel/locking/lockdep.c:951 [inline] register_lock_class+0x148d/0x1950 kernel/locking/lockdep.c:1263 __lock_acquire+0x106/0x57e0 kernel/locking/lockdep.c:4906 lock_acquire kernel/locking/lockdep.c:5637 [inline] lock_acquire+0x1ab/0x520 kernel/locking/lockdep.c:5602 percpu_down_read_trylock include/linux/percpu-rwsem.h:92 [inline] hci_uart_tx_wakeup+0x12e/0x490 drivers/bluetooth/hci_ldisc.c:124 h5_timed_event+0x32f/0x6a0 drivers/bluetooth/hci_h5.c:188 call_timer_fn+0x1a5/0x6b0 kernel/time/timer.c:1421 Fixes: d73e17281665 ("Bluetooth: hci_serdev: Init hci_uart proto_lock to avoid oops") Reported-by: Yiru Xu Signed-off-by: Pavel Skripkin Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_serdev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c index 3b00d82d36cf7..4cda890ce6470 100644 --- a/drivers/bluetooth/hci_serdev.c +++ b/drivers/bluetooth/hci_serdev.c @@ -305,6 +305,8 @@ int hci_uart_register_device(struct hci_uart *hu, if (err) return err; + percpu_init_rwsem(&hu->proto_lock); + err = p->open(hu); if (err) goto err_open; @@ -327,7 +329,6 @@ int hci_uart_register_device(struct hci_uart *hu, INIT_WORK(&hu->init_ready, hci_uart_init_work); INIT_WORK(&hu->write_work, hci_uart_write_work); - percpu_init_rwsem(&hu->proto_lock); /* Only when vendor specific setup callback is provided, consider * the manufacturer information valid. This avoids filling in the From 2fc967cc0dadad6735448cfbcbc77fe0ea30203d Mon Sep 17 00:00:00 2001 From: Mark Chen Date: Wed, 12 Jan 2022 15:39:11 +0800 Subject: [PATCH 16/30] Bluetooth: mt7921s: fix firmware coredump retrieve According to the MCU firmware behavior, as the driver is aware of the notification of the interrupt source FW_MAILBOX_INT that shows the MCU completed delivered a core dump piece to the host, the driver must acknowledge the MCU with the register PH2DSM0R bit PH2DSM0R_DRIVER_OWN to notify the MCU to handle the next core dump piece. Fixes: db57b625912a ("Bluetooth: btmtksdio: add support of processing firmware coredump and log") Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Mark Chen Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmtksdio.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 25fb9c79b1f42..784e65c3fdddb 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -87,8 +87,12 @@ MODULE_DEVICE_TABLE(sdio, btmtksdio_table); #define RX_DONE_INT BIT(1) #define TX_EMPTY BIT(2) #define TX_FIFO_OVERFLOW BIT(8) +#define FW_MAILBOX_INT BIT(15) #define RX_PKT_LEN GENMASK(31, 16) +#define MTK_REG_PH2DSM0R 0xc4 +#define PH2DSM0R_DRIVER_OWN BIT(0) + #define MTK_REG_CTDR 0x18 #define MTK_REG_CRDR 0x1c @@ -481,6 +485,12 @@ static void btmtksdio_txrx_work(struct work_struct *work) */ sdio_writel(bdev->func, int_status, MTK_REG_CHISR, NULL); + if ((int_status & FW_MAILBOX_INT) && + bdev->data->chipid == 0x7921) { + sdio_writel(bdev->func, PH2DSM0R_DRIVER_OWN, + MTK_REG_PH2DSM0R, 0); + } + if (int_status & FW_OWN_BACK_INT) bt_dev_dbg(bdev->hdev, "Get fw own back"); From c7e301d7c85544607ccc52ca5f26d20c59485342 Mon Sep 17 00:00:00 2001 From: Mark Chen Date: Wed, 12 Jan 2022 15:39:12 +0800 Subject: [PATCH 17/30] Bluetooth: btmtksdio: refactor btmtksdio_runtime_[suspend|resume]() Refactor btmtksdio_runtime_[suspend|resume]() to create the common funcitons btmtksdio_[fw|drv]_pmctrl() shared with btmtksdio_[open|close]() to avoid the redundant code as well. This is also a prerequisite patch for the incoming patches. Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Mark Chen Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmtksdio.c | 94 ++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 784e65c3fdddb..8cbd49013d868 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -282,6 +282,54 @@ static u32 btmtksdio_drv_own_query(struct btmtksdio_dev *bdev) return sdio_readl(bdev->func, MTK_REG_CHLPCR, NULL); } +static int btmtksdio_fw_pmctrl(struct btmtksdio_dev *bdev) +{ + u32 status; + int err; + + sdio_claim_host(bdev->func); + + /* Return ownership to the device */ + sdio_writel(bdev->func, C_FW_OWN_REQ_SET, MTK_REG_CHLPCR, &err); + if (err < 0) + goto out; + + err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status, + !(status & C_COM_DRV_OWN), 2000, 1000000); + +out: + sdio_release_host(bdev->func); + + if (err < 0) + bt_dev_err(bdev->hdev, "Cannot return ownership to device"); + + return err; +} + +static int btmtksdio_drv_pmctrl(struct btmtksdio_dev *bdev) +{ + u32 status; + int err; + + sdio_claim_host(bdev->func); + + /* Get ownership from the device */ + sdio_writel(bdev->func, C_FW_OWN_REQ_CLR, MTK_REG_CHLPCR, &err); + if (err < 0) + goto out; + + err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status, + status & C_COM_DRV_OWN, 2000, 1000000); + +out: + sdio_release_host(bdev->func); + + if (err < 0) + bt_dev_err(bdev->hdev, "Cannot get ownership from device"); + + return err; +} + static int btmtksdio_recv_event(struct hci_dev *hdev, struct sk_buff *skb) { struct btmtksdio_dev *bdev = hci_get_drvdata(hdev); @@ -541,7 +589,7 @@ static void btmtksdio_interrupt(struct sdio_func *func) static int btmtksdio_open(struct hci_dev *hdev) { struct btmtksdio_dev *bdev = hci_get_drvdata(hdev); - u32 status, val; + u32 val; int err; sdio_claim_host(bdev->func); @@ -552,18 +600,10 @@ static int btmtksdio_open(struct hci_dev *hdev) set_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state); - /* Get ownership from the device */ - sdio_writel(bdev->func, C_FW_OWN_REQ_CLR, MTK_REG_CHLPCR, &err); + err = btmtksdio_drv_pmctrl(bdev); if (err < 0) goto err_disable_func; - err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status, - status & C_COM_DRV_OWN, 2000, 1000000); - if (err < 0) { - bt_dev_err(bdev->hdev, "Cannot get ownership from device"); - goto err_disable_func; - } - /* Disable interrupt & mask out all interrupt sources */ sdio_writel(bdev->func, C_INT_EN_CLR, MTK_REG_CHLPCR, &err); if (err < 0) @@ -633,8 +673,6 @@ static int btmtksdio_open(struct hci_dev *hdev) static int btmtksdio_close(struct hci_dev *hdev) { struct btmtksdio_dev *bdev = hci_get_drvdata(hdev); - u32 status; - int err; sdio_claim_host(bdev->func); @@ -645,13 +683,7 @@ static int btmtksdio_close(struct hci_dev *hdev) cancel_work_sync(&bdev->txrx_work); - /* Return ownership to the device */ - sdio_writel(bdev->func, C_FW_OWN_REQ_SET, MTK_REG_CHLPCR, NULL); - - err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status, - !(status & C_COM_DRV_OWN), 2000, 1000000); - if (err < 0) - bt_dev_err(bdev->hdev, "Cannot return ownership to device"); + btmtksdio_fw_pmctrl(bdev); clear_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state); sdio_disable_func(bdev->func); @@ -1162,7 +1194,6 @@ static int btmtksdio_runtime_suspend(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); struct btmtksdio_dev *bdev; - u32 status; int err; bdev = sdio_get_drvdata(func); @@ -1174,19 +1205,10 @@ static int btmtksdio_runtime_suspend(struct device *dev) sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); - sdio_claim_host(bdev->func); - - sdio_writel(bdev->func, C_FW_OWN_REQ_SET, MTK_REG_CHLPCR, &err); - if (err < 0) - goto out; + err = btmtksdio_fw_pmctrl(bdev); - err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status, - !(status & C_COM_DRV_OWN), 2000, 1000000); -out: bt_dev_info(bdev->hdev, "status (%d) return ownership to device", err); - sdio_release_host(bdev->func); - return err; } @@ -1194,7 +1216,6 @@ static int btmtksdio_runtime_resume(struct device *dev) { struct sdio_func *func = dev_to_sdio_func(dev); struct btmtksdio_dev *bdev; - u32 status; int err; bdev = sdio_get_drvdata(func); @@ -1204,19 +1225,10 @@ static int btmtksdio_runtime_resume(struct device *dev) if (!test_bit(BTMTKSDIO_FUNC_ENABLED, &bdev->tx_state)) return 0; - sdio_claim_host(bdev->func); - - sdio_writel(bdev->func, C_FW_OWN_REQ_CLR, MTK_REG_CHLPCR, &err); - if (err < 0) - goto out; + err = btmtksdio_drv_pmctrl(bdev); - err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status, - status & C_COM_DRV_OWN, 2000, 1000000); -out: bt_dev_info(bdev->hdev, "status (%d) get ownership from device", err); - sdio_release_host(bdev->func); - return err; } From 752aea58489fd42f5c54dc50cb098d19e486ae61 Mon Sep 17 00:00:00 2001 From: Mark Chen Date: Wed, 12 Jan 2022 15:39:13 +0800 Subject: [PATCH 18/30] Bluetooth: mt7921s: fix bus hang with wrong privilege According to chip hw flow, mt7921s need to re-acquire privilege again before normal running. Otherwise, the bus may be stuck in an abnormal status. Fixes: c603bf1f94d0 ("Bluetooth: btmtksdio: add MT7921s Bluetooth support") Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Mark Chen Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmtksdio.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 8cbd49013d868..0951bb10d1176 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -960,6 +960,14 @@ static int btmtksdio_setup(struct hci_dev *hdev) if (err < 0) return err; + err = btmtksdio_fw_pmctrl(bdev); + if (err < 0) + return err; + + err = btmtksdio_drv_pmctrl(bdev); + if (err < 0) + return err; + /* Enable SCO over I2S/PCM */ err = btmtksdio_sco_setting(hdev); if (err < 0) { From 01ecc177b7d7ba055b79645e60e89385736ef2fc Mon Sep 17 00:00:00 2001 From: Mark Chen Date: Wed, 12 Jan 2022 15:39:14 +0800 Subject: [PATCH 19/30] Bluetooth: mt7921s: fix btmtksdio_[drv|fw]_pmctrl() According to the firmware behavior (even the oldest one in linux-firmware) If the firmware is downloaded, MT7921S must rely on the additional mailbox mechanism that resides in firmware to check if the device is the right state for btmtksdio_mcu_[drv|fw]_pmctrl(). Otherwise, we still apply the old way for that. That is a necessary patch before we enable runtime pm for mt7921s as default. Fixes: c603bf1f94d0 ("Bluetooth: btmtksdio: add MT7921s Bluetooth support") Co-developed-by: Sean Wang Signed-off-by: Sean Wang Signed-off-by: Mark Chen Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmtksdio.c | 38 +++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 0951bb10d1176..b0aae4143037f 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -38,21 +38,25 @@ static bool enable_autosuspend; struct btmtksdio_data { const char *fwname; u16 chipid; + bool lp_mbox_supported; }; static const struct btmtksdio_data mt7663_data = { .fwname = FIRMWARE_MT7663, .chipid = 0x7663, + .lp_mbox_supported = false, }; static const struct btmtksdio_data mt7668_data = { .fwname = FIRMWARE_MT7668, .chipid = 0x7668, + .lp_mbox_supported = false, }; static const struct btmtksdio_data mt7921_data = { .fwname = FIRMWARE_MT7961, .chipid = 0x7921, + .lp_mbox_supported = true, }; static const struct sdio_device_id btmtksdio_table[] = { @@ -90,8 +94,12 @@ MODULE_DEVICE_TABLE(sdio, btmtksdio_table); #define FW_MAILBOX_INT BIT(15) #define RX_PKT_LEN GENMASK(31, 16) +#define MTK_REG_CSICR 0xc0 +#define CSICR_CLR_MBOX_ACK BIT(0) #define MTK_REG_PH2DSM0R 0xc4 #define PH2DSM0R_DRIVER_OWN BIT(0) +#define MTK_REG_PD2HRM0R 0xdc +#define PD2HRM0R_DRV_OWN BIT(0) #define MTK_REG_CTDR 0x18 @@ -104,6 +112,7 @@ MODULE_DEVICE_TABLE(sdio, btmtksdio_table); #define BTMTKSDIO_TX_WAIT_VND_EVT 1 #define BTMTKSDIO_HW_TX_READY 2 #define BTMTKSDIO_FUNC_ENABLED 3 +#define BTMTKSDIO_PATCH_ENABLED 4 struct mtkbtsdio_hdr { __le16 len; @@ -282,6 +291,11 @@ static u32 btmtksdio_drv_own_query(struct btmtksdio_dev *bdev) return sdio_readl(bdev->func, MTK_REG_CHLPCR, NULL); } +static u32 btmtksdio_drv_own_query_79xx(struct btmtksdio_dev *bdev) +{ + return sdio_readl(bdev->func, MTK_REG_PD2HRM0R, NULL); +} + static int btmtksdio_fw_pmctrl(struct btmtksdio_dev *bdev) { u32 status; @@ -289,6 +303,19 @@ static int btmtksdio_fw_pmctrl(struct btmtksdio_dev *bdev) sdio_claim_host(bdev->func); + if (bdev->data->lp_mbox_supported && + test_bit(BTMTKSDIO_PATCH_ENABLED, &bdev->tx_state)) { + sdio_writel(bdev->func, CSICR_CLR_MBOX_ACK, MTK_REG_CSICR, + &err); + err = readx_poll_timeout(btmtksdio_drv_own_query_79xx, bdev, + status, !(status & PD2HRM0R_DRV_OWN), + 2000, 1000000); + if (err < 0) { + bt_dev_err(bdev->hdev, "mailbox ACK not cleared"); + goto out; + } + } + /* Return ownership to the device */ sdio_writel(bdev->func, C_FW_OWN_REQ_SET, MTK_REG_CHLPCR, &err); if (err < 0) @@ -321,6 +348,12 @@ static int btmtksdio_drv_pmctrl(struct btmtksdio_dev *bdev) err = readx_poll_timeout(btmtksdio_drv_own_query, bdev, status, status & C_COM_DRV_OWN, 2000, 1000000); + if (!err && bdev->data->lp_mbox_supported && + test_bit(BTMTKSDIO_PATCH_ENABLED, &bdev->tx_state)) + err = readx_poll_timeout(btmtksdio_drv_own_query_79xx, bdev, + status, status & PD2HRM0R_DRV_OWN, + 2000, 1000000); + out: sdio_release_host(bdev->func); @@ -728,6 +761,7 @@ static int btmtksdio_func_query(struct hci_dev *hdev) static int mt76xx_setup(struct hci_dev *hdev, const char *fwname) { + struct btmtksdio_dev *bdev = hci_get_drvdata(hdev); struct btmtk_hci_wmt_params wmt_params; struct btmtk_tci_sleep tci_sleep; struct sk_buff *skb; @@ -788,6 +822,8 @@ static int mt76xx_setup(struct hci_dev *hdev, const char *fwname) return err; } + set_bit(BTMTKSDIO_PATCH_ENABLED, &bdev->tx_state); + ignore_func_on: /* Apply the low power environment setup */ tci_sleep.mode = 0x5; @@ -810,6 +846,7 @@ static int mt76xx_setup(struct hci_dev *hdev, const char *fwname) static int mt79xx_setup(struct hci_dev *hdev, const char *fwname) { + struct btmtksdio_dev *bdev = hci_get_drvdata(hdev); struct btmtk_hci_wmt_params wmt_params; u8 param = 0x1; int err; @@ -835,6 +872,7 @@ static int mt79xx_setup(struct hci_dev *hdev, const char *fwname) hci_set_msft_opcode(hdev, 0xFD30); hci_set_aosp_capable(hdev); + set_bit(BTMTKSDIO_PATCH_ENABLED, &bdev->tx_state); return err; } From 095519de2debef7666d519208ac2e7bc96cfa6bf Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jan 2022 15:39:15 +0800 Subject: [PATCH 20/30] Bluetooth: btmtksdio: lower log level in btmtksdio_runtime_[resume|suspend]() Lower its log level from INFO to DEBUG prior to we enable runtime pm for mt7921s with the smaller idle time as default. Signed-off-by: Sean Wang Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmtksdio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index b0aae4143037f..3e8f19556e2c8 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -1253,7 +1253,7 @@ static int btmtksdio_runtime_suspend(struct device *dev) err = btmtksdio_fw_pmctrl(bdev); - bt_dev_info(bdev->hdev, "status (%d) return ownership to device", err); + bt_dev_dbg(bdev->hdev, "status (%d) return ownership to device", err); return err; } @@ -1273,7 +1273,7 @@ static int btmtksdio_runtime_resume(struct device *dev) err = btmtksdio_drv_pmctrl(bdev); - bt_dev_info(bdev->hdev, "status (%d) get ownership from device", err); + bt_dev_dbg(bdev->hdev, "status (%d) get ownership from device", err); return err; } From e98aa38cafec489ec025572c529dfb3d64559718 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jan 2022 15:39:16 +0800 Subject: [PATCH 21/30] Bluetooth: btmtksdio: run sleep mode by default Apply sleep mode by default and a smaller idle time to reduce power consumption further. Signed-off-by: Sean Wang Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmtksdio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 3e8f19556e2c8..491f029452ca8 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -31,9 +31,9 @@ #define VERSION "0.1" -#define MTKBTSDIO_AUTOSUSPEND_DELAY 8000 +#define MTKBTSDIO_AUTOSUSPEND_DELAY 1000 -static bool enable_autosuspend; +static bool enable_autosuspend = true; struct btmtksdio_data { const char *fwname; From db3f1f9b5d88d8d7f9eaa486f71784dd319285ff Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Wed, 12 Jan 2022 15:39:17 +0800 Subject: [PATCH 22/30] Bluetooth: btmtksdio: mask out interrupt status Currently, there is a loop in btmtksdio_txrx_work() which iteratively executes until the variable int_status is zero. But the variable int_status should be masked out with the actual interrupt sources (MTK_REG_CHISR bit 0-15) before we check the loop condition. Otherwise, RX_PKT_LEN (MTK_REG_CHISR bit 16-31) which is read-only and unclearable would cause the loop to get stuck on some chipsets like MT7663s. Fixes: 26270bc189ea ("Bluetooth: btmtksdio: move interrupt service to work") Signed-off-by: Sean Wang Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmtksdio.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 491f029452ca8..8be763ab3bf49 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -92,6 +92,7 @@ MODULE_DEVICE_TABLE(sdio, btmtksdio_table); #define TX_EMPTY BIT(2) #define TX_FIFO_OVERFLOW BIT(8) #define FW_MAILBOX_INT BIT(15) +#define INT_MASK GENMASK(15, 0) #define RX_PKT_LEN GENMASK(31, 16) #define MTK_REG_CSICR 0xc0 @@ -565,6 +566,7 @@ static void btmtksdio_txrx_work(struct work_struct *work) * FIFO. */ sdio_writel(bdev->func, int_status, MTK_REG_CHISR, NULL); + int_status &= INT_MASK; if ((int_status & FW_MAILBOX_INT) && bdev->data->chipid == 0x7921) { From 5201d23cc8e57531e0b17e41c0ae10405ba6abd3 Mon Sep 17 00:00:00 2001 From: Soenke Huster Date: Sun, 23 Jan 2022 06:57:09 +0100 Subject: [PATCH 23/30] Bluetooth: msft: fix null pointer deref on msft_monitor_device_evt msft_find_handle_data returns NULL if it can't find the handle. Therefore, handle_data must be checked, otherwise a null pointer is dereferenced. Signed-off-by: Soenke Huster Signed-off-by: Marcel Holtmann --- net/bluetooth/msft.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c index 4845408558636..9a3d77d3ca868 100644 --- a/net/bluetooth/msft.c +++ b/net/bluetooth/msft.c @@ -704,6 +704,8 @@ static void msft_monitor_device_evt(struct hci_dev *hdev, struct sk_buff *skb) ev->monitor_state, &ev->bdaddr); handle_data = msft_find_handle_data(hdev, ev->monitor_handle, false); + if (!handle_data) + return; switch (ev->addr_type) { case ADDR_LE_DEV_PUBLIC: From d5ebaa7c5f6f688959e8d40840b2249ede63b8ed Mon Sep 17 00:00:00 2001 From: Soenke Huster Date: Sun, 23 Jan 2022 15:06:24 +0100 Subject: [PATCH 24/30] Bluetooth: hci_event: Ignore multiple conn complete events When one of the three connection complete events is received multiple times for the same handle, the device is registered multiple times which leads to memory corruptions. Therefore, consequent events for a single connection are ignored. The conn->state can hold different values, therefore HCI_CONN_HANDLE_UNSET is introduced to identify new connections. To make sure the events do not contain this or another invalid handle HCI_CONN_HANDLE_MAX and checks are introduced. Buglink: https://bugzilla.kernel.org/show_bug.cgi?id=215497 Signed-off-by: Soenke Huster Signed-off-by: Luiz Augusto von Dentz --- include/net/bluetooth/hci_core.h | 3 ++ net/bluetooth/hci_conn.c | 1 + net/bluetooth/hci_event.c | 63 ++++++++++++++++++++++++-------- 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 21eadb113a31a..f5caff1ddb297 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -303,6 +303,9 @@ struct adv_monitor { #define HCI_MAX_SHORT_NAME_LENGTH 10 +#define HCI_CONN_HANDLE_UNSET 0xffff +#define HCI_CONN_HANDLE_MAX 0x0eff + /* Min encryption key size to match with SMP */ #define HCI_MIN_ENC_KEY_SIZE 7 diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 04ebe901e86f0..d106511080337 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -689,6 +689,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst, bacpy(&conn->dst, dst); bacpy(&conn->src, &hdev->bdaddr); + conn->handle = HCI_CONN_HANDLE_UNSET; conn->hdev = hdev; conn->type = type; conn->role = role; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 681c623aa3806..664ccf1d8d93a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3068,6 +3068,11 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, struct hci_ev_conn_complete *ev = data; struct hci_conn *conn; + if (__le16_to_cpu(ev->handle) > HCI_CONN_HANDLE_MAX) { + bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for invalid handle"); + return; + } + bt_dev_dbg(hdev, "status 0x%2.2x", ev->status); hci_dev_lock(hdev); @@ -3106,6 +3111,17 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, void *data, } } + /* The HCI_Connection_Complete event is only sent once per connection. + * Processing it more than once per connection can corrupt kernel memory. + * + * As the connection handle is set here for the first time, it indicates + * whether the connection is already set up. + */ + if (conn->handle != HCI_CONN_HANDLE_UNSET) { + bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for existing connection"); + goto unlock; + } + if (!ev->status) { conn->handle = __le16_to_cpu(ev->handle); @@ -4674,6 +4690,11 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, void *data, return; } + if (__le16_to_cpu(ev->handle) > HCI_CONN_HANDLE_MAX) { + bt_dev_err(hdev, "Ignoring HCI_Sync_Conn_Complete for invalid handle"); + return; + } + bt_dev_dbg(hdev, "status 0x%2.2x", ev->status); hci_dev_lock(hdev); @@ -4697,23 +4718,19 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, void *data, goto unlock; } + /* The HCI_Synchronous_Connection_Complete event is only sent once per connection. + * Processing it more than once per connection can corrupt kernel memory. + * + * As the connection handle is set here for the first time, it indicates + * whether the connection is already set up. + */ + if (conn->handle != HCI_CONN_HANDLE_UNSET) { + bt_dev_err(hdev, "Ignoring HCI_Sync_Conn_Complete event for existing connection"); + goto unlock; + } + switch (ev->status) { case 0x00: - /* The synchronous connection complete event should only be - * sent once per new connection. Receiving a successful - * complete event when the connection status is already - * BT_CONNECTED means that the device is misbehaving and sent - * multiple complete event packets for the same new connection. - * - * Registering the device more than once can corrupt kernel - * memory, hence upon detecting this invalid event, we report - * an error and ignore the packet. - */ - if (conn->state == BT_CONNECTED) { - bt_dev_err(hdev, "Ignoring connect complete event for existing connection"); - goto unlock; - } - conn->handle = __le16_to_cpu(ev->handle); conn->state = BT_CONNECTED; conn->type = ev->link_type; @@ -5509,6 +5526,11 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, struct smp_irk *irk; u8 addr_type; + if (handle > HCI_CONN_HANDLE_MAX) { + bt_dev_err(hdev, "Ignoring HCI_LE_Connection_Complete for invalid handle"); + return; + } + hci_dev_lock(hdev); /* All controllers implicitly stop advertising in the event of a @@ -5550,6 +5572,17 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 status, cancel_delayed_work(&conn->le_conn_timeout); } + /* The HCI_LE_Connection_Complete event is only sent once per connection. + * Processing it more than once per connection can corrupt kernel memory. + * + * As the connection handle is set here for the first time, it indicates + * whether the connection is already set up. + */ + if (conn->handle != HCI_CONN_HANDLE_UNSET) { + bt_dev_err(hdev, "Ignoring HCI_Connection_Complete for existing connection"); + goto unlock; + } + le_conn_update_addr(conn, bdaddr, bdaddr_type, local_rpa); /* Lookup the identity address from the stored connection From 2d4b37b67cacbbad6fdb8621333f5ce48ae0e5fd Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 25 Jan 2022 11:15:37 -0800 Subject: [PATCH 25/30] Bluetooth: hci_core: Rate limit the logging of invalid SCO handle The invalid SCO handle error is normally caused by a race in the USB transport where the data and event happen to be 2 different endpoints so the event carrying the SCO handle is processed after its data. Note: This can probably be resolved with use of force_poll_sync debugfs. Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 14c2da9d33ff4..5bde0ec411771 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3667,8 +3667,8 @@ static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) sco_recv_scodata(conn, skb); return; } else { - bt_dev_err(hdev, "SCO packet for unknown connection handle %d", - handle); + bt_dev_err_ratelimited(hdev, "SCO packet for unknown connection handle %d", + handle); } kfree_skb(skb); From 314d8cd2787418c5ac6b02035c344644f47b292b Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Tue, 25 Jan 2022 10:53:05 -0800 Subject: [PATCH 26/30] Bluetooth: hci_event: Fix HCI_EV_VENDOR max_len HCI_EV_VENDOR is in fact variable length since it acts as metaevent where a vendor can implement their own event sets. In addition to it this makes use of bt_dev_warn_ratelimited to supress the amount of logging in case the event has more data than expected. Fixes: 3e54c5890c87 ("Bluetooth: hci_event: Use of a function table to handle HCI event") Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 664ccf1d8d93a..63b925921c87b 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -6844,7 +6844,7 @@ static const struct hci_ev { HCI_EV(HCI_EV_NUM_COMP_BLOCKS, hci_num_comp_blocks_evt, sizeof(struct hci_ev_num_comp_blocks)), /* [0xff = HCI_EV_VENDOR] */ - HCI_EV(HCI_EV_VENDOR, msft_vendor_evt, 0), + HCI_EV_VL(HCI_EV_VENDOR, msft_vendor_evt, 0, HCI_MAX_EVENT_SIZE), }; static void hci_event_func(struct hci_dev *hdev, u8 event, struct sk_buff *skb, @@ -6869,8 +6869,9 @@ static void hci_event_func(struct hci_dev *hdev, u8 event, struct sk_buff *skb, * decide if that is acceptable. */ if (skb->len > ev->max_len) - bt_dev_warn(hdev, "unexpected event 0x%2.2x length: %u > %u", - event, skb->len, ev->max_len); + bt_dev_warn_ratelimited(hdev, + "unexpected event 0x%2.2x length: %u > %u", + event, skb->len, ev->max_len); data = hci_ev_skb_pull(hdev, skb, event, ev->min_len); if (!data) From b050c5bbbccfb9e6cbf29c8ee7a41c1bba972bdf Mon Sep 17 00:00:00 2001 From: Vyacheslav Bocharov Date: Wed, 26 Jan 2022 10:39:04 +0300 Subject: [PATCH 27/30] Bluetooth: btrtl: Add support for RTL8822C hci_ver 0x08 Add a variation of RTL8822CS with hci_ver = 0x08. This is fully similar to RTL8822CS with hci_ver = 0x0a observed on the Tanix TX6 Android set-top box and JetHome JetHub H1. Signed-off-by: Vyacheslav Bocharov Signed-off-by: Rudi Heitbaum Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btrtl.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c index c2bdd1e6060e8..c2030f7e25b40 100644 --- a/drivers/bluetooth/btrtl.c +++ b/drivers/bluetooth/btrtl.c @@ -148,6 +148,14 @@ static const struct id_table ic_id_table[] = { .fw_name = "rtl_bt/rtl8761bu_fw.bin", .cfg_name = "rtl_bt/rtl8761bu_config" }, + /* 8822C with UART interface */ + { IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0x8, HCI_UART), + .config_needed = true, + .has_rom_version = true, + .has_msft_ext = true, + .fw_name = "rtl_bt/rtl8822cs_fw.bin", + .cfg_name = "rtl_bt/rtl8822cs_config" }, + /* 8822C with UART interface */ { IC_INFO(RTL_ROM_LMP_8822B, 0xc, 0xa, HCI_UART), .config_needed = true, From adce573b927adf827f2f8627f05c2ba90031ebc9 Mon Sep 17 00:00:00 2001 From: Vyacheslav Bocharov Date: Wed, 26 Jan 2022 10:39:05 +0300 Subject: [PATCH 28/30] Bluetooth: hci_h5: Add power reset via gpio in h5_btrtl_open Add power reset for bluetooth via enable-gpios in h5_btrtl_open function. While testing the RTL8822CS SDIO WiFi/BT adapter, it was found that in some cases the kernel could not initialize BT firmware. However, manually resetting the adapter via gpio (off/on sequence) allows it to start correctly. Apparently, when the system starts, the adapter is in an undefined state (including unknown gpio state after starting uboot). A forced reset helps to initialize the adapter in most cases. It has been found experimentally that 100 ms is sufficient for a reset. Signed-off-by: Vyacheslav Bocharov Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_h5.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 34286ffe0568f..fdf504b0d265d 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -966,6 +966,11 @@ static void h5_btrtl_open(struct h5 *h5) pm_runtime_enable(&h5->hu->serdev->dev); } + /* The controller needs reset to startup */ + gpiod_set_value_cansleep(h5->enable_gpio, 0); + gpiod_set_value_cansleep(h5->device_wake_gpio, 0); + msleep(100); + /* The controller needs up to 500ms to wakeup */ gpiod_set_value_cansleep(h5->enable_gpio, 1); gpiod_set_value_cansleep(h5->device_wake_gpio, 1); From 0b94f2651f56b9e4aa5f012b0d7eb57308c773cf Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Wed, 26 Jan 2022 17:21:00 -0800 Subject: [PATCH 29/30] Bluetooth: hci_sync: Fix queuing commands when HCI_UNREGISTER is set hci_cmd_sync_queue shall return an error if HCI_UNREGISTER flag has been set as that means hci_unregister_dev has been called so it will likely cause a uaf after the timeout as the hdev will be freed. Signed-off-by: Luiz Augusto von Dentz Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_sync.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c index 2fe8c60dc62bc..6e71aa6b6feae 100644 --- a/net/bluetooth/hci_sync.c +++ b/net/bluetooth/hci_sync.c @@ -382,6 +382,9 @@ int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func, { struct hci_cmd_sync_work_entry *entry; + if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) + return -ENODEV; + entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; From 91cb4c19118a19470a9d7d6dbdf64763bbbadcde Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 26 Jan 2022 18:30:12 +0100 Subject: [PATCH 30/30] Bluetooth: Increment management interface revision Increment the mgmt revision due to recent changes. Signed-off-by: Marcel Holtmann Signed-off-by: Luiz Augusto von Dentz --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 08d6494f1b34e..5dd684e0b2592 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -42,7 +42,7 @@ #include "aosp.h" #define MGMT_VERSION 1 -#define MGMT_REVISION 21 +#define MGMT_REVISION 22 static const u16 mgmt_commands[] = { MGMT_OP_READ_INDEX_LIST,