Skip to content

Commit 182ee45

Browse files
Vudentzholtmann
authored andcommitted
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: Luiz Augusto von Dentz <[email protected]> Signed-off-by: Marcel Holtmann <[email protected]>
1 parent d0b1370 commit 182ee45

File tree

10 files changed

+650
-638
lines changed

10 files changed

+650
-638
lines changed

include/net/bluetooth/hci_core.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,6 @@ struct hci_dev {
523523
bool advertising_paused;
524524

525525
struct notifier_block suspend_notifier;
526-
struct work_struct suspend_prepare;
527526
enum suspended_state suspend_state_next;
528527
enum suspended_state suspend_state;
529528
bool scanning_paused;
@@ -532,9 +531,6 @@ struct hci_dev {
532531
bdaddr_t wake_addr;
533532
u8 wake_addr_type;
534533

535-
wait_queue_head_t suspend_wait_q;
536-
DECLARE_BITMAP(suspend_tasks, __SUSPEND_NUM_TASKS);
537-
538534
struct hci_conn_hash conn_hash;
539535

540536
struct list_head mgmt_pending;

include/net/bluetooth/hci_sync.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,6 @@ int hci_set_powered_sync(struct hci_dev *hdev, u8 val);
9292

9393
int hci_start_discovery_sync(struct hci_dev *hdev);
9494
int hci_stop_discovery_sync(struct hci_dev *hdev);
95+
96+
int hci_suspend_sync(struct hci_dev *hdev);
97+
int hci_resume_sync(struct hci_dev *hdev);

net/bluetooth/hci_conn.c

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -900,16 +900,6 @@ void hci_le_conn_failed(struct hci_conn *conn, u8 status)
900900

901901
hci_conn_del(conn);
902902

903-
/* The suspend notifier is waiting for all devices to disconnect and an
904-
* LE connect cancel will result in an hci_le_conn_failed. Once the last
905-
* connection is deleted, we should also wake the suspend queue to
906-
* complete suspend operations.
907-
*/
908-
if (list_empty(&hdev->conn_hash.list) &&
909-
test_and_clear_bit(SUSPEND_DISCONNECTING, hdev->suspend_tasks)) {
910-
wake_up(&hdev->suspend_wait_q);
911-
}
912-
913903
/* Since we may have temporarily stopped the background scanning in
914904
* favor of connection establishment, we should restart it.
915905
*/

net/bluetooth/hci_core.c

Lines changed: 12 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,61 +2374,6 @@ void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
23742374
}
23752375
}
23762376

2377-
static void hci_suspend_clear_tasks(struct hci_dev *hdev)
2378-
{
2379-
int i;
2380-
2381-
for (i = 0; i < __SUSPEND_NUM_TASKS; i++)
2382-
clear_bit(i, hdev->suspend_tasks);
2383-
2384-
wake_up(&hdev->suspend_wait_q);
2385-
}
2386-
2387-
static int hci_suspend_wait_event(struct hci_dev *hdev)
2388-
{
2389-
#define WAKE_COND \
2390-
(find_first_bit(hdev->suspend_tasks, __SUSPEND_NUM_TASKS) == \
2391-
__SUSPEND_NUM_TASKS)
2392-
2393-
int i;
2394-
int ret = wait_event_timeout(hdev->suspend_wait_q,
2395-
WAKE_COND, SUSPEND_NOTIFIER_TIMEOUT);
2396-
2397-
if (ret == 0) {
2398-
bt_dev_err(hdev, "Timed out waiting for suspend events");
2399-
for (i = 0; i < __SUSPEND_NUM_TASKS; ++i) {
2400-
if (test_bit(i, hdev->suspend_tasks))
2401-
bt_dev_err(hdev, "Suspend timeout bit: %d", i);
2402-
clear_bit(i, hdev->suspend_tasks);
2403-
}
2404-
2405-
ret = -ETIMEDOUT;
2406-
} else {
2407-
ret = 0;
2408-
}
2409-
2410-
return ret;
2411-
}
2412-
2413-
static void hci_prepare_suspend(struct work_struct *work)
2414-
{
2415-
struct hci_dev *hdev =
2416-
container_of(work, struct hci_dev, suspend_prepare);
2417-
2418-
hci_dev_lock(hdev);
2419-
hci_req_prepare_suspend(hdev, hdev->suspend_state_next);
2420-
hci_dev_unlock(hdev);
2421-
}
2422-
2423-
static int hci_change_suspend_state(struct hci_dev *hdev,
2424-
enum suspended_state next)
2425-
{
2426-
hdev->suspend_state_next = next;
2427-
set_bit(SUSPEND_PREPARE_NOTIFIER, hdev->suspend_tasks);
2428-
queue_work(hdev->req_workqueue, &hdev->suspend_prepare);
2429-
return hci_suspend_wait_event(hdev);
2430-
}
2431-
24322377
static void hci_clear_wake_reason(struct hci_dev *hdev)
24332378
{
24342379
hci_dev_lock(hdev);
@@ -2565,7 +2510,6 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
25652510
INIT_WORK(&hdev->tx_work, hci_tx_work);
25662511
INIT_WORK(&hdev->power_on, hci_power_on);
25672512
INIT_WORK(&hdev->error_reset, hci_error_reset);
2568-
INIT_WORK(&hdev->suspend_prepare, hci_prepare_suspend);
25692513

25702514
hci_cmd_sync_init(hdev);
25712515

@@ -2576,7 +2520,6 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
25762520
skb_queue_head_init(&hdev->raw_q);
25772521

25782522
init_waitqueue_head(&hdev->req_wait_q);
2579-
init_waitqueue_head(&hdev->suspend_wait_q);
25802523

25812524
INIT_DELAYED_WORK(&hdev->cmd_timer, hci_cmd_timeout);
25822525
INIT_DELAYED_WORK(&hdev->ncmd_timer, hci_ncmd_timeout);
@@ -2729,11 +2672,8 @@ void hci_unregister_dev(struct hci_dev *hdev)
27292672

27302673
hci_cmd_sync_clear(hdev);
27312674

2732-
if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks)) {
2733-
hci_suspend_clear_tasks(hdev);
2675+
if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks))
27342676
unregister_pm_notifier(&hdev->suspend_notifier);
2735-
cancel_work_sync(&hdev->suspend_prepare);
2736-
}
27372677

