Commit 182ee45d authored by Luiz Augusto von Dentz's avatar Luiz Augusto von Dentz Committed by Marcel Holtmann

Bluetooth: hci_sync: Rework hci_suspend_notifier

This makes hci_suspend_notifier use the hci_*_sync which can be
executed synchronously which is allowed in the suspend_notifier and
simplifies a lot of the handling since the status of each command can
be checked inline so no other work need to be scheduled thus can be
performed without using of a state machine.
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent d0b13706
...@@ -523,7 +523,6 @@ struct hci_dev { ...@@ -523,7 +523,6 @@ struct hci_dev {
bool advertising_paused; bool advertising_paused;
struct notifier_block suspend_notifier; struct notifier_block suspend_notifier;
struct work_struct suspend_prepare;
enum suspended_state suspend_state_next; enum suspended_state suspend_state_next;
enum suspended_state suspend_state; enum suspended_state suspend_state;
bool scanning_paused; bool scanning_paused;
...@@ -532,9 +531,6 @@ struct hci_dev { ...@@ -532,9 +531,6 @@ struct hci_dev {
bdaddr_t wake_addr; bdaddr_t wake_addr;
u8 wake_addr_type; u8 wake_addr_type;
wait_queue_head_t suspend_wait_q;
DECLARE_BITMAP(suspend_tasks, __SUSPEND_NUM_TASKS);
struct hci_conn_hash conn_hash; struct hci_conn_hash conn_hash;
struct list_head mgmt_pending; struct list_head mgmt_pending;
......
...@@ -92,3 +92,6 @@ int hci_set_powered_sync(struct hci_dev *hdev, u8 val); ...@@ -92,3 +92,6 @@ int hci_set_powered_sync(struct hci_dev *hdev, u8 val);
int hci_start_discovery_sync(struct hci_dev *hdev); int hci_start_discovery_sync(struct hci_dev *hdev);
int hci_stop_discovery_sync(struct hci_dev *hdev); int hci_stop_discovery_sync(struct hci_dev *hdev);
int hci_suspend_sync(struct hci_dev *hdev);
int hci_resume_sync(struct hci_dev *hdev);
...@@ -900,16 +900,6 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status) ...@@ -900,16 +900,6 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
hci_conn_del(conn); hci_conn_del(conn);
/* The suspend notifier is waiting for all devices to disconnect and an
* LE connect cancel will result in an hci_le_conn_failed. Once the last
* connection is deleted, we should also wake the suspend queue to
* complete suspend operations.
*/
if (list_empty(&hdev->conn_hash.list) &&
test_and_clear_bit(SUSPEND_DISCONNECTING, hdev->suspend_tasks)) {
wake_up(&hdev->suspend_wait_q);
}
/* Since we may have temporarily stopped the background scanning in /* Since we may have temporarily stopped the background scanning in
* favor of connection establishment, we should restart it. * favor of connection establishment, we should restart it.
*/ */
......
...@@ -2374,61 +2374,6 @@ void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr, ...@@ -2374,61 +2374,6 @@ void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
} }
} }
static void hci_suspend_clear_tasks(struct hci_dev *hdev)
{
int i;
for (i = 0; i < __SUSPEND_NUM_TASKS; i++)
clear_bit(i, hdev->suspend_tasks);
wake_up(&hdev->suspend_wait_q);
}
static int hci_suspend_wait_event(struct hci_dev *hdev)
{
#define WAKE_COND \
(find_first_bit(hdev->suspend_tasks, __SUSPEND_NUM_TASKS) == \
__SUSPEND_NUM_TASKS)
int i;
int ret = wait_event_timeout(hdev->suspend_wait_q,
WAKE_COND, SUSPEND_NOTIFIER_TIMEOUT);
if (ret == 0) {
bt_dev_err(hdev, "Timed out waiting for suspend events");
for (i = 0; i < __SUSPEND_NUM_TASKS; ++i) {
if (test_bit(i, hdev->suspend_tasks))
bt_dev_err(hdev, "Suspend timeout bit: %d", i);
clear_bit(i, hdev->suspend_tasks);
}
ret = -ETIMEDOUT;
} else {
ret = 0;
}
return ret;
}
static void hci_prepare_suspend(struct work_struct *work)
{
struct hci_dev *hdev =
container_of(work, struct hci_dev, suspend_prepare);
hci_dev_lock(hdev);
hci_req_prepare_suspend(hdev, hdev->suspend_state_next);
hci_dev_unlock(hdev);
}
static int hci_change_suspend_state(struct hci_dev *hdev,
enum suspended_state next)
{
hdev->suspend_state_next = next;
set_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks);
queue_work(hdev->req_workqueue, &hdev->suspend_prepare);
return hci_suspend_wait_event(hdev);
}
static void hci_clear_wake_reason(struct hci_dev *hdev) static void hci_clear_wake_reason(struct hci_dev *hdev)
{ {
hci_dev_lock(hdev); hci_dev_lock(hdev);
...@@ -2565,7 +2510,6 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv) ...@@ -2565,7 +2510,6 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
INIT_WORK(&hdev->tx_work, hci_tx_work); INIT_WORK(&hdev->tx_work, hci_tx_work);
INIT_WORK(&hdev->power_on, hci_power_on); INIT_WORK(&hdev->power_on, hci_power_on);
INIT_WORK(&hdev->error_reset, hci_error_reset); INIT_WORK(&hdev->error_reset, hci_error_reset);
INIT_WORK(&hdev->suspend_prepare, hci_prepare_suspend);
hci_cmd_sync_init(hdev); hci_cmd_sync_init(hdev);
...@@ -2576,7 +2520,6 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv) ...@@ -2576,7 +2520,6 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
skb_queue_head_init(&hdev->raw_q); skb_queue_head_init(&hdev->raw_q);
init_waitqueue_head(&hdev->req_wait_q); init_waitqueue_head(&hdev->req_wait_q);
init_waitqueue_head(&hdev->suspend_wait_q);
INIT_DELAYED_WORK(&hdev->cmd_timer, hci_cmd_timeout); INIT_DELAYED_WORK(&hdev->cmd_timer, hci_cmd_timeout);
INIT_DELAYED_WORK(&hdev->ncmd_timer, hci_ncmd_timeout); INIT_DELAYED_WORK(&hdev->ncmd_timer, hci_ncmd_timeout);
...@@ -2729,11 +2672,8 @@ void hci_unregister_dev(struct hci_dev *hdev) ...@@ -2729,11 +2672,8 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_cmd_sync_clear(hdev); hci_cmd_sync_clear(hdev);
if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks)) { if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks))
hci_suspend_clear_tasks(hdev);
unregister_pm_notifier(&hdev->suspend_notifier); unregister_pm_notifier(&hdev->suspend_notifier);
cancel_work_sync(&hdev->suspend_prepare);
}
msft_unregister(hdev); msft_unregister(hdev);
...@@ -2800,7 +2740,6 @@ EXPORT_SYMBOL(hci_release_dev); ...@@ -2800,7 +2740,6 @@ EXPORT_SYMBOL(hci_release_dev);
int hci_suspend_dev(struct hci_dev *hdev) int hci_suspend_dev(struct hci_dev *hdev)
{ {
int ret; int ret;
u8 state = BT_RUNNING;
bt_dev_dbg(hdev, ""); bt_dev_dbg(hdev, "");
...@@ -2809,40 +2748,17 @@ int hci_suspend_dev(struct hci_dev *hdev) ...@@ -2809,40 +2748,17 @@ int hci_suspend_dev(struct hci_dev *hdev)
hci_dev_test_flag(hdev, HCI_UNREGISTER)) hci_dev_test_flag(hdev, HCI_UNREGISTER))
return 0; return 0;
/* If powering down, wait for completion. */ /* If powering down don't attempt to suspend */
if (mgmt_powering_down(hdev)) { if (mgmt_powering_down(hdev))
set_bit(SUSPEND_POWERING_DOWN, hdev->suspend_tasks); return 0;
ret = hci_suspend_wait_event(hdev);
if (ret)
goto done;
}
/* Suspend consists of two actions:
* - First, disconnect everything and make the controller not
* connectable (disabling scanning)
* - Second, program event filter/accept list and enable scan
*/
ret = hci_change_suspend_state(hdev, BT_SUSPEND_DISCONNECT);
if (ret)
goto clear;
state = BT_SUSPEND_DISCONNECT;
/* Only configure accept list if device may wakeup. */ hci_req_sync_lock(hdev);
if (hdev->wakeup && hdev->wakeup(hdev)) { ret = hci_suspend_sync(hdev);
ret = hci_change_suspend_state(hdev, BT_SUSPEND_CONFIGURE_WAKE); hci_req_sync_unlock(hdev);
if (!ret)
state = BT_SUSPEND_CONFIGURE_WAKE;
}
clear:
hci_clear_wake_reason(hdev); hci_clear_wake_reason(hdev);
mgmt_suspending(hdev, state); mgmt_suspending(hdev, hdev->suspend_state);
done:
/* We always allow suspend even if suspend preparation failed and
* attempt to recover in resume.
*/
hci_sock_dev_event(hdev, HCI_DEV_SUSPEND); hci_sock_dev_event(hdev, HCI_DEV_SUSPEND);
return ret; return ret;
} }
...@@ -2864,10 +2780,12 @@ int hci_resume_dev(struct hci_dev *hdev) ...@@ -2864,10 +2780,12 @@ int hci_resume_dev(struct hci_dev *hdev)
if (mgmt_powering_down(hdev)) if (mgmt_powering_down(hdev))
return 0; return 0;
ret = hci_change_suspend_state(hdev, BT_RUNNING); hci_req_sync_lock(hdev);
ret = hci_resume_sync(hdev);
hci_req_sync_unlock(hdev);
mgmt_resuming(hdev, hdev->wake_reason, &hdev->wake_addr, mgmt_resuming(hdev, hdev->wake_reason, &hdev->wake_addr,
hdev->wake_addr_type); hdev->wake_addr_type);
hci_sock_dev_event(hdev, HCI_DEV_RESUME); hci_sock_dev_event(hdev, HCI_DEV_RESUME);
return ret; return ret;
......
...@@ -2414,9 +2414,14 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status) ...@@ -2414,9 +2414,14 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
static void hci_cs_disconnect(struct hci_dev *hdev, u8 status) static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
{ {
struct hci_cp_disconnect *cp; struct hci_cp_disconnect *cp;
struct hci_conn_params *params;
struct hci_conn *conn; struct hci_conn *conn;
bool mgmt_conn;
if (!status) /* Wait for HCI_EV_DISCONN_COMPLETE if status 0x00 and not suspended
* otherwise cleanup the connection immediately.
*/
if (!status && !hdev->suspended)
return; return;
cp = hci_sent_cmd_data(hdev, HCI_OP_DISCONNECT); cp = hci_sent_cmd_data(hdev, HCI_OP_DISCONNECT);
...@@ -2426,7 +2431,10 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status) ...@@ -2426,7 +2431,10 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
hci_dev_lock(hdev); hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
if (conn) { if (!conn)
goto unlock;
if (status) {
mgmt_disconnect_failed(hdev, &conn->dst, conn->type, mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
conn->dst_type, status); conn->dst_type, status);
...@@ -2435,14 +2443,48 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status) ...@@ -2435,14 +2443,48 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
hci_enable_advertising(hdev); hci_enable_advertising(hdev);
} }
/* If the disconnection failed for any reason, the upper layer goto done;
* does not retry to disconnect in current implementation.
* Hence, we need to do some basic cleanup here and re-enable
* advertising if necessary.
*/
hci_conn_del(conn);
} }
mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags);
if (conn->type == ACL_LINK) {
if (test_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
hci_remove_link_key(hdev, &conn->dst);
}
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
if (params) {
switch (params->auto_connect) {
case HCI_AUTO_CONN_LINK_LOSS:
if (cp->reason != HCI_ERROR_CONNECTION_TIMEOUT)
break;
fallthrough;
case HCI_AUTO_CONN_DIRECT:
case HCI_AUTO_CONN_ALWAYS:
list_del_init(&params->action);
list_add(&params->action, &hdev->pend_le_conns);
break;
default:
break;
}
}
mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type,
cp->reason, mgmt_conn);
hci_disconn_cfm(conn, cp->reason);
done:
/* If the disconnection failed for any reason, the upper layer
* does not retry to disconnect in current implementation.
* Hence, we need to do some basic cleanup here and re-enable
* advertising if necessary.
*/
hci_conn_del(conn);
unlock:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
...@@ -3047,14 +3089,6 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -3047,14 +3089,6 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_conn_del(conn); hci_conn_del(conn);
/* The suspend notifier is waiting for all devices to disconnect so
* clear the bit from pending tasks and inform the wait queue.
*/
if (list_empty(&hdev->conn_hash.list) &&
test_and_clear_bit(SUSPEND_DISCONNECTING, hdev->suspend_tasks)) {
wake_up(&hdev->suspend_wait_q);
}
unlock: unlock:
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
...@@ -5575,8 +5609,9 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev, ...@@ -5575,8 +5609,9 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
if (adv_type != LE_ADV_IND && adv_type != LE_ADV_DIRECT_IND) if (adv_type != LE_ADV_IND && adv_type != LE_ADV_DIRECT_IND)
return NULL; return NULL;
/* Ignore if the device is blocked */ /* Ignore if the device is blocked or hdev is suspended */
if (hci_bdaddr_list_lookup(&hdev->reject_list, addr, addr_type)) if (hci_bdaddr_list_lookup(&hdev->reject_list, addr, addr_type) ||
hdev->suspended)
return NULL; return NULL;
/* Most controller will fail if we try to create new connections /* Most controller will fail if we try to create new connections
......
...@@ -492,9 +492,6 @@ void hci_req_add_le_scan_disable(struct hci_request *req, bool rpa_le_conn) ...@@ -492,9 +492,6 @@ void hci_req_add_le_scan_disable(struct hci_request *req, bool rpa_le_conn)
return; return;
} }
if (hdev->suspended)
set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
if (use_ext_scan(hdev)) { if (use_ext_scan(hdev)) {
struct hci_cp_le_set_ext_scan_enable cp; struct hci_cp_le_set_ext_scan_enable cp;
...@@ -868,8 +865,6 @@ void hci_req_add_le_passive_scan(struct hci_request *req) ...@@ -868,8 +865,6 @@ void hci_req_add_le_passive_scan(struct hci_request *req)
if (hdev->suspended) { if (hdev->suspended) {
window = hdev->le_scan_window_suspend; window = hdev->le_scan_window_suspend;
interval = hdev->le_scan_int_suspend; interval = hdev->le_scan_int_suspend;
set_bit(SUSPEND_SCAN_ENABLE, hdev->suspend_tasks);
} else if (hci_is_le_conn_scanning(hdev)) { } else if (hci_is_le_conn_scanning(hdev)) {
window = hdev->le_scan_window_connect; window = hdev->le_scan_window_connect;
interval = hdev->le_scan_int_connect; interval = hdev->le_scan_int_connect;
...@@ -902,59 +897,6 @@ void hci_req_add_le_passive_scan(struct hci_request *req) ...@@ -902,59 +897,6 @@ void hci_req_add_le_passive_scan(struct hci_request *req)
addr_resolv); addr_resolv);
} }
static void hci_req_clear_event_filter(struct hci_request *req)
{
struct hci_cp_set_event_filter f;
if (!hci_dev_test_flag(req->hdev, HCI_BREDR_ENABLED))
return;
if (hci_dev_test_flag(req->hdev, HCI_EVENT_FILTER_CONFIGURED)) {
memset(&f, 0, sizeof(f));
f.flt_type = HCI_FLT_CLEAR_ALL;
hci_req_add(req, HCI_OP_SET_EVENT_FLT, 1, &f);
}
}
static void hci_req_set_event_filter(struct hci_request *req)
{
struct bdaddr_list_with_flags *b;
struct hci_cp_set_event_filter f;
struct hci_dev *hdev = req->hdev;
u8 scan = SCAN_DISABLED;
bool scanning = test_bit(HCI_PSCAN, &hdev->flags);
if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
return;
/* Always clear event filter when starting */
hci_req_clear_event_filter(req);
list_for_each_entry(b, &hdev->accept_list, list) {
if (!hci_conn_test_flag(HCI_CONN_FLAG_REMOTE_WAKEUP,
b->current_flags))
continue;
memset(&f, 0, sizeof(f));
bacpy(&f.addr_conn_flt.bdaddr, &b->bdaddr);
f.flt_type = HCI_FLT_CONN_SETUP;
f.cond_type = HCI_CONN_SETUP_ALLOW_BDADDR;
f.addr_conn_flt.auto_accept = HCI_CONN_SETUP_AUTO_ON;
bt_dev_dbg(hdev, "Adding event filters for %pMR", &b->bdaddr);
hci_req_add(req, HCI_OP_SET_EVENT_FLT, sizeof(f), &f);
scan = SCAN_PAGE;
}
if (scan && !scanning) {
set_bit(SUSPEND_SCAN_ENABLE, hdev->suspend_tasks);
hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
} else if (!scan && scanning) {
set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
}
}
static void cancel_adv_timeout(struct hci_dev *hdev) static void cancel_adv_timeout(struct hci_dev *hdev)
{ {
if (hdev->adv_instance_timeout) { if (hdev->adv_instance_timeout) {
...@@ -1013,185 +955,6 @@ int hci_req_resume_adv_instances(struct hci_dev *hdev) ...@@ -1013,185 +955,6 @@ int hci_req_resume_adv_instances(struct hci_dev *hdev)
return hci_req_run(&req, NULL); return hci_req_run(&req, NULL);
} }
static void suspend_req_complete(struct hci_dev *hdev, u8 status, u16 opcode)
{
bt_dev_dbg(hdev, "Request complete opcode=0x%x, status=0x%x", opcode,
status);
if (test_bit(SUSPEND_SCAN_ENABLE, hdev->suspend_tasks) ||
test_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks)) {
clear_bit(SUSPEND_SCAN_ENABLE, hdev->suspend_tasks);
clear_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
wake_up(&hdev->suspend_wait_q);
}
if (test_bit(SUSPEND_SET_ADV_FILTER, hdev->suspend_tasks)) {
clear_bit(SUSPEND_SET_ADV_FILTER, hdev->suspend_tasks);
wake_up(&hdev->suspend_wait_q);
}
}
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:
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 && suspending)
set_bit(SUSPEND_SET_ADV_FILTER, hdev->suspend_tasks);
}
/* 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;
int disconnect_counter;
if (next == hdev->suspend_state) {
bt_dev_dbg(hdev, "Same state before and after: %d", next);
goto done;
}
hdev->suspend_state = next;
hci_req_init(&req, hdev);
if (next == BT_SUSPEND_DISCONNECT) {
/* 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 directed 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);
}
/* Pause other advertisements */
if (hdev->adv_instance_cnt)
__hci_req_pause_adv_instances(&req);
hdev->advertising_paused = true;
hdev->advertising_old_state = old_state;
/* Disable page scan if enabled */
if (test_bit(HCI_PSCAN, &hdev->flags)) {
page_scan = SCAN_DISABLED;
hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1,
&page_scan);
set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
}
/* Disable LE passive scan if enabled */
if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
cancel_interleave_scan(hdev);
hci_req_add_le_scan_disable(&req, false);
}
/* Disable advertisement filters */
hci_req_prepare_adv_monitor_suspend(&req, true);
/* Prevent disconnects from causing scanning to be re-enabled */
hdev->scanning_paused = true;
/* Run commands before disconnecting */
hci_req_run(&req, suspend_req_complete);
disconnect_counter = 0;
/* Soft disconnect everything (power off) */
list_for_each_entry(conn, &hdev->conn_hash.list, list) {
hci_disconnect(conn, HCI_ERROR_REMOTE_POWER_OFF);
disconnect_counter++;
}
if (disconnect_counter > 0) {
bt_dev_dbg(hdev,
"Had %d disconnects. Will wait on them",
disconnect_counter);
set_bit(SUSPEND_DISCONNECTING, hdev->suspend_tasks);
}
} else if (next == BT_SUSPEND_CONFIGURE_WAKE) {
/* Unpause to take care of updating scanning params */
hdev->scanning_paused = false;
/* Enable event filter for paired devices */
hci_req_set_event_filter(&req);
/* Enable passive scan at lower duty cycle */
__hci_update_background_scan(&req);
/* Pause scan changes again. */
hdev->scanning_paused = true;
hci_req_run(&req, suspend_req_complete);
} else {
hdev->suspended = false;
hdev->scanning_paused = false;
/* Clear any event filters and restore scan state */
hci_req_clear_event_filter(&req);
__hci_req_update_scan(&req);
/* Reset passive/background scanning to normal */
__hci_update_background_scan(&req);
/* Enable all of the advertisement filters */
hci_req_prepare_adv_monitor_suspend(&req, false);
/* Unpause directed 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;
}
/* Resume other advertisements */
if (hdev->adv_instance_cnt)
__hci_req_resume_adv_instances(&req);
/* 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);
}
hdev->suspend_state = next;
done:
clear_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks);
wake_up(&hdev->suspend_wait_q);
}
static bool adv_cur_instance_is_scannable(struct hci_dev *hdev) static bool adv_cur_instance_is_scannable(struct hci_dev *hdev)
{ {
return hci_adv_instance_is_scannable(hdev, hdev->cur_adv_instance); return hci_adv_instance_is_scannable(hdev, hdev->cur_adv_instance);
......
This diff is collapsed.
...@@ -5171,13 +5171,6 @@ void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status) ...@@ -5171,13 +5171,6 @@ void mgmt_start_discovery_complete(struct hci_dev *hdev, u8 status)
} }
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
/* Handle suspend notifier */
if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY,
hdev->suspend_tasks)) {
bt_dev_dbg(hdev, "Unpaused discovery");
wake_up(&hdev->suspend_wait_q);
}
} }
static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type, static bool discovery_type_is_valid(struct hci_dev *hdev, uint8_t type,
...@@ -5217,14 +5210,7 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err) ...@@ -5217,14 +5210,7 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
cmd->param, 1); cmd->param, 1);
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
/* Handle suspend notifier */ hci_discovery_set_state(hdev, err ? DISCOVERY_STOPPED:
if (test_and_clear_bit(SUSPEND_UNPAUSE_DISCOVERY,
hdev->suspend_tasks)) {
bt_dev_dbg(hdev, "Unpaused discovery");
wake_up(&hdev->suspend_wait_q);
}
hci_discovery_set_state(hdev, err ? DISCOVERY_STOPPED :
DISCOVERY_FINDING); DISCOVERY_FINDING);
} }
...@@ -5446,12 +5432,6 @@ void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status) ...@@ -5446,12 +5432,6 @@ void mgmt_stop_discovery_complete(struct hci_dev *hdev, u8 status)
} }
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
/* Handle suspend notifier */
if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) {
bt_dev_dbg(hdev, "Paused discovery");
wake_up(&hdev->suspend_wait_q);
}
} }
static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err) static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
...@@ -5464,12 +5444,6 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err) ...@@ -5464,12 +5444,6 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
cmd->param, 1); cmd->param, 1);
mgmt_pending_free(cmd); mgmt_pending_free(cmd);
/* Handle suspend notifier */
if (test_and_clear_bit(SUSPEND_PAUSE_DISCOVERY, hdev->suspend_tasks)) {
bt_dev_dbg(hdev, "Paused discovery");
wake_up(&hdev->suspend_wait_q);
}
if (!err) if (!err)
hci_discovery_set_state(hdev, DISCOVERY_STOPPED); hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
} }
...@@ -5709,17 +5683,6 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err) ...@@ -5709,17 +5683,6 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
if (match.sk) if (match.sk)
sock_put(match.sk); sock_put(match.sk);
/* Handle suspend notifier */
if (test_and_clear_bit(SUSPEND_PAUSE_ADVERTISING,
hdev->suspend_tasks)) {
bt_dev_dbg(hdev, "Paused advertising");
wake_up(&hdev->suspend_wait_q);
} else if (test_and_clear_bit(SUSPEND_UNPAUSE_ADVERTISING,
hdev->suspend_tasks)) {
bt_dev_dbg(hdev, "Unpaused advertising");
wake_up(&hdev->suspend_wait_q);
}
/* If "Set Advertising" was just disabled and instance advertising was /* If "Set Advertising" was just disabled and instance advertising was
* set up earlier, then re-enable multi-instance advertising. * set up earlier, then re-enable multi-instance advertising.
*/ */
......
This diff is collapsed.
...@@ -24,8 +24,8 @@ int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor, ...@@ -24,8 +24,8 @@ int msft_remove_monitor(struct hci_dev *hdev, struct adv_monitor *monitor,
u16 handle); u16 handle);
void msft_req_add_set_filter_enable(struct hci_request *req, bool enable); void msft_req_add_set_filter_enable(struct hci_request *req, bool enable);
int msft_set_filter_enable(struct hci_dev *hdev, bool enable); int msft_set_filter_enable(struct hci_dev *hdev, bool enable);
void msft_suspend(struct hci_dev *hdev); int msft_suspend_sync(struct hci_dev *hdev);
void msft_resume(struct hci_dev *hdev); int msft_resume_sync(struct hci_dev *hdev);
bool msft_curve_validity(struct hci_dev *hdev); bool msft_curve_validity(struct hci_dev *hdev);
#else #else
...@@ -61,8 +61,15 @@ static inline int msft_set_filter_enable(struct hci_dev *hdev, bool enable) ...@@ -61,8 +61,15 @@ static inline int msft_set_filter_enable(struct hci_dev *hdev, bool enable)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
static inline void msft_suspend(struct hci_dev *hdev) {} static inline int msft_suspend_sync(struct hci_dev *hdev)
static inline void msft_resume(struct hci_dev *hdev) {} {
return -EOPNOTSUPP;
}
static inline int msft_resume_sync(struct hci_dev *hdev)
{
return -EOPNOTSUPP;
}
static inline bool msft_curve_validity(struct hci_dev *hdev) static inline bool msft_curve_validity(struct hci_dev *hdev)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment