Skip to content

Commit 7ebe7da

Browse files
carlescufijhedberg
authored andcommitted
Bluetooth: controller: Controller to Host flow control
The Bluetooth Specification allows for optional Controller to Host flow control based on the same credit-based mechanism as the Host to Controller one. This is particularly useful in 2-chip solutions where the Host and the Controller are connected via a physical link (UART, SPI or similar) where the Host is sometimes required to ask the Controller to throttle its data traffic while still making sure that relevant events get through the line. This implementation is based on a simple queue of pending events and data that is populated whenever the Controller detects that the Host is out of buffers and then emptied whenever the Host notifies the Controller that is ready to receive data again. Events relevant to the connections are also queued to preserve the order of arrival. At this point the Controller ignores the connection handle sent by the Host and treats all connections equally, and it also queues events even for connections that have no data pending in the queue. Both this items can be improved if necessity arises. Note that Number of Completed Packets will still flow freely from the Controller to the Host regardless of the pending ACL data packets, which might lead to inconsistencies in the sequential order of certain operations that include bi-directional data transfer. Jira: ZEP-1735 Signed-off-by: Carles Cufi <[email protected]>
1 parent 7e7a045 commit 7ebe7da

File tree

7 files changed

+452
-44
lines changed

7 files changed

+452
-44
lines changed

