Bluetooth: (Re)introduce ACL host flow control

This feature was removed some time ago, but turns out it's important
to have it available for split host-controller setups.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2017-05-04 14:09:10 +03:00 committed by Johan Hedberg
commit b484c1eeed
5 changed files with 143 additions and 0 deletions

View file

@ -103,6 +103,36 @@ config BLUETOOTH_INTERNAL_STORAGE
an internal default handler is used for this.
if BLUETOOTH_CONN
config BLUETOOTH_HOST_FLOW_CONTROL
bool "Controller to Host ACL flow control support"
default n
default y if !BLUETOOTH_CONTROLLER
help
Enable support for throttling ACL buffers from the controller
to the host. This is particularly useful when the host and
controller are on separate cores since it ensures that we do
not run out of incoming ACL buffers.
if BLUETOOTH_HOST_FLOW_CONTROL
config BLUETOOTH_ACL_RX_COUNT
int "Number of incoming ACL data buffers"
default 6
default BLUETOOTH_CONTROLLER_RX_BUFFERS if BLUETOOTH_CONTROLLER
range 2 64
help
Number of buffers available for incoming ACL data.
config BLUETOOTH_L2CAP_RX_MTU
int "Maximum supported L2CAP MTU for incoming data"
default 23
default 65 if BLUETOOTH_SMP
default 200 if BLUETOOTH_BREDR
range 23 1300
range 65 1300 if BLUETOOTH_SMP
help
Maximum size of each incoming L2CAP PDU.
endif # BLUETOOTH_HOST_FLOW_CONTROL
config BLUETOOTH_L2CAP_TX_BUF_COUNT
int "Number of L2CAP TX buffers"
default 3
@ -399,8 +429,10 @@ config BLUETOOTH_RFCOMM
config BLUETOOTH_RFCOMM_L2CAP_MTU
int "L2CAP MTU for RFCOMM frames"
default BLUETOOTH_RX_BUF_LEN
default BLUETOOTH_L2CAP_RX_MTU if BLUETOOTH_HOST_FLOW_CONTROL
depends on BLUETOOTH_RFCOMM
range BLUETOOTH_RX_BUF_LEN 32767
range BLUETOOTH_L2CAP_RX_MTU 32767 if BLUETOOTH_HOST_FLOW_CONTROL
help
Maximum size of L2CAP PDU for RFCOMM frames.

View file

