Skip to content

Commit 6a98e38

Browse files
committed
Bluetooth: Add helper for serialized HCI command execution
The usage of __hci_cmd_sync() within the hdev->setup() callback allows for a nice and simple serialized execution of HCI commands. More importantly it allows for result processing before issueing the next command. With the current usage of hci_req_run() it is possible to batch up commands and execute them, but it is impossible to react to their results or errors. This is an attempt to generalize the hdev->setup() handling and provide a simple way of running multiple HCI commands from a single function context. There are multiple struct work that are decdicated to certain tasks already used right now. It is add a lot of bloat to hci_dev struct and extra handling code. So it might be possible to put all of these behind a common HCI command infrastructure and just execute the HCI commands from the same work context in a serialized fashion. For example updating the white list and resolving list can be done now without having to know the list size ahead of time. Also preparing for suspend or resume shouldn't require a state machine anymore. There are other tasks that should be simplified as well. Signed-off-by: Marcel Holtmann <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]> Signed-off-by: Marcel Holtmann <[email protected]>
1 parent 2128939 commit 6a98e38

File tree

7 files changed

+385
-95
lines changed

7 files changed

+385
-95
lines changed

include/net/bluetooth/hci_core.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <linux/rculist.h>
3131

3232
#include <net/bluetooth/hci.h>
33+
#include <net/bluetooth/hci_sync.h>
3334
#include <net/bluetooth/hci_sock.h>
3435

3536
/* HCI priority */
@@ -475,6 +476,9 @@ struct hci_dev {
475476
struct work_struct power_on;
476477
struct delayed_work power_off;
477478
struct work_struct error_reset;
479+
struct work_struct cmd_sync_work;
480+
struct list_head cmd_sync_work_list;
481+
struct mutex cmd_sync_work_lock;
478482

479483
__u16 discov_timeout;
480484
struct delayed_work discov_off;
@@ -1690,10 +1694,6 @@ static inline int hci_check_conn_params(u16 min, u16 max, u16 latency,
16901694
int hci_register_cb(struct hci_cb *hcb);
16911695
int hci_unregister_cb(struct hci_cb *hcb);
16921696

1693-
struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
1694-
const void *param, u32 timeout);
1695-
struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
1696-
const void *param, u8 event, u32 timeout);
16971697
int __hci_cmd_send(struct hci_dev *hdev, u16 opcode, u32 plen,
16981698
const void *param);
16991699

@@ -1704,9 +1704,6 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
17041704

17051705
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
17061706

1707-
struct sk_buff *hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
1708-
const void *param, u32 timeout);
1709-
17101707
u32 hci_conn_get_phy(struct hci_conn *conn);
17111708

17121709
/* ----- HCI Sockets ----- */

include/net/bluetooth/hci_sync.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
/*
3+
* BlueZ - Bluetooth protocol stack for Linux
4+
*
5+
* Copyright (C) 2021 Intel Corporation
6+
*/
7+
8+
typedef int (*hci_cmd_sync_work_func_t)(struct hci_dev *hdev, void *data);
9+
typedef void (*hci_cmd_sync_work_destroy_t)(struct hci_dev *hdev, void *data,
10+
int err);
11+
12+
struct hci_cmd_sync_work_entry {
13+
struct list_head list;
14+
hci_cmd_sync_work_func_t func;
15+
void *data;
16+
hci_cmd_sync_work_destroy_t destroy;
17+
};
18+
19+
/* Function with sync suffix shall not be called with hdev->lock held as they
20+
* wait the command to complete and in the meantime an event could be received
21+
* which could attempt to acquire hdev->lock causing a deadlock.
22+
*/
23+
struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
24+
const void *param, u32 timeout);
25+
struct sk_buff *hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
26+
const void *param, u32 timeout);
27+
struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
28+
const void *param, u8 event, u32 timeout);
29+
struct sk_buff *__hci_cmd_sync_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
30+
const void *param, u8 event, u32 timeout,
31+
struct sock *sk);
32+
int __hci_cmd_sync_status(struct hci_dev *hdev, u16 opcode, u32 plen,
33+
const void *param, u32 timeout);
34+
int __hci_cmd_sync_status_sk(struct hci_dev *hdev, u16 opcode, u32 plen,
35+
const void *param, u8 event, u32 timeout,
36+
struct sock *sk);
37+
38+
void hci_cmd_sync_init(struct hci_dev *hdev);
39+
void hci_cmd_sync_clear(struct hci_dev *hdev);
40+
41+
int hci_cmd_sync_queue(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
42+
void *data, hci_cmd_sync_work_destroy_t destroy);

net/bluetooth/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ bluetooth_6lowpan-y := 6lowpan.o
1515
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
1616
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \
1717
ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o hci_codec.o \
18-
eir.o
18+
eir.o hci_sync.o
1919

2020
bluetooth-$(CONFIG_BT_BREDR) += sco.o
2121
bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o

net/bluetooth/hci_core.c

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3747,6 +3747,8 @@ struct hci_dev *hci_alloc_dev_priv(int sizeof_priv)
37473747
INIT_WORK(&hdev->error_reset, hci_error_reset);
37483748
INIT_WORK(&hdev->suspend_prepare, hci_prepare_suspend);
37493749

3750+
hci_cmd_sync_init(hdev);
3751+
37503752
INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
37513753

37523754
skb_queue_head_init(&hdev->rx_q);
@@ -3905,6 +3907,8 @@ void hci_unregister_dev(struct hci_dev *hdev)
39053907

39063908
cancel_work_sync(&hdev->power_on);
39073909

3910+
hci_cmd_sync_clear(hdev);
3911+
39083912
if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks)) {
39093913
hci_suspend_clear_tasks(hdev);
39103914
unregister_pm_notifier(&hdev->suspend_notifier);
@@ -4271,25 +4275,6 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
42714275
return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE;
42724276
}
42734277

4274-
/* Send HCI command and wait for command complete event */
4275-
struct sk_buff *hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
4276-
const void *param, u32 timeout)
4277-
{
4278-
struct sk_buff *skb;
4279-
4280-
if (!test_bit(HCI_UP, &hdev->flags))
4281-
return ERR_PTR(-ENETDOWN);
4282-
4283-
bt_dev_dbg(hdev, "opcode 0x%4.4x plen %d", opcode, plen);
4284-
4285-
hci_req_sync_lock(hdev);
4286-
skb = __hci_cmd_sync(hdev, opcode, plen, param, timeout);
4287-
hci_req_sync_unlock(hdev);
4288-
4289-
return skb;
4290-
}
4291-
EXPORT_SYMBOL(hci_cmd_sync);
4292-
42934278
/* Send ACL data */
42944279
static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
42954280
{

net/bluetooth/hci_request.c

Lines changed: 0 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@
3232
#include "msft.h"
3333
#include "eir.h"
3434

35-
#define HCI_REQ_DONE 0
36-
#define HCI_REQ_PEND 1
37-
#define HCI_REQ_CANCELED 2
38-
3935
void hci_req_init(struct hci_request *req, struct hci_dev *hdev)
4036
{
4137
skb_queue_head_init(&req->cmd_q);
@@ -126,70 +122,6 @@ void hci_req_sync_cancel(struct hci_dev *hdev, int err)
126122
}
127123
}
128124

129-
struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
130-
const void *param, u8 event, u32 timeout)
131-
{
132-
struct hci_request req;
133-
struct sk_buff *skb;
134-
int err = 0;
135-
136-
bt_dev_dbg(hdev, "");
137-
138-
hci_req_init(&req, hdev);
139-
140-
hci_req_add_ev(&req, opcode, plen, param, event);
141-
142-
hdev->req_status = HCI_REQ_PEND;
143-
144-
err = hci_req_run_skb(&req, hci_req_sync_complete);
145-
if (err < 0)
146-
return ERR_PTR(err);
147-
148-
err = wait_event_interruptible_timeout(hdev->req_wait_q,
149-
hdev->req_status != HCI_REQ_PEND, timeout);
150-
151-
if (err == -ERESTARTSYS)
152-
return ERR_PTR(-EINTR);
153-
154-
switch (hdev->req_status) {
155-
case HCI_REQ_DONE:
156-
err = -bt_to_errno(hdev->req_result);
157-
break;
158-
159-
case HCI_REQ_CANCELED:
160-
err = -hdev->req_result;
161-
break;
162-
163-
default:
164-
err = -ETIMEDOUT;
165-
break;
166-
}
167-
168-
hdev->req_status = hdev->req_result = 0;
169-
skb = hdev->req_skb;
170-
hdev->req_skb = NULL;
171-
172-
bt_dev_dbg(hdev, "end: err %d", err);
173-
174-
if (err < 0) {
175-
kfree_skb(skb);
176-
return ERR_PTR(err);
177-
}
178-
179-
if (!skb)
180-
return ERR_PTR(-ENODATA);
181-
182-
return skb;
183-
}
184-
EXPORT_SYMBOL(__hci_cmd_sync_ev);
185-
186-
struct sk_buff *__hci_cmd_sync(struct hci_dev *hdev, u16 opcode, u32 plen,
187-
const void *param, u32 timeout)
188-
{
189-
return __hci_cmd_sync_ev(hdev, opcode, plen, param, 0, timeout);
190-
}
191-
EXPORT_SYMBOL(__hci_cmd_sync);
192-
193125
/* Execute request and wait for completion. */
194126
int __hci_req_sync(struct hci_dev *hdev, int (*func)(struct hci_request *req,
195127
unsigned long opt),

net/bluetooth/hci_request.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@
2525
#define hci_req_sync_lock(hdev) mutex_lock(&hdev->req_lock)
2626
#define hci_req_sync_unlock(hdev) mutex_unlock(&hdev->req_lock)
2727

28+
#define HCI_REQ_DONE 0
29+
#define HCI_REQ_PEND 1
30+
#define HCI_REQ_CANCELED 2
31+
2832
struct hci_request {
2933
struct hci_dev *hdev;
3034
struct sk_buff_head cmd_q;

0 commit comments

Comments
 (0)