Bluetooth: host: poll on CTLR buffers instead of host TX queue

When there are no buffers, it doesn't make sense to repeatedly try to send
the host TX queue.

Signed-off-by: Jonathan Rico <jonathan.rico@nordicsemi.no>
This commit is contained in:
Jonathan Rico 2022-11-15 12:05:50 +01:00 committed by Fabio Baltieri
commit ef19c64f1b
4 changed files with 31 additions and 7 deletions

View file

@ -513,7 +513,7 @@ static int send_frag(struct bt_conn *conn, struct net_buf *buf, uint8_t flags,
int err = 0; int err = 0;
/* Check if the controller can accept ACL packets */ /* Check if the controller can accept ACL packets */
if (k_sem_take(bt_conn_get_pkts(conn), K_MSEC(100))) { if (k_sem_take(bt_conn_get_pkts(conn), K_NO_WAIT)) {
/* not `goto fail`, we don't want to free the tx context: in the /* not `goto fail`, we don't want to free the tx context: in the
* case where it is the original buffer, it will contain the * case where it is the original buffer, it will contain the
* callback ptr. * callback ptr.
@ -776,10 +776,26 @@ static int conn_prepare_events(struct bt_conn *conn,
LOG_DBG("Adding conn %p to poll list", conn); LOG_DBG("Adding conn %p to poll list", conn);
k_poll_event_init(&events[0], bool buffers_available = k_sem_count_get(bt_conn_get_pkts(conn)) > 0;
K_POLL_TYPE_FIFO_DATA_AVAILABLE, bool packets_waiting = !k_fifo_is_empty(&conn->tx_queue);
K_POLL_MODE_NOTIFY_ONLY,
&conn->tx_queue); if (packets_waiting && !buffers_available) {
/* Only resume sending when the controller has buffer space
* available for this connection.
*/
LOG_DBG("wait on ctlr buffers");
k_poll_event_init(&events[0],
K_POLL_TYPE_SEM_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY,
bt_conn_get_pkts(conn));
} else {
/* Wait until there is more data to send. */
LOG_DBG("wait on host fifo");
k_poll_event_init(&events[0],
K_POLL_TYPE_FIFO_DATA_AVAILABLE,
K_POLL_MODE_NOTIFY_ONLY,
&conn->tx_queue);
}
events[0].tag = BT_EVENT_CONN_TX_QUEUE; events[0].tag = BT_EVENT_CONN_TX_QUEUE;
return 0; return 0;

View file

@ -2465,6 +2465,13 @@ static void process_events(struct k_poll_event *ev, int count)
switch (ev->state) { switch (ev->state) {
case K_POLL_STATE_SIGNALED: case K_POLL_STATE_SIGNALED:
break; break;
case K_POLL_STATE_SEM_AVAILABLE:
/* After this fn is exec'd, `bt_conn_prepare_events()`
* will be called once again, and this time buffers will
* be available, so the FIFO will be added to the poll
* list instead of the ctlr buffers semaphore.
*/
break;
case K_POLL_STATE_FIFO_DATA_AVAILABLE: case K_POLL_STATE_FIFO_DATA_AVAILABLE:
if (ev->tag == BT_EVENT_CMD_TX) { if (ev->tag == BT_EVENT_CMD_TX) {
send_cmd(); send_cmd();
@ -2524,6 +2531,7 @@ static void hci_tx_thread(void *p1, void *p2, void *p3)
events[0].state = K_POLL_STATE_NOT_READY; events[0].state = K_POLL_STATE_NOT_READY;
ev_count = 1; ev_count = 1;
/* This adds the FIFO per-connection */
if (IS_ENABLED(CONFIG_BT_CONN) || IS_ENABLED(CONFIG_BT_ISO)) { if (IS_ENABLED(CONFIG_BT_CONN) || IS_ENABLED(CONFIG_BT_ISO)) {
ev_count += bt_conn_prepare_events(&events[1]); ev_count += bt_conn_prepare_events(&events[1]);
} }

View file

@ -36,7 +36,7 @@ extern enum bst_result_t bst_result;
} }
#define WAIT_SECONDS 220 /* seconds */ #define WAIT_SECONDS 270 /* seconds */
#define WAIT_TIME (WAIT_SECONDS * USEC_PER_SEC) /* microseconds*/ #define WAIT_TIME (WAIT_SECONDS * USEC_PER_SEC) /* microseconds*/
#define FAIL(...) \ #define FAIL(...) \

View file

@ -35,7 +35,7 @@ Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=4 -testid=per
Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=5 -testid=peripheral -rs=230 Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=5 -testid=peripheral -rs=230
Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=6 -testid=peripheral -rs=9 Execute "${bsim_exe}" -v=${verbosity_level} -s=${simulation_id} -d=6 -testid=peripheral -rs=9
Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} -D=7 -sim_length=240e6 $@ Execute ./bs_2G4_phy_v1 -v=${verbosity_level} -s=${simulation_id} -D=7 -sim_length=270e6 $@
for process_id in $process_ids; do for process_id in $process_ids; do
wait $process_id || let "exit_code=$?" wait $process_id || let "exit_code=$?"