include/bluetooth/hci.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,8 +491,12 @@ struct bt_hci_write_local_name {
491491
#define BT_BREDR_SCAN_INQUIRY 0x01
492492
#define BT_BREDR_SCAN_PAGE 0x02
493493

494+
#define BT_HCI_CTL_TO_HOST_FLOW_DISABLE 0x00
494495
#define BT_HCI_CTL_TO_HOST_FLOW_ENABLE 0x01
495496
#define BT_HCI_OP_SET_CTL_TO_HOST_FLOW BT_OP(BT_OGF_BASEBAND, 0x0031)
497+
struct bt_hci_cp_set_ctl_to_host_flow {
498+
u8_t flow_enable;
499+
} __packed;
496500

497501
#define BT_HCI_OP_HOST_BUFFER_SIZE BT_OP(BT_OGF_BASEBAND, 0x0033)
498502
struct bt_hci_cp_host_buffer_size {

subsys/bluetooth/controller/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ endchoice
3030

3131
comment "BLE Controller configuration"
3232

33+
config BLUETOOTH_CONTROLLER_TO_HOST_FC
34+
bool "Controller to Host Flow Control"
35+
depends on BLUETOOTH_CONN
36+
default n
37+
default y if BLUETOOTH_HCI_RAW
38+
select POLL
39+
help
40+
Enable Controller to Host flow control.
41+
3342
config BLUETOOTH_CONTROLLER_DUP_FILTER_LEN
3443
prompt "Number of addresses in the scan duplicate filter"
3544
int

subsys/bluetooth/controller/hci/hci.c

Lines changed: 198 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <soc.h>
1313
#include <toolchain.h>
1414
#include <errno.h>
15+
#include <atomic.h>
1516
#include <bluetooth/hci.h>
1617
#include <bluetooth/buf.h>
1718
#include <bluetooth/bluetooth.h>
@@ -46,6 +47,18 @@ static s32_t dup_count;
4647
static u32_t dup_curr;
4748
#endif
4849

50+
#if defined(CONFIG_BLUETOOTH_CONTROLLER_TO_HOST_FC)
51+
s32_t hci_hbuf_total;
52+
u32_t hci_hbuf_sent;
53+
u32_t hci_hbuf_acked;
54+
atomic_t hci_state_mask;
55+
static struct k_poll_signal *hbuf_signal;
56+
#endif
57+
58+
#if defined(CONFIG_BLUETOOTH_CONN)
59+
static u32_t conn_count;
60+
#endif
61+
4962
#define DEFAULT_EVENT_MASK 0x1fffffffffff
5063
#define DEFAULT_LE_EVENT_MASK 0x1f
5164

@@ -159,18 +172,119 @@ static void reset(struct net_buf *buf, struct net_buf **evt)
159172
{
160173
struct bt_hci_evt_cc_status *ccst;
161174

162-
ll_reset();
163-
164175
#if CONFIG_BLUETOOTH_CONTROLLER_DUP_FILTER_LEN > 0
165176
dup_count = -1;
166177
#endif
167178
/* reset event masks */
168179
event_mask = DEFAULT_EVENT_MASK;
169180
le_event_mask = DEFAULT_LE_EVENT_MASK;
170181

182+
if (buf) {
183+
ll_reset();
184+
ccst = cmd_complete(evt, sizeof(*ccst));
185+
ccst->status = 0x00;
186+
}
187+
#if defined(CONFIG_BLUETOOTH_CONTROLLER_TO_HOST_FC)
188+
hci_hbuf_total = 0;
189+
hci_hbuf_sent = 0;
190+
hci_hbuf_acked = 0;
191+
conn_count = 0;
192+
atomic_set_bit(&hci_state_mask, HCI_STATE_BIT_RESET);
193+
k_poll_signal(hbuf_signal, 0x0);
194+
#endif
195+
}
196+
197+
#if defined(CONFIG_BLUETOOTH_CONTROLLER_TO_HOST_FC)
198+
static void set_ctl_to_host_flow(struct net_buf *buf, struct net_buf **evt)
199+
{
200+
struct bt_hci_cp_set_ctl_to_host_flow *cmd = (void *)buf->data;
201+
struct bt_hci_evt_cc_status *ccst;
202+
171203
ccst = cmd_complete(evt, sizeof(*ccst));
172-
ccst->status = 0x00;
204+
205+
/* require host buffer size before enabling flow control, and
206+
* disallow if any connections are up
207+
*/
208+
if (!hci_hbuf_total || conn_count) {
209+
ccst->status = BT_HCI_ERR_CMD_DISALLOWED;
210+
return;
211+
} else {
212+
ccst->status = 0x00;
213+
}
214+
215+
switch (cmd->flow_enable) {
216+
case BT_HCI_CTL_TO_HOST_FLOW_DISABLE:
217+
if (hci_hbuf_total < 0) {
218+
/* already disabled */
219+
return;
220+
}
221+
break;
222+
case BT_HCI_CTL_TO_HOST_FLOW_ENABLE:
223+
if (hci_hbuf_total > 0) {
224+
/* already enabled */
225+
return;
226+
}
227+
break;
228+
default:
229+
ccst->status = BT_HCI_ERR_INVALID_PARAM;
230+
return;
231+
}
232+
233+
hci_hbuf_sent = 0;
234+
hci_hbuf_acked = 0;
235+
hci_hbuf_total = -hci_hbuf_total;
236+
}
237+
238+
static void host_buffer_size(struct net_buf *buf, struct net_buf **evt)
239+
{
240+
struct bt_hci_cp_host_buffer_size *cmd = (void *)buf->data;
241+
struct bt_hci_evt_cc_status *ccst;
242+
243+
ccst = cmd_complete(evt, sizeof(*ccst));
244+
245+
if (hci_hbuf_total) {
246+
ccst->status = BT_HCI_ERR_CMD_DISALLOWED;
247+
return;
248+
}
249+
/* fragmentation from controller to host not supported, require
250+
* ACL MTU to be at least the LL MTU
251+
*/
252+
if (cmd->acl_mtu < RADIO_LL_LENGTH_OCTETS_RX_MAX) {
253+
ccst->status = BT_HCI_ERR_INVALID_PARAM;
254+
return;
255+
}
256+
257+
hci_hbuf_total = -cmd->acl_pkts;
258+
}
259+
260+
static void host_num_completed_packets(struct net_buf *buf,
261+
struct net_buf **evt)
262+
{
263+
struct bt_hci_cp_host_num_completed_packets *cmd = (void *)buf->data;
264+
struct bt_hci_evt_cc_status *ccst;
265+
u32_t count = 0;
266+
int i;
267+
268+
/* special case, no event returned except for error conditions */
269+
if (hci_hbuf_total <= 0) {
270+
ccst = cmd_complete(evt, sizeof(*ccst));
271+
ccst->status = BT_HCI_ERR_CMD_DISALLOWED;
272+
return;
273+
} else if (!conn_count) {
274+
ccst = cmd_complete(evt, sizeof(*ccst));
275+
ccst->status = BT_HCI_ERR_INVALID_PARAM;
276+
return;
277+
}
278+
279+
/* leave *evt == NULL so no event is generated */
280+
for (i = 0; i < cmd->num_handles; i++) {
281+
count += cmd->h[i].count;
282+
}
283+
284+
hci_hbuf_acked += count;
285+
k_poll_signal(hbuf_signal, 0x0);
173286
}
287+
#endif
174288

175289
static int ctrl_bb_cmd_handle(u8_t ocf, struct net_buf *cmd,
176290
struct net_buf **evt)
@@ -184,6 +298,19 @@ static int ctrl_bb_cmd_handle(u8_t ocf, struct net_buf *cmd,
184298
reset(cmd, evt);
185299
break;
186300

301+
#if defined(CONFIG_BLUETOOTH_CONTROLLER_TO_HOST_FC)
302+
case BT_OCF(BT_HCI_OP_SET_CTL_TO_HOST_FLOW):
303+
set_ctl_to_host_flow(cmd, evt);
304+
break;
305+
306+
case BT_OCF(BT_HCI_OP_HOST_BUFFER_SIZE):
307+
host_buffer_size(cmd, evt);
308+
break;
309+
310+
case BT_OCF(BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS):
311+
host_num_completed_packets(cmd, evt);
312+
break;
313+
#endif
187314
default:
188315
return -EINVAL;
189316
}
@@ -1082,6 +1209,7 @@ static void le_advertising_report(struct pdu_data *pdu_data, u8_t *b,
10821209

10831210
}
10841211

1212+
#if defined(CONFIG_BLUETOOTH_CONN)
10851213
static void le_conn_complete(struct pdu_data *pdu_data, u16_t handle,
10861214
struct net_buf *buf)
10871215
{
@@ -1106,6 +1234,8 @@ static void le_conn_complete(struct pdu_data *pdu_data, u16_t handle,
11061234
sep->latency = sys_cpu_to_le16(radio_cc->latency);
11071235
sep->supv_timeout = sys_cpu_to_le16(radio_cc->timeout);
11081236
sep->clock_accuracy = radio_cc->mca;
1237+
1238+
conn_count++;
11091239
}
11101240

11111241
static void disconn_complete(struct pdu_data *pdu_data, u16_t handle,
@@ -1123,6 +1253,8 @@ static void disconn_complete(struct pdu_data *pdu_data, u16_t handle,
11231253
ep->status = 0x00;
11241254
ep->handle = sys_cpu_to_le16(handle);
11251255
ep->reason = *((u8_t *)pdu_data);
1256+
1257+
conn_count--;
11261258
}
11271259

11281260
static void le_conn_update_complete(struct pdu_data *pdu_data, u16_t handle,
@@ -1163,6 +1295,7 @@ static void enc_refresh_complete(struct pdu_data *pdu_data, u16_t handle,
11631295
ep->status = 0x00;
11641296
ep->handle = sys_cpu_to_le16(handle);
11651297
}
1298+
#endif
11661299

11671300
#if defined(CONFIG_BLUETOOTH_CONTROLLER_LE_PING)
11681301
static void auth_payload_timeout_exp(struct pdu_data *pdu_data, u16_t handle,
@@ -1212,6 +1345,7 @@ static void encode_control(struct radio_pdu_node_rx *node_rx,
12121345
le_advertising_report(pdu_data, b, buf);
12131346
break;
12141347

1348+
#if defined(CONFIG_BLUETOOTH_CONN)
12151349
case NODE_RX_TYPE_CONNECTION:
12161350
le_conn_complete(pdu_data, handle, buf);
12171351
break;
@@ -1227,6 +1361,7 @@ static void encode_control(struct radio_pdu_node_rx *node_rx,
12271361
case NODE_RX_TYPE_ENC_REFRESH:
12281362
enc_refresh_complete(pdu_data, handle, buf);
12291363
break;
1364+
#endif
12301365

12311366
#if defined(CONFIG_BLUETOOTH_CONTROLLER_LE_PING)
12321367
case NODE_RX_TYPE_APTO:
@@ -1460,6 +1595,7 @@ static void encode_data_ctrl(struct radio_pdu_node_rx *node_rx,
14601595
}
14611596
}
14621597

1598+
#if defined(CONFIG_BLUETOOTH_CONN)
14631599
void hci_acl_encode(struct radio_pdu_node_rx *node_rx, struct net_buf *buf)
14641600
{
14651601
struct bt_hci_acl_hdr *acl;
@@ -1484,6 +1620,13 @@ void hci_acl_encode(struct radio_pdu_node_rx *node_rx, struct net_buf *buf)
14841620
acl->len = sys_cpu_to_le16(pdu_data->len);
14851621
data = (void *)net_buf_add(buf, pdu_data->len);
14861622
memcpy(data, &pdu_data->payload.lldata[0], pdu_data->len);
1623+
#if defined(CONFIG_BLUETOOTH_CONTROLLER_TO_HOST_FC)
1624+
if (hci_hbuf_total > 0) {
1625+
LL_ASSERT((hci_hbuf_sent - hci_hbuf_acked) <
1626+
hci_hbuf_total);
1627+
hci_hbuf_sent++;
1628+
}
1629+
#endif
14871630
break;
14881631

14891632
default:
@@ -1492,6 +1635,7 @@ void hci_acl_encode(struct radio_pdu_node_rx *node_rx, struct net_buf *buf)
14921635
}
14931636

14941637
}
1638+
#endif
14951639

14961640
void hci_evt_encode(struct radio_pdu_node_rx *node_rx, struct net_buf *buf)
14971641
{
@@ -1534,3 +1678,54 @@ bool hci_evt_is_discardable(struct radio_pdu_node_rx *node_rx)
15341678
return false;
15351679
}
15361680
}
1681+
1682+
s8_t hci_get_class(struct radio_pdu_node_rx *node_rx)
1683+
{
1684+
struct pdu_data *pdu_data;
1685+
1686+
pdu_data = (struct pdu_data *)node_rx->pdu_data;
1687+
1688+
if (node_rx->hdr.type != NODE_RX_TYPE_DC_PDU) {
1689+
1690+
switch (node_rx->hdr.type) {
1691+
case NODE_RX_TYPE_REPORT:
1692+
#if defined(CONFIG_BLUETOOTH_CONTROLLER_ADV_INDICATION)
1693+
case NODE_RX_TYPE_ADV_INDICATION:
1694+
#endif
1695+
#if defined(CONFIG_BLUETOOTH_CONTROLLER_PROFILE_ISR)
1696+
case NODE_RX_TYPE_PROFILE:
1697+
#endif
1698+
return HCI_CLASS_EVT_DISCARDABLE;
1699+
case NODE_RX_TYPE_CONNECTION:
1700+
return HCI_CLASS_EVT_REQUIRED;
1701+
case NODE_RX_TYPE_TERMINATE:
1702+
case NODE_RX_TYPE_CONN_UPDATE:
1703+
case NODE_RX_TYPE_ENC_REFRESH:
1704+
#if defined(CONFIG_BLUETOOTH_CONTROLLER_CONN_RSSI)
1705+
case NODE_RX_TYPE_RSSI:
1706+
#endif
1707+
#if defined(CONFIG_BLUETOOTH_CONTROLLER_LE_PING)
1708+
case NODE_RX_TYPE_APTO:
1709+
#endif
1710+
#if defined(CONFIG_BLUETOOTH_CONTROLLER_CHAN_SEL_2)
1711+
case NODE_RX_TYPE_CHAN_SEL_ALGO:
1712+
#endif
1713+
return HCI_CLASS_EVT_CONNECTION;
1714+
default:
1715+
return -1;
1716+
}
1717+
1718+
} else if (pdu_data->ll_id == PDU_DATA_LLID_CTRL) {
1719+
return HCI_CLASS_EVT_CONNECTION;
1720+
} else {
1721+
return HCI_CLASS_ACL_DATA;
1722+
}
1723+
}
1724+
1725+
void hci_init(struct k_poll_signal *signal_host_buf)
1726+
{
1727+
#if defined(CONFIG_BLUETOOTH_CONTROLLER_TO_HOST_FC)
1728+
hbuf_signal = signal_host_buf;
1729+
#endif
1730+
reset(NULL, NULL);
1731+
}

0 commit comments

Comments
 (0)