Bluetooth: Split buffers into separate pools
In order to do proper flow control of ACL data to/from the controller we need to have precise management of the available buffers. Mixing with the events/commands buffers would make this impossible. This patch splits the buffer pools into three separate ones: 1. HCI commands/events 2. Incoming ACL data 3. Outgoing ACL data The total number of available buffers is also increased to match what's the smallest number supported by current controllers (to avoid the stack from becoming a bottle neck). Change-Id: I7e131d61c83a4dda554068d7917c5ee09f2f837d Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
parent
d829fe9755
commit
b6804df02e
3 changed files with 76 additions and 13 deletions
|
@ -91,7 +91,10 @@ size_t bt_buf_headroom(struct bt_buf *buf);
|
|||
/* Return pointer to the end of the data in the buffer */
|
||||
#define bt_buf_tail(buf) ((buf)->data + (buf)->len)
|
||||
|
||||
/* Initialize the buffers */
|
||||
void bt_buf_init(void);
|
||||
/* Initialize the buffers with specified amount of incoming and outgoing
|
||||
* ACL buffers. The HCI command and event buffers will be allocated from
|
||||
* whatever is left over.
|
||||
*/
|
||||
int bt_buf_init(int acl_in, int acl_out);
|
||||
|
||||
#endif /* __BT_BUF_H */
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include <nanokernel.h>
|
||||
#include <toolchain.h>
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <bluetooth/hci.h>
|
||||
|
@ -40,16 +41,36 @@
|
|||
|
||||
#include "hci_core.h"
|
||||
|
||||
/* Available (free) buffers queue */
|
||||
#define NUM_BUFS 5
|
||||
/* Total number of all types of buffers */
|
||||
#define NUM_BUFS 20
|
||||
static struct bt_buf buffers[NUM_BUFS];
|
||||
static struct nano_fifo free_bufs;
|
||||
|
||||
/* Available (free) buffers queues */
|
||||
static struct nano_fifo avail_hci;
|
||||
static struct nano_fifo avail_acl_in;
|
||||
static struct nano_fifo avail_acl_out;
|
||||
|
||||
static struct nano_fifo *get_avail(enum bt_buf_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case BT_CMD:
|
||||
case BT_EVT:
|
||||
return &avail_hci;
|
||||
case BT_ACL_IN:
|
||||
return &avail_acl_in;
|
||||
case BT_ACL_OUT:
|
||||
return &avail_acl_out;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct bt_buf *bt_buf_get(enum bt_buf_type type, size_t reserve_head)
|
||||
{
|
||||
struct nano_fifo *avail = get_avail(type);
|
||||
struct bt_buf *buf;
|
||||
|
||||
buf = nano_fifo_get(&free_bufs);
|
||||
buf = nano_fifo_get(avail);
|
||||
if (!buf) {
|
||||
BT_ERR("Failed to get free buffer\n");
|
||||
return NULL;
|
||||
|
@ -67,9 +88,11 @@ struct bt_buf *bt_buf_get(enum bt_buf_type type, size_t reserve_head)
|
|||
|
||||
void bt_buf_put(struct bt_buf *buf)
|
||||
{
|
||||
struct nano_fifo *avail = get_avail(buf->type);
|
||||
|
||||
BT_DBG("buf %p\n", buf);
|
||||
|
||||
nano_fifo_put(&free_bufs, buf);
|
||||
nano_fifo_put(avail, buf);
|
||||
}
|
||||
|
||||
uint8_t *bt_buf_add(struct bt_buf *buf, size_t len)
|
||||
|
@ -102,10 +125,30 @@ size_t bt_buf_tailroom(struct bt_buf *buf)
|
|||
return BT_BUF_MAX_DATA - bt_buf_headroom(buf) - buf->len;
|
||||
}
|
||||
|
||||
void bt_buf_init(void)
|
||||
int bt_buf_init(int acl_in, int acl_out)
|
||||
{
|
||||
nano_fifo_init(&free_bufs);
|
||||
int i;
|
||||
|
||||
for (int i = 0; i < NUM_BUFS; i++)
|
||||
nano_fifo_put(&free_bufs, &buffers[i]);
|
||||
/* Check that we have enough buffers configured */
|
||||
if (acl_out + acl_in >= NUM_BUFS - 2) {
|
||||
BT_ERR("Too many ACL buffers requested\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
BT_DBG("Available bufs: ACL in: %d, ACL out: %d, cmds/evts: %d\n",
|
||||
acl_in, acl_out, NUM_BUFS - (acl_in + acl_out));
|
||||
|
||||
nano_fifo_init(&avail_acl_in);
|
||||
for (i = 0; acl_in > 0; i++, acl_in--)
|
||||
nano_fifo_put(&avail_acl_in, &buffers[i]);
|
||||
|
||||
nano_fifo_init(&avail_acl_out);
|
||||
for (; acl_out > 0; i++, acl_out--)
|
||||
nano_fifo_put(&avail_acl_out, &buffers[i]);
|
||||
|
||||
nano_fifo_init(&avail_hci);
|
||||
for (; i < NUM_BUFS; i++)
|
||||
nano_fifo_put(&avail_hci, &buffers[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,10 @@
|
|||
#include "hci_core.h"
|
||||
#include "conn.h"
|
||||
|
||||
/* How many buffers to use for incoming ACL data */
|
||||
#define ACL_IN_MAX 7
|
||||
#define ACL_OUT_MAX 7
|
||||
|
||||
/* Stacks for the fibers */
|
||||
#define RX_STACK_SIZE 1024
|
||||
#define CMD_STACK_SIZE 256
|
||||
|
@ -623,12 +627,15 @@ static void rx_queue_init(void)
|
|||
int bt_init(void)
|
||||
{
|
||||
struct bt_driver *drv = dev.drv;
|
||||
int acl_out;
|
||||
int err;
|
||||
|
||||
if (!drv)
|
||||
return -ENODEV;
|
||||
|
||||
bt_buf_init();
|
||||
/* Initialize buffers with zero ACL for starters */
|
||||
bt_buf_init(0, 0);
|
||||
|
||||
cmd_queue_init();
|
||||
rx_queue_init();
|
||||
|
||||
|
@ -636,7 +643,17 @@ int bt_init(void)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
return hci_init();
|
||||
err = hci_init();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Re-initialize buffers now that we know the ACL counts */
|
||||
if (dev.le_pkts > ACL_OUT_MAX)
|
||||
acl_out = ACL_OUT_MAX;
|
||||
else
|
||||
acl_out = dev.le_pkts;
|
||||
|
||||
return bt_buf_init(ACL_IN_MAX, acl_out);
|
||||
}
|
||||
|
||||
int bt_start_advertising(uint8_t type, const char *name, uint8_t name_len)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue