Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PW_SID:550611] [v3] bluetooth: Fix Advertisement Monitor Suspend/Resume #512

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: CI

on: [pull_request]

jobs:
ci:
runs-on: ubuntu-latest
name: CI for Pull Request
steps:
- name: Checkout the source code
uses: actions/checkout@v2
with:
path: src

- name: Checkout the BlueZ source code
uses: actions/checkout@v2
with:
repository: BluezTestBot/bluez
path: bluez

- name: Create output folder
run: |
mkdir results

- name: CI
uses: BluezTestBot/action-kernel-ci@main
with:
src_path: src
bluez_path: bluez
output_path: results
github_token: ${{ secrets.GITHUB_TOKEN }}
email_token: ${{ secrets.EMAIL_TOKEN }}
patchwork_token: ${{ secrets.PATCHWORK_TOKEN }}

- name: Upload results
uses: actions/upload-artifact@v2
with:
name: tester-logs
path: results/
if-no-files-found: warn
35 changes: 35 additions & 0 deletions .github/workflows/schedule_work.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Scheduled Work

on:
schedule:
- cron: "20 * * * *"

jobs:
sync_repo:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Sync Repo
uses: BluezTestBot/action-manage-repo@master
with:
src_repo: "bluez/bluetooth-next"
for_upstream_branch: 'for-upstream'
workflow_branch: 'workflow'
github_token: ${{ secrets.GITHUB_TOKEN }}

sync_patchwork:
needs: sync_repo
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Sync Patchwork
uses: BluezTestBot/action-patchwork-to-pr@master
with:
pw_exclude_str: 'BlueZ'
base_branch: 'workflow'
github_token: ${{ secrets.ACTION_TOKEN }}
15 changes: 9 additions & 6 deletions net/bluetooth/hci_request.c
Original file line number Diff line number Diff line change
Expand Up @@ -1105,21 +1105,24 @@ static void suspend_req_complete(struct hci_dev *hdev, u8 status, u16 opcode)
}
}

static void hci_req_add_set_adv_filter_enable(struct hci_request *req,
bool enable)
static void hci_req_prepare_adv_monitor_suspend(struct hci_request *req,
bool suspending)
{
struct hci_dev *hdev = req->hdev;

switch (hci_get_adv_monitor_offload_ext(hdev)) {
case HCI_ADV_MONITOR_EXT_MSFT:
msft_req_add_set_filter_enable(req, enable);
if (suspending)
msft_suspend(hdev);
else
msft_resume(hdev);
break;
default:
return;
}

/* No need to block when enabling since it's on resume path */
if (hdev->suspended && !enable)
if (hdev->suspended && suspending)
set_bit(SUSPEND_SET_ADV_FILTER, hdev->suspend_tasks);
}

Expand Down Expand Up @@ -1186,7 +1189,7 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
}

/* Disable advertisement filters */
hci_req_add_set_adv_filter_enable(&req, false);
hci_req_prepare_adv_monitor_suspend(&req, true);

/* Prevent disconnects from causing scanning to be re-enabled */
hdev->scanning_paused = true;
Expand Down Expand Up @@ -1228,7 +1231,7 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
/* Reset passive/background scanning to normal */
__hci_update_background_scan(&req);
/* Enable all of the advertisement filters */
hci_req_add_set_adv_filter_enable(&req, true);
hci_req_prepare_adv_monitor_suspend(&req, false);

/* Unpause directed advertising */
hdev->advertising_paused = false;
Expand Down
117 changes: 102 additions & 15 deletions net/bluetooth/msft.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,14 @@ struct msft_data {
__u16 pending_add_handle;
__u16 pending_remove_handle;
__u8 reregistering;
__u8 suspending;
__u8 filter_enabled;
};

static int __msft_add_monitor_pattern(struct hci_dev *hdev,
struct adv_monitor *monitor);
static int __msft_remove_monitor(struct hci_dev *hdev,
struct adv_monitor *monitor, u16 handle);

bool msft_monitor_supported(struct hci_dev *hdev)
{
Expand Down Expand Up @@ -154,7 +157,7 @@ static bool read_supported_features(struct hci_dev *hdev,
}

/* This function requires the caller holds hdev->lock */
static void reregister_monitor_on_restart(struct hci_dev *hdev, int handle)
static void reregister_monitor(struct hci_dev *hdev, int handle)
{
struct adv_monitor *monitor;
struct msft_data *msft = hdev->msft_data;
Expand Down Expand Up @@ -182,6 +185,69 @@ static void reregister_monitor_on_restart(struct hci_dev *hdev, int handle)
}
}

/* This function requires the caller holds hdev->lock */
static void remove_monitor_on_suspend(struct hci_dev *hdev, int handle)
{
struct adv_monitor *monitor;
struct msft_data *msft = hdev->msft_data;
int err;

while (1) {
monitor = idr_get_next(&hdev->adv_monitors_idr, &handle);
if (!monitor) {
/* All monitors have been removed */
msft->suspending = false;
hci_update_background_scan(hdev);
return;
}

msft->pending_remove_handle = (u16)handle;
err = __msft_remove_monitor(hdev, monitor, handle);

/* If success, return and wait for monitor removed callback */
if (!err)
return;

/* Otherwise free the monitor and keep removing */
hci_free_adv_monitor(hdev, monitor);
handle++;
}
}

