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:
parent
70e09b11ea
commit
b484c1eeed
5 changed files with 143 additions and 0 deletions
|
@ -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.
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue