Bluetooth: Pause discovery and advertising during suspend

To prevent spurious wake ups, we disable any discovery or advertising
when we enter suspend and restore it when we exit suspend. While paused,
we disable any management requests to modify discovery or advertising.

Signed-off-by: Abhishek Pandit-Subedi <abhishekpandit@chromium.org>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
Abhishek Pandit-Subedi 2020-03-11 08:54:03 -07:00 committed by Marcel Holtmann
parent dd522a7429
commit 4867bd007d
3 changed files with 96 additions and 0 deletions

View file

@ -1021,6 +1021,7 @@ static void suspend_req_complete(struct hci_dev *hdev, u8 status, u16 opcode)
/* Call with hci_dev_lock */
void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
{
int old_state;
struct hci_conn *conn;
struct hci_request req;
u8 page_scan;
@ -1038,6 +1039,28 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
/* Mark device as suspended */
hdev->suspended = true;
/* Pause discovery if not already stopped */
old_state = hdev->discovery.state;
if (old_state != DISCOVERY_STOPPED) {
set_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks);
hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
queue_work(hdev->req_workqueue, &hdev->discov_update);
}
hdev->discovery_paused = true;
hdev->discovery_old_state = old_state;
/* Stop advertising */
old_state = hci_dev_test_flag(hdev, HCI_ADVERTISING);
if (old_state) {
set_bit(SUSPEND_PAUSE_ADVERTISING, hdev->suspend_tasks);
cancel_delayed_work(&hdev->discov_off);
queue_delayed_work(hdev->req_workqueue,
&hdev->discov_off, 0);
}
hdev->advertising_paused = true;
hdev->advertising_old_state = old_state;
/* Disable page scan */
page_scan = SCAN_DISABLED;
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &page_scan);
@ -1084,6 +1107,27 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
hci_req_clear_event_filter(&req);
/* Reset passive/background scanning to normal */
hci_req_config_le_suspend_scan(&req);
/* Unpause advertising */
hdev->advertising_paused = false;
if (hdev->advertising_old_state) {
set_bit(SUSPEND_UNPAUSE_ADVERTISING,
hdev->suspend_tasks);
hci_dev_set_flag(hdev, HCI_ADVERTISING);
queue_work(hdev->req_workqueue,
&hdev->discoverable_update);
hdev->advertising_old_state = 0;
}
/* Unpause discovery */
hdev->discovery_paused = false;
if (hdev->discovery_old_state != DISCOVERY_STOPPED &&
hdev->discovery_old_state != DISCOVERY_STOPPING) {
set_bit(SUSPEND_UNPAUSE_DISCOVERY, hdev->suspend_tasks);
hci_discovery_set_state(hdev, DISCOVERY_STARTING);
queue_work(hdev->req_workqueue, &hdev->discov_update);
}
hci_req_run(&req, suspend_req_complete);
}