/* This function requires the caller holds hdev->lock */
void msft_suspend(struct hci_dev *hdev)
{
struct msft_data *msft = hdev->msft_data;

if (!msft)
return;

if (msft_monitor_supported(hdev)) {
msft->suspending = true;
/* Quitely remove all monitors on suspend to avoid waking up
* the system.
*/
remove_monitor_on_suspend(hdev, 0);
}
}

/* This function requires the caller holds hdev->lock */
void msft_resume(struct hci_dev *hdev)
{
struct msft_data *msft = hdev->msft_data;

if (!msft)
return;

if (msft_monitor_supported(hdev)) {
msft->reregistering = true;
/* Monitors are removed on suspend, so we need to add all
* monitors on resume.
*/
reregister_monitor(hdev, 0);
}
}

void msft_do_open(struct hci_dev *hdev)
{
struct msft_data *msft = hdev->msft_data;
Expand Down Expand Up @@ -214,7 +280,7 @@ void msft_do_open(struct hci_dev *hdev)
/* Monitors get removed on power off, so we need to explicitly
* tell the controller to re-monitor.
*/
reregister_monitor_on_restart(hdev, 0);
reregister_monitor(hdev, 0);
}
}

Expand Down Expand Up @@ -382,8 +448,7 @@ static void msft_le_monitor_advertisement_cb(struct hci_dev *hdev,

/* If in restart/reregister sequence, keep registering. */
if (msft->reregistering)
reregister_monitor_on_restart(hdev,
msft->pending_add_handle + 1);
reregister_monitor(hdev, msft->pending_add_handle + 1);

hci_dev_unlock(hdev);

Expand Down Expand Up @@ -420,13 +485,25 @@ static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
if (handle_data) {
monitor = idr_find(&hdev->adv_monitors_idr,
handle_data->mgmt_handle);
if (monitor)

if (monitor && monitor->state == ADV_MONITOR_STATE_OFFLOADED)
monitor->state = ADV_MONITOR_STATE_REGISTERED;

/* Do not free the monitor if it is being removed due to
* suspend. It will be re-monitored on resume.
*/
if (monitor && !msft->suspending)
hci_free_adv_monitor(hdev, monitor);

list_del(&handle_data->list);
kfree(handle_data);
}

/* If in suspend/remove sequence, keep removing. */
if (msft->suspending)
remove_monitor_on_suspend(hdev,
msft->pending_remove_handle + 1);

/* If remove all monitors is required, we need to continue the process
* here because the earlier it was paused when waiting for the
* response from controller.
Expand All @@ -445,7 +522,8 @@ static void msft_le_cancel_monitor_advertisement_cb(struct hci_dev *hdev,
hci_dev_unlock(hdev);

done:
hci_remove_adv_monitor_complete(hdev, status);
if (!msft->suspending)
hci_remove_adv_monitor_complete(hdev, status);
}

static void msft_le_set_advertisement_filter_enable_cb(struct hci_dev *hdev,
Expand Down Expand Up @@ -578,28 +656,22 @@ int msft_add_monitor_pattern(struct hci_dev *hdev, struct adv_monitor *monitor)
if (!msft)
return -EOPNOTSUPP;

if (msft->reregistering)
if (msft->reregistering || msft->suspending)
return -EBUSY;

return __msft_add_monitor_pattern(hdev, monitor);
}

/* This function requires the caller holds hdev->lock */
int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
u16 handle)
static int __msft_remove_monitor(struct hci_dev *hdev,
struct adv_monitor *monitor, u16 handle)
{
struct msft_cp_le_cancel_monitor_advertisement cp;
struct msft_monitor_advertisement_handle_data *handle_data;
struct hci_request req;
struct msft_data *msft = hdev->msft_data;
int err = 0;

if (!msft)
return -EOPNOTSUPP;

if (msft->reregistering)
return -EBUSY;

handle_data = msft_find_handle_data(hdev, monitor->handle, true);

/* If no matched handle, just remove without telling controller */
Expand All @@ -619,6 +691,21 @@ int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
return err;
}

/* This function requires the caller holds hdev->lock */
int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
u16 handle)
{
struct msft_data *msft = hdev->msft_data;

if (!msft)
return -EOPNOTSUPP;

if (msft->reregistering || msft->suspending)
return -EBUSY;

return __msft_remove_monitor(hdev, monitor, handle);
}

void msft_req_add_set_filter_enable(struct hci_request *req, bool enable)
{
struct hci_dev *hdev = req->hdev;
Expand Down
5 changes: 5 additions & 0 deletions net/bluetooth/msft.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
u16 handle);
void msft_req_add_set_filter_enable(struct hci_request *req, bool enable);
int msft_set_filter_enable(struct hci_dev *hdev, bool enable);
void msft_suspend(struct hci_dev *hdev);
void msft_resume(struct hci_dev *hdev);
bool msft_curve_validity(struct hci_dev *hdev);

#else
Expand Down Expand Up @@ -59,6 +61,9 @@ static inline int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
return -EOPNOTSUPP;
}

void msft_suspend(struct hci_dev *hdev) {}
void msft_resume(struct hci_dev *hdev) {}

static inline bool msft_curve_validity(struct hci_dev *hdev)
{
return false;
Expand Down