Bluetooth: Add dedicated stack for Command Complete/Status events

These events are special since they release any blocking
bt_hci_cmd_send_sync() calls. In order to be able to use the send_sync
API from HCI Event handlers without deadlocking having the Command
Complete/Status events processed through a dedicated fiber is
essential.

Change-Id: Id5c597d618bf326a8efb7c9ca2500af60a502d77
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
This commit is contained in:
Johan Hedberg 2015-05-23 19:58:06 +03:00 committed by Anas Nashif
commit d8e9e71acd
2 changed files with 80 additions and 14 deletions

View file

@ -57,19 +57,22 @@
/* Stacks for the fibers */
#if defined(CONFIG_BLUETOOTH_DEBUG)
#define RX_STACK_SIZE 2048
#define CMD_RX_STACK_SIZE 512
#define CMD_TX_STACK_SIZE 512
#else
#define RX_STACK_SIZE 1024
#define CMD_RX_STACK_SIZE 256
#define CMD_TX_STACK_SIZE 256
#endif
static const uint8_t BDADDR_ANY[6] = { 0, 0, 0, 0, 0 };
static char rx_fiber_stack[RX_STACK_SIZE];
static char cmd_rx_fiber_stack[CMD_RX_STACK_SIZE];
static char cmd_tx_fiber_stack[CMD_TX_STACK_SIZE];
#if defined(CONFIG_BLUETOOTH_DEBUG)
static nano_context_id_t rx_fiber_id;
static nano_context_id_t cmd_rx_fiber_id;
#endif
static struct bt_dev dev;
@ -202,7 +205,7 @@ int bt_hci_cmd_send_sync(uint16_t opcode, struct bt_buf *buf,
* event and giving back the blocking semaphore.
*/
#if defined(CONFIG_BLUETOOTH_DEBUG)
if (context_self_get() == rx_fiber_id) {
if (context_self_get() == cmd_rx_fiber_id) {
BT_ERR("called from invalid context!\n");
return -EDEADLK;
}
@ -592,12 +595,6 @@ static void hci_event(struct bt_buf *buf)
case BT_HCI_EVT_ENCRYPT_CHANGE:
hci_encrypt_change(buf);
break;
case BT_HCI_EVT_CMD_COMPLETE:
hci_cmd_complete(buf);
break;
case BT_HCI_EVT_CMD_STATUS:
hci_cmd_status(buf);
break;
case BT_HCI_EVT_NUM_COMPLETED_PACKETS:
hci_num_completed_packets(buf);
break;
@ -653,11 +650,6 @@ static void hci_rx_fiber(void)
BT_DBG("started\n");
/* So we can avoid bt_hci_cmd_send_sync deadlocks */
#if defined(CONFIG_BLUETOOTH_DEBUG)
rx_fiber_id = context_self_get();
#endif
while (1) {
BT_DBG("calling fifo_get_wait\n");
buf = nano_fifo_get_wait(&dev.rx_queue);
@ -680,6 +672,50 @@ static void hci_rx_fiber(void)
}
}
static void cmd_rx_fiber(void)
{
struct bt_buf *buf;
BT_DBG("started\n");
/* So we can avoid bt_hci_cmd_send_sync deadlocks */
#if defined(CONFIG_BLUETOOTH_DEBUG)
cmd_rx_fiber_id = context_self_get();
#endif
while (1) {
struct bt_hci_evt_hdr *hdr;
BT_DBG("calling fifo_get_wait\n");
buf = nano_fifo_get_wait(&dev.cmd_rx_queue);
BT_DBG("buf %p type %u len %u\n", buf, buf->type, buf->len);
if (buf->type != BT_EVT) {
BT_ERR("Unknown buf type %u\n", buf->type);
bt_buf_put(buf);
continue;
}
hdr = (void *)buf->data;
bt_buf_pull(buf, sizeof(*hdr));
switch (hdr->evt) {
case BT_HCI_EVT_CMD_COMPLETE:
hci_cmd_complete(buf);
break;
case BT_HCI_EVT_CMD_STATUS:
hci_cmd_status(buf);
break;
default:
BT_ERR("Unknown event 0x%02x\n", hdr->evt);
break;
}
bt_buf_put(buf);
}
}
static void read_local_features_complete(struct bt_buf *buf)
{
struct bt_hci_rp_read_local_features *rp = (void *)buf->data;
@ -907,7 +943,31 @@ int bt_hci_reset(void)
void bt_recv(struct bt_buf *buf)
{
struct bt_hci_evt_hdr *hdr;
BT_DBG("buf %p len %u\n", buf, buf->len);
if (buf->type == BT_ACL_IN) {
nano_fifo_put(&dev.rx_queue, buf);
return;
}
if (buf->type != BT_EVT) {
BT_ERR("Invalid buf type %u\n", buf->type);
bt_buf_put(buf);
return;
}
/* Command Complete/Status events have their own cmd_rx queue,
* all other events go through rx queue.
*/
hdr = (void *)buf->data;
if (hdr->evt == BT_HCI_EVT_CMD_COMPLETE ||
hdr->evt == BT_HCI_EVT_CMD_STATUS) {
nano_fifo_put(&dev.cmd_rx_queue, buf);
return;
}
nano_fifo_put(&dev.rx_queue, buf);
}
@ -949,9 +1009,12 @@ static void cmd_queue_init(void)
static void rx_queue_init(void)
{
nano_fifo_init(&dev.rx_queue);
fiber_start(rx_fiber_stack, RX_STACK_SIZE,
(nano_fiber_entry_t) hci_rx_fiber, 0, 0, 7, 0);
nano_fifo_init(&dev.cmd_rx_queue);
fiber_start(cmd_rx_fiber_stack, RX_STACK_SIZE,
(nano_fiber_entry_t) cmd_rx_fiber, 0, 0, 7, 0);
}
int bt_init(void)

View file

@ -71,6 +71,9 @@ struct bt_dev {
/* Queue for incoming HCI events & ACL data */
struct nano_fifo rx_queue;
/* Queue for incoming HCI Command Complete/Status events */
struct nano_fifo cmd_rx_queue;
/* Queue for outgoing HCI commands */
struct nano_fifo cmd_tx_queue;