-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add patch to fix Bluetooth LE advertisement stall (#2598)
On some platforms (it seems to be pronounced on Intel NUC systems) Bluetooth advertisements suddenly stop after a short while. Currently there are work arounds in place to restart the HCI controller to keep receiving the advertisements. Advertisements have been received fine with Linux 5.15. This change reverts a commit which has been isolated to be the culprit.
- Loading branch information
Showing
1 changed file
with
221 additions
and
0 deletions.
There are no files selected for viewing
221 changes: 221 additions & 0 deletions
221
...ot-external/patches/linux/0001-Revert-Bluetooth-Rework-le_scan_restart-for-hci_sync.patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
From 013a0ae9045de9e25b2f51ff56785e7fbce88626 Mon Sep 17 00:00:00 2001 | ||
Message-ID: <013a0ae9045de9e25b2f51ff56785e7fbce88626.1686815046.git.stefan@agner.ch> | ||
From: Stefan Agner <[email protected]> | ||
Date: Thu, 15 Jun 2023 09:43:59 +0200 | ||
Subject: [PATCH] Revert "Bluetooth: Rework le_scan_restart for hci_sync" | ||
|
||
This reverts commit 27d54b778ad1fb32c2c108cfe97e861c3909a46f. | ||
--- | ||
net/bluetooth/hci_request.c | 88 +++++++++++++++++++++++++++++++++++++ | ||
net/bluetooth/hci_sync.c | 75 ------------------------------- | ||
2 files changed, 88 insertions(+), 75 deletions(-) | ||
|
||
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c | ||
index f7e006a36382..43178a21ea7e 100644 | ||
--- a/net/bluetooth/hci_request.c | ||
+++ b/net/bluetooth/hci_request.c | ||
@@ -909,8 +909,95 @@ static void set_random_addr(struct hci_request *req, bdaddr_t *rpa) | ||
hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, rpa); | ||
} | ||
|
||
+static int le_scan_restart(struct hci_request *req, unsigned long opt) | ||
+{ | ||
+ struct hci_dev *hdev = req->hdev; | ||
+ | ||
+ /* If controller is not scanning we are done. */ | ||
+ if (!hci_dev_test_flag(hdev, HCI_LE_SCAN)) | ||
+ return 0; | ||
+ | ||
+ if (hdev->scanning_paused) { | ||
+ bt_dev_dbg(hdev, "Scanning is paused for suspend"); | ||
+ return 0; | ||
+ } | ||
+ | ||
+ hci_req_add_le_scan_disable(req, false); | ||
+ | ||
+ if (use_ext_scan(hdev)) { | ||
+ struct hci_cp_le_set_ext_scan_enable ext_enable_cp; | ||
+ | ||
+ memset(&ext_enable_cp, 0, sizeof(ext_enable_cp)); | ||
+ ext_enable_cp.enable = LE_SCAN_ENABLE; | ||
+ ext_enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE; | ||
+ | ||
+ hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_ENABLE, | ||
+ sizeof(ext_enable_cp), &ext_enable_cp); | ||
+ } else { | ||
+ struct hci_cp_le_set_scan_enable cp; | ||
+ | ||
+ memset(&cp, 0, sizeof(cp)); | ||
+ cp.enable = LE_SCAN_ENABLE; | ||
+ cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE; | ||
+ hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); | ||
+ } | ||
+ | ||
+ return 0; | ||
+} | ||
+ | ||
+static void le_scan_restart_work(struct work_struct *work) | ||
+{ | ||
+ struct hci_dev *hdev = container_of(work, struct hci_dev, | ||
+ le_scan_restart.work); | ||
+ unsigned long timeout, duration, scan_start, now; | ||
+ u8 status; | ||
+ | ||
+ bt_dev_dbg(hdev, ""); | ||
+ | ||
+ hci_req_sync(hdev, le_scan_restart, 0, HCI_CMD_TIMEOUT, &status); | ||
+ if (status) { | ||
+ bt_dev_err(hdev, "failed to restart LE scan: status %d", | ||
+ status); | ||
+ return; | ||
+ } | ||
+ | ||
+ hci_dev_lock(hdev); | ||
+ | ||
+ if (!test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) || | ||
+ !hdev->discovery.scan_start) | ||
+ goto unlock; | ||
+ | ||
+ /* When the scan was started, hdev->le_scan_disable has been queued | ||
+ * after duration from scan_start. During scan restart this job | ||
+ * has been canceled, and we need to queue it again after proper | ||
+ * timeout, to make sure that scan does not run indefinitely. | ||
+ */ | ||
+ duration = hdev->discovery.scan_duration; | ||
+ scan_start = hdev->discovery.scan_start; | ||
+ now = jiffies; | ||
+ if (now - scan_start <= duration) { | ||
+ int elapsed; | ||
+ | ||
+ if (now >= scan_start) | ||
+ elapsed = now - scan_start; | ||
+ else | ||
+ elapsed = ULONG_MAX - scan_start + now; | ||
+ | ||
+ timeout = duration - elapsed; | ||
+ } else { | ||
+ timeout = 0; | ||
+ } | ||
+ | ||
+ queue_delayed_work(hdev->req_workqueue, | ||
+ &hdev->le_scan_disable, timeout); | ||
+ | ||
+unlock: | ||
+ hci_dev_unlock(hdev); | ||
+} | ||
+ | ||
void hci_request_setup(struct hci_dev *hdev) | ||
{ | ||
+ INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work); | ||
INIT_DELAYED_WORK(&hdev->interleave_scan, interleave_scan_work); | ||
} | ||
|
||
@@ -919,4 +1006,5 @@ void hci_request_cancel_all(struct hci_dev *hdev) | ||
__hci_cmd_sync_cancel(hdev, ENODEV); | ||
|
||
cancel_interleave_scan(hdev); | ||
+ cancel_delayed_work_sync(&hdev->le_scan_restart); | ||
} | ||
diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c | ||
index 3eec688a88a9..34f29d83b7ff 100644 | ||
--- a/net/bluetooth/hci_sync.c | ||
+++ b/net/bluetooth/hci_sync.c | ||
@@ -393,79 +393,6 @@ static void le_scan_disable(struct work_struct *work) | ||
hci_dev_unlock(hdev); | ||
} | ||
|
||
-static int hci_le_set_scan_enable_sync(struct hci_dev *hdev, u8 val, | ||
- u8 filter_dup); | ||
-static int hci_le_scan_restart_sync(struct hci_dev *hdev) | ||
-{ | ||
- /* If controller is not scanning we are done. */ | ||
- if (!hci_dev_test_flag(hdev, HCI_LE_SCAN)) | ||
- return 0; | ||
- | ||
- if (hdev->scanning_paused) { | ||
- bt_dev_dbg(hdev, "Scanning is paused for suspend"); | ||
- return 0; | ||
- } | ||
- | ||
- hci_le_set_scan_enable_sync(hdev, LE_SCAN_DISABLE, 0x00); | ||
- return hci_le_set_scan_enable_sync(hdev, LE_SCAN_ENABLE, | ||
- LE_SCAN_FILTER_DUP_ENABLE); | ||
-} | ||
- | ||
-static int le_scan_restart_sync(struct hci_dev *hdev, void *data) | ||
-{ | ||
- return hci_le_scan_restart_sync(hdev); | ||
-} | ||
- | ||
-static void le_scan_restart(struct work_struct *work) | ||
-{ | ||
- struct hci_dev *hdev = container_of(work, struct hci_dev, | ||
- le_scan_restart.work); | ||
- unsigned long timeout, duration, scan_start, now; | ||
- int status; | ||
- | ||
- bt_dev_dbg(hdev, ""); | ||
- | ||
- hci_dev_lock(hdev); | ||
- | ||
- status = hci_cmd_sync_queue(hdev, le_scan_restart_sync, NULL, NULL); | ||
- if (status) { | ||
- bt_dev_err(hdev, "failed to restart LE scan: status %d", | ||
- status); | ||
- goto unlock; | ||
- } | ||
- | ||
- if (!test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) || | ||
- !hdev->discovery.scan_start) | ||
- goto unlock; | ||
- | ||
- /* When the scan was started, hdev->le_scan_disable has been queued | ||
- * after duration from scan_start. During scan restart this job | ||
- * has been canceled, and we need to queue it again after proper | ||
- * timeout, to make sure that scan does not run indefinitely. | ||
- */ | ||
- duration = hdev->discovery.scan_duration; | ||
- scan_start = hdev->discovery.scan_start; | ||
- now = jiffies; | ||
- if (now - scan_start <= duration) { | ||
- int elapsed; | ||
- | ||
- if (now >= scan_start) | ||
- elapsed = now - scan_start; | ||
- else | ||
- elapsed = ULONG_MAX - scan_start + now; | ||
- | ||
- timeout = duration - elapsed; | ||
- } else { | ||
- timeout = 0; | ||
- } | ||
- | ||
- queue_delayed_work(hdev->req_workqueue, | ||
- &hdev->le_scan_disable, timeout); | ||
- | ||
-unlock: | ||
- hci_dev_unlock(hdev); | ||
-} | ||
- | ||
static int reenable_adv_sync(struct hci_dev *hdev, void *data) | ||
{ | ||
bt_dev_dbg(hdev, ""); | ||
@@ -632,7 +559,6 @@ void hci_cmd_sync_init(struct hci_dev *hdev) | ||
INIT_WORK(&hdev->cmd_sync_cancel_work, hci_cmd_sync_cancel_work); | ||
INIT_WORK(&hdev->reenable_adv_work, reenable_adv); | ||
INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable); | ||
- INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart); | ||
INIT_DELAYED_WORK(&hdev->adv_instance_expire, adv_timeout_expire); | ||
} | ||
|
||
@@ -4771,7 +4697,6 @@ int hci_dev_close_sync(struct hci_dev *hdev) | ||
cancel_delayed_work(&hdev->power_off); | ||
cancel_delayed_work(&hdev->ncmd_timer); | ||
cancel_delayed_work(&hdev->le_scan_disable); | ||
- cancel_delayed_work(&hdev->le_scan_restart); | ||
|
||
hci_request_cancel_all(hdev); | ||
|
||
-- | ||
2.41.0 | ||
|