Skip to content

Commit

Permalink
Bluetooth: scan: Implement non-blocking ext-adv report reassembly
Browse files Browse the repository at this point in the history
Re-assemble the extended advertising reports into a dedicated buffer
pool and notify the application asynchronously.

To achieve this we:
- decompose the re-assembly function into fragmented and non-frag parts
- for reassembled reports: push any other info onto the reassembled buffer
- for non-frag reports: pass the raw event buffer directly
- put that buffer on a FIFO
- trigger a (sys)work item that pulls and calls the cb

The optimization for 80% of cases is kept: Processing non-fragmented
extended advertising reports will not double-copy: We add a buffer pool
similar to `sync_evt_pool` and apply the following algo:
- if report is non-frag & we have at least 1 buf available in pool
  -> ref() that buffer and put it on the FIFO directly
- else:
  -> allocate from re-assembly pool and copy into it

Note that we can only apply this optimization when we are processing the
last report in the event buffer.

Note to reviewers: The diff of this commit is garbage, you're probably
better of comparing with the previous implementation manually.

Signed-off-by: Jonathan Rico <jonathan.rico@nordicsemi.no>
Co-authored-by: Aleksander Wasaznik <aleksander.wasaznik@nordicsemi.no>
  • Loading branch information
jori-nordic and alwa-nordic committed Sep 27, 2024
1 parent 90d264b commit a07430c
Show file tree
Hide file tree
Showing 4 changed files with 364 additions and 135 deletions.
13 changes: 13 additions & 0 deletions subsys/bluetooth/host/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,19 @@ config BT_EXT_SCAN_BUF_SIZE
provided by the controller is larger than this buffer size,
the remaining data will be discarded.

config BT_EXT_SCAN_BUF_NUM
int "Maximum number of report reassembly buffers"
range 1 65535
default 2
help
Advertising reports can be fragmented when transmitted over HCI to the
Host. They are re-assembled into a dedicated buffer pool and the
application is notified asynchronously. This number governs the amount
of pending reassembled advertising reports.

Note that this option only uses up resources if extended advertising
is enabled.

endif # BT_OBSERVER

config BT_SCAN_WITH_IDENTITY
Expand Down
26 changes: 26 additions & 0 deletions subsys/bluetooth/host/buf.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,24 @@ static bool is_hci_event_discardable(const uint8_t evt_type, const uint8_t subev
}
}

NET_BUF_POOL_FIXED_DEFINE(sync_adv_pool, 2, SYNC_EVT_SIZE, sizeof(struct bt_buf_data), NULL);

/* This is a host-private function */
bool bt_buf_can_steal_ext_adv_report_buf(struct net_buf *buf)
{
if (net_buf_pool_get(buf->pool_id) != &sync_adv_pool) {
/* The driver did not use `bt_buf_get_evt_but_better` */
return false;
}

/* Host can steal the buffer if we have at least one available.
* This is the case when:
* - There are buffers in the `free` LIFO
* - There are un-initialized buffers
*/
return (!k_fifo_is_empty(&sync_adv_pool.free)) || (sync_adv_pool.uninit_count != 0);
}

struct net_buf *bt_buf_get_evt_but_better(uint8_t evt, uint8_t meta, k_timeout_t timeout)
{
/* Always allocs so-called "discardable" events with K_NO_WAIT. Most of
Expand All @@ -120,6 +138,13 @@ struct net_buf *bt_buf_get_evt_but_better(uint8_t evt, uint8_t meta, k_timeout_t
bool is_ext_adv = meta == BT_HCI_EVT_LE_EXT_ADVERTISING_REPORT;
bool is_meta = evt == BT_HCI_EVT_LE_META_EVENT;

if (is_ext_adv) {
buf = net_buf_alloc(&sync_adv_pool, timeout);
/* 60% of the time we get a buffer every time */
__ASSERT_NO_MSG(buf);
break;
}

if (is_meta && !is_ext_adv) {
/* For now we use the sync pool only for ext adv
* reports. They cannot be marked as discardable thanks
Expand All @@ -128,6 +153,7 @@ struct net_buf *bt_buf_get_evt_but_better(uint8_t evt, uint8_t meta, k_timeout_t
*/
break;
}

buf = net_buf_alloc(&sync_evt_pool, timeout);
break;
}
Expand Down
12 changes: 12 additions & 0 deletions subsys/bluetooth/host/hci_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -4070,6 +4070,18 @@ void hci_event_prio(struct net_buf *buf)
}
}

struct k_work_q *bt_get_rx_wq(void)
{
#if defined(CONFIG_BT_RECV_WORKQ_SYS)
return &k_sys_work_q;
#elif defined(CONFIG_BT_RECV_WORKQ_BT)
return &bt_workq;
#else
BUILD_ASSERT("config not supported");
return NULL;
#endif /* CONFIG_BT_RECV_WORKQ_SYS */
}

static void rx_queue_put(struct net_buf *buf)
{
net_buf_slist_put(&bt_dev.rx_queue, buf);
Expand Down
Loading

0 comments on commit a07430c

Please sign in to comment.