@ -23,6 +23,7 @@
#include <bluetooth/log.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>
#include <bluetooth/l2cap.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_driver.h>
#include <bluetooth/storage.h>
@ -124,6 +125,45 @@ NET_BUF_POOL_DEFINE(hci_cmd_pool, CONFIG_BLUETOOTH_HCI_CMD_COUNT,
NET_BUF_POOL_DEFINE(hci_rx_pool, CONFIG_BLUETOOTH_RX_BUF_COUNT,
BT_BUF_RX_SIZE, BT_BUF_USER_DATA_MIN, NULL);
#if defined(CONFIG_BLUETOOTH_HOST_FLOW_CONTROL)
static void report_completed_packet(struct net_buf *buf)
{
struct bt_hci_cp_host_num_completed_packets *cp;
u16_t handle = acl(buf)->handle;
struct bt_hci_handle_count *hc;
net_buf_destroy(buf);
/* Do nothing if controller to host flow control is not supported */
if (!(bt_dev.supported_commands[10] & 0x20)) {
return;
}
BT_DBG("Reporting completed packet for handle %u", handle);
buf = bt_hci_cmd_create(BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS,
sizeof(*cp) + sizeof(*hc));
if (!buf) {
BT_ERR("Unable to allocate new HCI command");
return;
}
cp = net_buf_add(buf, sizeof(*cp));
cp->num_handles = sys_cpu_to_le16(1);
hc = net_buf_add(buf, sizeof(*hc));
hc->handle = sys_cpu_to_le16(handle);
hc->count = sys_cpu_to_le16(1);
bt_hci_cmd_send(BT_HCI_OP_HOST_NUM_COMPLETED_PACKETS, buf);
}
#define ACL_IN_SIZE BT_L2CAP_BUF_SIZE(CONFIG_BLUETOOTH_L2CAP_RX_MTU)
NET_BUF_POOL_DEFINE(acl_in_pool, CONFIG_BLUETOOTH_ACL_RX_COUNT, ACL_IN_SIZE,
BT_BUF_USER_DATA_MIN, report_completed_packet);
#endif /* CONFIG_BLUETOOTH_HOST_FLOW_CONTROL */
#if defined(CONFIG_BLUETOOTH_DEBUG)
const char *bt_addr_str(const bt_addr_t *addr)
{
@ -973,6 +1013,46 @@ failed:
bt_conn_unref(conn);
bt_le_scan_update(false);
}
#if defined(CONFIG_BLUETOOTH_HOST_FLOW_CONTROL)
static int set_flow_control(void)
{
struct bt_hci_cp_host_buffer_size *hbs;
struct net_buf *buf;
int err;
/* Check if host flow control is actually supported */
if (!(bt_dev.supported_commands[10] & 0x20)) {
BT_WARN("Controller to host flow control not supported");
return 0;
}
buf = bt_hci_cmd_create(BT_HCI_OP_HOST_BUFFER_SIZE,
sizeof(*hbs));
if (!buf) {
return -ENOBUFS;
}
hbs = net_buf_add(buf, sizeof(*hbs));
memset(hbs, 0, sizeof(*hbs));
hbs->acl_mtu = sys_cpu_to_le16(CONFIG_BLUETOOTH_L2CAP_RX_MTU +
sizeof(struct bt_l2cap_hdr));
hbs->acl_pkts = sys_cpu_to_le16(CONFIG_BLUETOOTH_ACL_RX_COUNT);
err = bt_hci_cmd_send_sync(BT_HCI_OP_HOST_BUFFER_SIZE, buf, NULL);
if (err) {
return err;
}
buf = bt_hci_cmd_create(BT_HCI_OP_SET_CTL_TO_HOST_FLOW, 1);
if (!buf) {
return -ENOBUFS;
}
net_buf_add_u8(buf, BT_HCI_CTL_TO_HOST_FLOW_ENABLE);
return bt_hci_cmd_send_sync(BT_HCI_OP_SET_CTL_TO_HOST_FLOW, buf, NULL);
}
#endif /* CONFIG_BLUETOOTH_HOST_FLOW_CONTROL */
#endif /* CONFIG_BLUETOOTH_CONN */
#if defined(CONFIG_BLUETOOTH_BREDR)
@ -2990,6 +3070,13 @@ static int common_init(void)
read_supported_commands_complete(rsp);
net_buf_unref(rsp);
#if defined(CONFIG_BLUETOOTH_HOST_FLOW_CONTROL)
err = set_flow_control();
if (err) {
return err;
}
#endif /* CONFIG_BLUETOOTH_CONN */
return 0;
}
@ -4108,7 +4195,16 @@ struct net_buf *bt_buf_get_rx(enum bt_buf_type type, s32_t timeout)
__ASSERT(type == BT_BUF_EVT || type == BT_BUF_ACL_IN,
"Invalid buffer type requested");
#if defined(CONFIG_BLUETOOTH_HOST_FLOW_CONTROL)
if (type == BT_BUF_EVT) {
buf = net_buf_alloc(&hci_rx_pool, timeout);
} else {
buf = net_buf_alloc(&acl_in_pool, timeout);
}
#else
buf = net_buf_alloc(&hci_rx_pool, timeout);
#endif
if (buf) {
net_buf_reserve(buf, CONFIG_BLUETOOTH_HCI_RESERVE);
bt_buf_set_type(buf, type);

View file

@ -27,7 +27,13 @@
#define LE_CHAN_RTX(_w) CONTAINER_OF(_w, struct bt_l2cap_le_chan, chan.rtx_work)
#define L2CAP_LE_MIN_MTU 23
#if defined(CONFIG_BLUETOOTH_HOST_FLOW_CONTROL)
#define L2CAP_LE_MAX_CREDITS (CONFIG_BLUETOOTH_ACL_RX_COUNT - 1)
#else
#define L2CAP_LE_MAX_CREDITS (CONFIG_BLUETOOTH_RX_BUF_COUNT - 1)
#endif
#define L2CAP_LE_CREDITS_THRESHOLD(_creds) (_creds / 2)
#define L2CAP_LE_CID_DYN_START 0x0040

View file

@ -192,8 +192,12 @@ struct bt_l2cap_le_credits {
#define BT_L2CAP_SDU_HDR_LEN 2
#if defined(CONFIG_BLUETOOTH_HOST_FLOW_CONTROL)
#define BT_L2CAP_RX_MTU CONFIG_BLUETOOTH_L2CAP_RX_MTU
#else
#define BT_L2CAP_RX_MTU (CONFIG_BLUETOOTH_RX_BUF_LEN - \
BT_HCI_ACL_HDR_SIZE - BT_L2CAP_HDR_SIZE)
#endif
struct bt_l2cap_fixed_chan {
u16_t cid;

View file

@ -34,7 +34,12 @@
#define RFCOMM_MIN_MTU BT_RFCOMM_SIG_MIN_MTU
#define RFCOMM_DEFAULT_MTU 127
#if defined(CONFIG_BLUETOOTH_HOST_FLOW_CONTROL)
#define RFCOMM_MAX_CREDITS (CONFIG_BLUETOOTH_ACL_RX_COUNT - 1)
#else
#define RFCOMM_MAX_CREDITS (CONFIG_BLUETOOTH_RX_BUF_COUNT - 1)
#endif
#define RFCOMM_CREDITS_THRESHOLD (RFCOMM_MAX_CREDITS / 2)
#define RFCOMM_DEFAULT_CREDIT RFCOMM_MAX_CREDITS