Bluetooth: Initial conversion to net_buf API

This patch performs the minimal necessary conversion to the net_buf
API. It uses a temporary "#define bt_buf net_buf" to make it possible
to convert the code in smaller increments. Most old bt_buf function
also serve as one-line wrappers to the matching net_buf APIs. Once
everything is converted these helpers will be removed.

Change-Id: Ie31433d33576022c9c193a35d2389267005545d6
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2015-10-28 10:20:43 +02:00 committed by Anas Nashif
parent c1f007687f
commit 581fa90ea8
4 changed files with 141 additions and 246 deletions

View file

@ -218,27 +218,28 @@ static void uart_out(struct device *dev, const uint8_t *data, int size)
static int bt_uart_send(struct bt_buf *buf)
{
uint8_t *type;
uint8_t *h4_type, *buf_type;
if (bt_buf_headroom(buf) < H4_HEADER_SIZE) {
BT_ERR("Not enough headroom in buffer\n");
return -EINVAL;
}
type = bt_buf_push(buf, 1);
h4_type = bt_buf_push(buf, 1);
buf_type = net_buf_user_data(buf);
switch (buf->type) {
switch (*buf_type) {
case BT_CMD:
*type = H4_CMD;
*h4_type = H4_CMD;
break;
case BT_ACL_OUT:
*type = H4_ACL;
*h4_type = H4_ACL;
break;
case BT_EVT:
*type = H4_EVT;
*h4_type = H4_EVT;
break;
default:
BT_ERR("Unknown buf type %u\n", buf->type);
BT_ERR("Unknown buf type %u\n", *buf_type);
return -EINVAL;
}

View file

@ -22,6 +22,7 @@
#include <stddef.h>
#include <stdint.h>
#include <net/buf.h>
/** @def BT_BUF_MAX_DATA
* @brief Maximum amount of data that can fit in a buffer.
@ -34,7 +35,9 @@
*/
#define BT_BUF_MAX_DATA 74
/** Type of data contained in a buffer */
#define BT_BUF_ACL_IN_MAX 7
#define BT_BUF_ACL_OUT_MAX 7
enum bt_buf_type {
BT_CMD, /** HCI command */
BT_EVT, /** HCI event */
@ -43,44 +46,30 @@ enum bt_buf_type {
BT_DUMMY = BT_CMD, /** Only used for waking up fibers */
};
/** HCI command specific information */
struct bt_buf_hci_data {
struct bt_hci_data {
/** Type of data contained in a buffer (bt_buf_type) */
uint8_t type;
/** The command OpCode that the buffer contains */
uint16_t opcode;
/** Used by bt_hci_cmd_send_sync. Initially contains the waiting
* semaphore, as the semaphore is given back contains the bt_buf
* for the return parameters.
*/
void *sync;
/** The command OpCode that the buffer contains */
uint16_t opcode;
};
struct bt_acl_data {
/** Type of data contained in a buffer (bt_buf_type) */
uint8_t type;
/** ACL data buffer specific information */
struct bt_buf_acl_data {
/** ACL connection handle */
uint16_t handle;
};
struct bt_buf {
/** FIFO uses first 4 bytes itself, reserve space */
int __unused;
union {
struct bt_buf_hci_data hci;
struct bt_buf_acl_data acl;
};
/** Pointer to the start of data in the buffer. */
uint8_t *data;
/** Length of the data behind the data pointer. */
uint8_t len;
uint8_t ref:5, /** Reference count */
type:3; /** Type of data contained in the buffer */
/** The full available buffer. */
uint8_t buf[BT_BUF_MAX_DATA];
};
/* Temporary define to ease porting */
#define bt_buf net_buf
/** @brief Get a new buffer from the pool.
*
@ -210,19 +199,14 @@ size_t bt_buf_headroom(struct bt_buf *buf);
*
* @return Tail pointer for the buffer.
*/
#define bt_buf_tail(buf) ((buf)->data + (buf)->len)
void *bt_buf_tail(struct bt_buf *buf);
/** @brief Initialize buffer handling.
*
* 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.
*
* @param acl_in Number of incoming ACL data buffers.
* @param acl_out Number of outgoing ACL data buffers.
* Initialize the HCI and ACL buffers.
*
* @return Zero on success or (negative) error code on failure.
*/
int bt_buf_init(int acl_in, int acl_out);
int bt_buf_init(void);
#endif /* __BT_BUF_H */

View file

@ -36,84 +36,21 @@
#define BT_DBG(fmt, ...)
#endif
/* Total number of all types of buffers */
#if defined(CONFIG_BLUETOOTH_CONN)
#define NUM_BUFS 22
#else
#define NUM_BUFS 8
#endif /* CONFIG_BLUETOOTH_CONN */
static struct bt_buf buffers[NUM_BUFS];
/* Available (free) buffers queues */
static struct nano_fifo avail_hci;
static NET_BUF_POOL(hci_pool, 8, BT_BUF_MAX_DATA, &avail_hci, NULL,
sizeof(struct bt_hci_data));
#if defined(CONFIG_BLUETOOTH_CONN)
static struct nano_fifo avail_acl_in;
static struct nano_fifo avail_acl_out;
#endif /* CONFIG_BLUETOOTH_CONN */
static struct nano_fifo *get_avail(enum bt_buf_type type)
{
switch (type) {
case BT_CMD:
case BT_EVT:
return &avail_hci;
#if defined(CONFIG_BLUETOOTH_CONN)
case BT_ACL_IN:
return &avail_acl_in;
case BT_ACL_OUT:
return &avail_acl_out;
#endif /* CONFIG_BLUETOOTH_CONN */
default:
return NULL;
}
}
struct bt_buf *bt_buf_get(enum bt_buf_type type, size_t reserve_head)
{
struct nano_fifo *avail;
struct bt_buf *buf;
BT_DBG("type %d reserve %u\n", type, reserve_head);
avail = get_avail(type);
if (!avail) {
return NULL;
}
buf = nano_fifo_get(avail);
if (!buf) {
if (sys_execution_context_type_get() == NANO_CTX_ISR) {
BT_ERR("Failed to get free buffer\n");
return NULL;
}
BT_WARN("Low on buffers. Waiting (type %d)\n", type);
buf = nano_fifo_get_wait(avail);
}
memset(buf, 0, sizeof(*buf));
buf->ref = 1;
buf->type = type;
buf->data = buf->buf + reserve_head;
BT_DBG("buf %p type %d reserve %u\n", buf, buf->type, reserve_head);
return buf;
}
#if defined(CONFIG_BLUETOOTH_CONN)
static void report_completed_packet(struct bt_buf *buf)
static void report_completed_packet(struct net_buf *buf)
{
struct bt_acl_data *acl = net_buf_user_data(buf);
struct bt_hci_cp_host_num_completed_packets *cp;
struct bt_hci_handle_count *hc;
uint16_t handle;
handle = buf->acl.handle;
nano_fifo_put(&avail_acl_in, buf);
handle = acl->handle;
BT_DBG("Reporting completed packet for handle %u\n", handle);
@ -127,155 +64,114 @@ static void report_completed_packet(struct bt_buf *buf)
cp = bt_buf_add(buf, sizeof(*cp));
cp->num_handles = sys_cpu_to_le16(1);
hc = bt_buf_add(buf, sizeof(*hc));
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);
}
static struct nano_fifo avail_acl_in;
static struct nano_fifo avail_acl_out;
static NET_BUF_POOL(acl_in_pool, BT_BUF_ACL_IN_MAX, BT_BUF_MAX_DATA,
&avail_acl_in, report_completed_packet,
sizeof(struct bt_acl_data));
static NET_BUF_POOL(acl_out_pool, BT_BUF_ACL_OUT_MAX, BT_BUF_MAX_DATA,
&avail_acl_out, NULL, sizeof(struct bt_acl_data));
#endif /* CONFIG_BLUETOOTH_CONN */
struct bt_buf *bt_buf_get(enum bt_buf_type type, size_t reserve_head)
{
struct net_buf *buf;
switch (type) {
case BT_CMD:
case BT_EVT:
buf = net_buf_get(&avail_hci, reserve_head);
break;
#if defined(CONFIG_BLUETOOTH_CONN)
case BT_ACL_IN:
buf = net_buf_get(&avail_acl_in, reserve_head);
break;
case BT_ACL_OUT:
buf = net_buf_get(&avail_acl_out, reserve_head);
break;
#endif /* CONFIG_BLUETOOTH_CONN */
default:
return NULL;
}
if (buf) {
uint8_t *buf_type = net_buf_user_data(buf);
*buf_type = type;
}
return buf;
}
void bt_buf_put(struct bt_buf *buf)
{
struct nano_fifo *avail = get_avail(buf->type);
BT_DBG("buf %p ref %u type %d\n", buf, buf->ref, buf->type);
if (--buf->ref) {
return;
}
#if defined(CONFIG_BLUETOOTH_CONN)
if (avail == &avail_acl_in) {
report_completed_packet(buf);
return;
}
#endif /* CONFIG_BLUETOOTH_CONN */
/* Even if connection support is disabled avail shall always be not
* null. It is required to first get bt_buf with specific type to be
* able to put it. If connection support is disabled get returns NULL.
*/
BT_ASSERT(avail);
nano_fifo_put(avail, buf);
net_buf_unref(buf);
}
struct bt_buf *bt_buf_hold(struct bt_buf *buf)
{
BT_DBG("buf %p (old) ref %u type %d\n", buf, buf->ref, buf->type);
buf->ref++;
return buf;
return net_buf_ref(buf);
}
struct bt_buf *bt_buf_clone(struct bt_buf *buf)
{
struct bt_buf *clone;
clone = bt_buf_get(buf->type, bt_buf_headroom(buf));
if (!clone) {
return NULL;
}
/* TODO: Add reference to the original buffer instead of copying it. */
memcpy(bt_buf_add(clone, buf->len), buf->data, buf->len);
return clone;
return net_buf_clone(buf);
}
void *bt_buf_add(struct bt_buf *buf, size_t len)
{
uint8_t *tail = bt_buf_tail(buf);
BT_DBG("buf %p len %u\n", buf, len);
BT_ASSERT(bt_buf_tailroom(buf) >= len);
buf->len += len;
return tail;
return net_buf_add(buf, len);
}
void bt_buf_add_le16(struct bt_buf *buf, uint16_t value)
{
BT_DBG("buf %p value %u\n", buf, value);
value = sys_cpu_to_le16(value);
memcpy(bt_buf_add(buf, sizeof(value)), &value, sizeof(value));
net_buf_add_le16(buf, value);
}
void *bt_buf_push(struct bt_buf *buf, size_t len)
{
BT_DBG("buf %p len %u\n", buf, len);
BT_ASSERT(bt_buf_headroom(buf) >= len);
buf->data -= len;
buf->len += len;
return buf->data;
return net_buf_push(buf, len);
}
void *bt_buf_pull(struct bt_buf *buf, size_t len)
{
BT_DBG("buf %p len %u\n", buf, len);
BT_ASSERT(buf->len >= len);
buf->len -= len;
return buf->data += len;
return net_buf_pull(buf, len);
}
uint16_t bt_buf_pull_le16(struct bt_buf *buf)
{
uint16_t value;
value = UNALIGNED_GET((uint16_t *)buf->data);
bt_buf_pull(buf, sizeof(value));
return sys_le16_to_cpu(value);
return net_buf_pull_le16(buf);
}
size_t bt_buf_headroom(struct bt_buf *buf)
{
return buf->data - buf->buf;
return net_buf_headroom(buf);
}
size_t bt_buf_tailroom(struct bt_buf *buf)
{
return BT_BUF_MAX_DATA - bt_buf_headroom(buf) - buf->len;
return net_buf_tailroom(buf);
}
int bt_buf_init(int acl_in, int acl_out)
void *bt_buf_tail(struct bt_buf *buf)
{
int i = 0;
/* 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));
return net_buf_tail(buf);
}
int bt_buf_init(void)
{
#if defined(CONFIG_BLUETOOTH_CONN)
nano_fifo_init(&avail_acl_in);
for (; 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]);
}
net_buf_pool_init(acl_in_pool);
net_buf_pool_init(acl_out_pool);
#endif /* CONFIG_BLUETOOTH_CONN */
nano_fifo_init(&avail_hci);
for (; i < NUM_BUFS; i++) {
nano_fifo_put(&avail_hci, &buffers[i]);
}
BT_DBG("%u buffers * %u bytes = %u bytes\n", NUM_BUFS,
sizeof(buffers[0]), sizeof(buffers));
net_buf_pool_init(hci_pool);
return 0;
}

View file

@ -45,15 +45,6 @@
#define BT_DBG(fmt, ...)
#endif
/* How many buffers to use for incoming ACL data */
#if defined(CONFIG_BLUETOOTH_CONN)
#define ACL_IN_MAX 7
#define ACL_OUT_MAX 7
#else
#define ACL_IN_MAX 0
#define ACL_OUT_MAX 0
#endif /* CONFIG_BLUETOOTH_CONN */
/* Stacks for the fibers */
static BT_STACK_NOINIT(rx_fiber_stack, 1024);
static BT_STACK_NOINIT(rx_prio_fiber_stack, 256);
@ -98,6 +89,7 @@ const char *bt_addr_le_str(const bt_addr_le_t *addr)
struct bt_buf *bt_hci_cmd_create(uint16_t opcode, uint8_t param_len)
{
struct bt_hci_cmd_hdr *hdr;
struct bt_hci_data *hci;
struct bt_buf *buf;
BT_DBG("opcode %x param_len %u\n", opcode, param_len);
@ -110,8 +102,9 @@ struct bt_buf *bt_hci_cmd_create(uint16_t opcode, uint8_t param_len)
BT_DBG("buf %p\n", buf);
buf->hci.opcode = opcode;
buf->hci.sync = NULL;
hci = net_buf_user_data(buf);
hci->opcode = opcode;
hci->sync = NULL;
hdr = bt_buf_add(buf, sizeof(*hdr));
hdr->opcode = sys_cpu_to_le16(opcode);
@ -156,6 +149,7 @@ int bt_hci_cmd_send_sync(uint16_t opcode, struct bt_buf *buf,
struct bt_buf **rsp)
{
struct nano_sem sync_sem;
struct bt_hci_data *hci;
int err;
/* This function cannot be called from the rx fiber since it
@ -179,23 +173,24 @@ int bt_hci_cmd_send_sync(uint16_t opcode, struct bt_buf *buf,
BT_DBG("opcode %x len %u\n", opcode, buf->len);
nano_sem_init(&sync_sem);
buf->hci.sync = &sync_sem;
hci = net_buf_user_data(buf);
hci->sync = &sync_sem;
nano_fifo_put(&bt_dev.cmd_tx_queue, buf);
nano_sem_take_wait(&sync_sem);
/* Indicate failure if we failed to get the return parameters */
if (!buf->hci.sync) {
if (!hci->sync) {
err = -EIO;
} else {
err = 0;
}
if (rsp) {
*rsp = buf->hci.sync;
} else if (buf->hci.sync) {
bt_buf_put(buf->hci.sync);
*rsp = hci->sync;
} else if (hci->sync) {
bt_buf_put(hci->sync);
}
bt_buf_put(buf);
@ -260,6 +255,7 @@ static void hci_acl(struct bt_buf *buf)
{
struct bt_hci_acl_hdr *hdr = (void *)buf->data;
uint16_t handle, len = sys_le16_to_cpu(hdr->len);
struct bt_acl_data *acl;
struct bt_conn *conn;
uint8_t flags;
@ -267,11 +263,13 @@ static void hci_acl(struct bt_buf *buf)
handle = sys_le16_to_cpu(hdr->handle);
flags = (handle >> 12);
buf->acl.handle = bt_acl_handle(handle);
acl = net_buf_user_data(buf);
acl->handle = bt_acl_handle(handle);
bt_buf_pull(buf, sizeof(*hdr));
BT_DBG("handle %u len %u flags %u\n", buf->acl.handle, len, flags);
BT_DBG("handle %u len %u flags %u\n", acl->handle, len, flags);
if (buf->len != len) {
BT_ERR("ACL data length mismatch (%u != %u)\n", buf->len, len);
@ -279,9 +277,9 @@ static void hci_acl(struct bt_buf *buf)
return;
}
conn = bt_conn_lookup_handle(buf->acl.handle);
conn = bt_conn_lookup_handle(acl->handle);
if (!conn) {
BT_ERR("Unable to find conn for handle %u\n", buf->acl.handle);
BT_ERR("Unable to find conn for handle %u\n", acl->handle);
bt_buf_put(buf);
return;
}
@ -687,7 +685,7 @@ static int set_flow_control(void)
hbs->acl_mtu = sys_cpu_to_le16(BT_BUF_MAX_DATA -
sizeof(struct bt_hci_acl_hdr) -
bt_dev.drv->head_reserve);
hbs->acl_pkts = sys_cpu_to_le16(ACL_IN_MAX);
hbs->acl_pkts = sys_cpu_to_le16(BT_BUF_ACL_IN_MAX);
err = bt_hci_cmd_send(BT_HCI_OP_HOST_BUFFER_SIZE, buf);
if (err) {
@ -868,13 +866,15 @@ static void hci_reset_complete(struct bt_buf *buf)
static void hci_cmd_done(uint16_t opcode, uint8_t status, struct bt_buf *buf)
{
struct bt_hci_data *hci;
struct bt_buf *sent = bt_dev.sent_cmd;
if (!sent) {
return;
}
if (bt_dev.sent_cmd->hci.opcode != opcode) {
hci = net_buf_user_data(sent);
if (hci->opcode != opcode) {
BT_ERR("Unexpected completion of opcode 0x%04x\n", opcode);
return;
}
@ -882,13 +882,13 @@ static void hci_cmd_done(uint16_t opcode, uint8_t status, struct bt_buf *buf)
bt_dev.sent_cmd = NULL;
/* If the command was synchronous wake up bt_hci_cmd_send_sync() */
if (sent->hci.sync) {
struct nano_sem *sem = sent->hci.sync;
if (hci->sync) {
struct nano_sem *sem = hci->sync;
if (status) {
sent->hci.sync = NULL;
hci->sync = NULL;
} else {
sent->hci.sync = bt_buf_hold(buf);
hci->sync = bt_buf_hold(buf);
}
nano_fiber_sem_give(sem);
@ -1173,8 +1173,14 @@ static void hci_cmd_tx_fiber(void)
bt_dev.sent_cmd = NULL;
}
BT_DBG("Sending command %x (buf %p) to driver\n",
buf->hci.opcode, buf);
#if defined(CONFIG_BLUETOOTH_DEBUG_HCI_CORE)
{
struct bt_hci_data *hci = net_buf_user_data(buf);
BT_DBG("Sending command %x (buf %p) to driver\n",
hci->opcode, buf);
}
#endif /* CONFIG_BLUETOOTH_DEBUG_HCI_CORE */
err = drv->send(buf);
if (err) {
@ -1200,14 +1206,17 @@ static void rx_prio_fiber(void)
while (1) {
struct bt_hci_evt_hdr *hdr;
uint8_t *type;
BT_DBG("calling fifo_get_wait\n");
buf = nano_fifo_get_wait(&bt_dev.rx_prio_queue);
BT_DBG("buf %p type %u len %u\n", buf, buf->type, buf->len);
type = net_buf_user_data(buf);
if (buf->type != BT_EVT) {
BT_ERR("Unknown buf type %u\n", buf->type);
BT_DBG("buf %p type %u len %u\n", buf, *type, buf->len);
if (*type != BT_EVT) {
BT_ERR("Unknown buf type %u\n", *type);
bt_buf_put(buf);
continue;
}
@ -1440,17 +1449,18 @@ static int hci_init(void)
void bt_recv(struct bt_buf *buf)
{
uint8_t *type = net_buf_user_data(buf);
struct bt_hci_evt_hdr *hdr;
BT_DBG("buf %p len %u\n", buf, buf->len);
if (buf->type == BT_ACL_IN) {
if (*type == BT_ACL_IN) {
nano_fifo_put(&bt_dev.rx_queue, buf);
return;
}
if (buf->type != BT_EVT) {
BT_ERR("Invalid buf type %u\n", buf->type);
if (*type != BT_EVT) {
BT_ERR("Invalid buf type %u\n", *type);
bt_buf_put(buf);
return;
}
@ -1522,12 +1532,16 @@ static void hci_rx_fiber(bt_ready_cb_t ready_cb)
}
while (1) {
uint8_t *type;
BT_DBG("calling fifo_get_wait\n");
buf = nano_fifo_get_wait(&bt_dev.rx_queue);
BT_DBG("buf %p type %u len %u\n", buf, buf->type, buf->len);
type = net_buf_user_data(buf);
switch (buf->type) {
BT_DBG("buf %p type %u len %u\n", buf, *type, buf->len);
switch (*type) {
#if defined(CONFIG_BLUETOOTH_CONN)
case BT_ACL_IN:
hci_acl(buf);
@ -1537,7 +1551,7 @@ static void hci_rx_fiber(bt_ready_cb_t ready_cb)
hci_event(buf);
break;
default:
BT_ERR("Unknown buf type %u\n", buf->type);
BT_ERR("Unknown buf type %u\n", *type);
bt_buf_put(buf);
break;
}
@ -1552,7 +1566,7 @@ int bt_enable(bt_ready_cb_t cb)
return -ENODEV;
}
bt_buf_init(ACL_IN_MAX, ACL_OUT_MAX);
bt_buf_init();
/* Give cmd_sem allowing to send first HCI_Reset cmd */
bt_dev.ncmd = 1;