27382678
msft_unregister(hdev);
27392679

@@ -2800,7 +2740,6 @@ EXPORT_SYMBOL(hci_release_dev);
28002740
int hci_suspend_dev(struct hci_dev *hdev)
28012741
{
28022742
int ret;
2803-
u8 state = BT_RUNNING;
28042743

28052744
bt_dev_dbg(hdev, "");
28062745

@@ -2809,40 +2748,17 @@ int hci_suspend_dev(struct hci_dev *hdev)
28092748
hci_dev_test_flag(hdev, HCI_UNREGISTER))
28102749
return 0;
28112750

2812-
/* If powering down, wait for completion. */
2813-
if (mgmt_powering_down(hdev)) {
2814-
set_bit(SUSPEND_POWERING_DOWN, hdev->suspend_tasks);
2815-
ret = hci_suspend_wait_event(hdev);
2816-
if (ret)
2817-
goto done;
2818-
}
2819-
2820-
/* Suspend consists of two actions:
2821-
* - First, disconnect everything and make the controller not
2822-
* connectable (disabling scanning)
2823-
* - Second, program event filter/accept list and enable scan
2824-
*/
2825-
ret = hci_change_suspend_state(hdev, BT_SUSPEND_DISCONNECT);
2826-
if (ret)
2827-
goto clear;
2828-
2829-
state = BT_SUSPEND_DISCONNECT;
2751+
/* If powering down don't attempt to suspend */
2752+
if (mgmt_powering_down(hdev))
2753+
return 0;
28302754

2831-
/* Only configure accept list if device may wakeup. */
2832-
if (hdev->wakeup && hdev->wakeup(hdev)) {
2833-
ret = hci_change_suspend_state(hdev, BT_SUSPEND_CONFIGURE_WAKE);
2834-
if (!ret)
2835-
state = BT_SUSPEND_CONFIGURE_WAKE;
2836-
}
2755+
hci_req_sync_lock(hdev);
2756+
ret = hci_suspend_sync(hdev);
2757+
hci_req_sync_unlock(hdev);
28372758

2838-
clear:
28392759
hci_clear_wake_reason(hdev);
2840-
mgmt_suspending(hdev, state);
2760+
mgmt_suspending(hdev, hdev->suspend_state);
28412761

2842-
done:
2843-
/* We always allow suspend even if suspend preparation failed and
2844-
* attempt to recover in resume.
2845-
*/
28462762
hci_sock_dev_event(hdev, HCI_DEV_SUSPEND);
28472763
return ret;
28482764
}
@@ -2864,10 +2780,12 @@ int hci_resume_dev(struct hci_dev *hdev)
28642780
if (mgmt_powering_down(hdev))
28652781
return 0;
28662782

2867-
ret = hci_change_suspend_state(hdev, BT_RUNNING);
2783+
hci_req_sync_lock(hdev);
2784+
ret = hci_resume_sync(hdev);
2785+
hci_req_sync_unlock(hdev);
28682786

28692787
mgmt_resuming(hdev, hdev->wake_reason, &hdev->wake_addr,
2870-
hdev->wake_addr_type);
2788+
hdev->wake_addr_type);
28712789

28722790
hci_sock_dev_event(hdev, HCI_DEV_RESUME);
28732791
return ret;

net/bluetooth/hci_event.c

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2414,9 +2414,14 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
24142414
static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
24152415
{
24162416
struct hci_cp_disconnect *cp;
2417+
struct hci_conn_params *params;
24172418
struct hci_conn *conn;
2419+
bool mgmt_conn;
24182420

2419-
if (!status)
2421+
/* Wait for HCI_EV_DISCONN_COMPLETE if status 0x00 and not suspended
2422+
* otherwise cleanup the connection immediately.
2423+
*/
2424+
if (!status && !hdev->suspended)
24202425
return;
24212426

24222427
cp = hci_sent_cmd_data(hdev, HCI_OP_DISCONNECT);
@@ -2426,7 +2431,10 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
24262431
hci_dev_lock(hdev);
24272432

24282433
conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle));
2429-
if (conn) {
2434+
if (!conn)
2435+
goto unlock;
2436+
2437+
if (status) {
24302438
mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
24312439
conn->dst_type, status);
24322440

@@ -2435,14 +2443,48 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
24352443
hci_enable_advertising(hdev);
24362444
}
24372445

2438-
/* If the disconnection failed for any reason, the upper layer
2439-
* does not retry to disconnect in current implementation.
2440-
* Hence, we need to do some basic cleanup here and re-enable
2441-
* advertising if necessary.
2442-
*/
2443-
hci_conn_del(conn);
2446+
goto done;
24442447
}
24452448

2449+
mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags);
2450+
2451+
if (conn->type == ACL_LINK) {
2452+
if (test_bit(HCI_CONN_FLUSH_KEY, &conn->flags))
2453+
hci_remove_link_key(hdev, &conn->dst);
2454+
}
2455+
2456+
params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type);
2457+
if (params) {
2458+
switch (params->auto_connect) {
2459+
case HCI_AUTO_CONN_LINK_LOSS:
2460+
if (cp->reason != HCI_ERROR_CONNECTION_TIMEOUT)
2461+
break;
2462+
fallthrough;
2463+
2464+
case HCI_AUTO_CONN_DIRECT:
2465+
case HCI_AUTO_CONN_ALWAYS:
2466+
list_del_init(&params->action);
2467+
list_add(&params->action, &hdev->pend_le_conns);
2468+
break;
2469+
2470+
default:
2471+
break;
2472+
}
2473+
}
2474+
2475+
mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type,
2476+
cp->reason, mgmt_conn);
2477+
2478+
hci_disconn_cfm(conn, cp->reason);
2479+
2480+
done:
2481+
/* If the disconnection failed for any reason, the upper layer
2482+
* does not retry to disconnect in current implementation.
2483+
* Hence, we need to do some basic cleanup here and re-enable
2484+
* advertising if necessary.
2485+
*/
2486+
hci_conn_del(conn);
2487+
unlock:
24462488
hci_dev_unlock(hdev);
24472489
}
24482490

@@ -3047,14 +3089,6 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
30473089

30483090
hci_conn_del(conn);
30493091

3050-
/* The suspend notifier is waiting for all devices to disconnect so
3051-
* clear the bit from pending tasks and inform the wait queue.
3052-
*/
3053-
if (list_empty(&hdev->conn_hash.list) &&
3054-
test_and_clear_bit(SUSPEND_DISCONNECTING, hdev->suspend_tasks)) {
3055-
wake_up(&hdev->suspend_wait_q);
3056-
}
3057-
30583092
unlock:
30593093
hci_dev_unlock(hdev);
30603094
}
@@ -5575,8 +5609,9 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
55755609
if (adv_type != LE_ADV_IND && adv_type != LE_ADV_DIRECT_IND)
55765610
return NULL;
55775611

5578-
/* Ignore if the device is blocked */
5579-
if (hci_bdaddr_list_lookup(&hdev->reject_list, addr, addr_type))
5612+
/* Ignore if the device is blocked or hdev is suspended */
5613+
if (hci_bdaddr_list_lookup(&hdev->reject_list, addr, addr_type) ||
5614+
hdev->suspended)
55805615
return NULL;
55815616

55825617
/* Most controller will fail if we try to create new connections

0 commit comments

Comments
 (0)