Skip to content

Commit 43fc447

Browse files
PavelVPVcvinayak
authored andcommitted
bluetooth: buf: Add a callback for freed buffer in rx pool
The Bluetooth data buffer API currently lacks a mechanism to notify when a buffer is freed in the RX pool. This limitation forces HCI drivers to adopt inefficient workarounds to manage buffer allocation. HCI drivers face two suboptimal options: - Blocking calls: Use bt_buf_get_rx with K_FOREVER, which blocks the execution context until a buffer becomes available. - Polling: Repeatedly call bt_buf_get_rx with K_NO_WAIT, which increases CPU load and reduces efficiency. This commit introduces a callback mechanism that is triggered each time a buffer is freed in the RX pool. With this feature, HCI drivers can: - Call bt_buf_get_rx with K_NO_WAIT. - Wait for the callback notification if a NULL buffer is returned, avoiding unnecessary polling. The new callback improves efficiency by enabling event-driven behavior for buffer management, reducing CPU overhead while maintaining responsiveness. Signed-off-by: Pavel Vasilyev <[email protected]> (cherry picked from commit c2488fd) Signed-off-by: Vinayak Kariappa Chettimada <[email protected]>
1 parent 2c507e5 commit 43fc447

File tree

5 files changed

+130
-13
lines changed

5 files changed

+130
-13
lines changed

include/zephyr/bluetooth/buf.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,27 @@ BUILD_ASSERT(CONFIG_BT_BUF_EVT_RX_COUNT > CONFIG_BT_BUF_ACL_TX_COUNT,
146146
*/
147147
struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout);
148148

149+
/** A callback to notify about freed buffer in the incoming data pool.
150+
*
151+
* This callback is called when a buffer of a given type is freed and can be requested through the
152+
* @ref bt_buf_get_rx function. However, this callback is called from the context of the buffer
153+
* freeing operation and must not attempt to allocate a new buffer from the same pool.
154+
*
155+
* @warning When this callback is called, the scheduler is locked and the callee must not perform
156+
* any action that makes the current thread unready. This callback must only be used for very
157+
* short non-blocking operation (e.g. submitting a work item).
158+
*
159+
* @param type_mask A bit mask of buffer types that have been freed.
160+
*/
161+
typedef void (*bt_buf_rx_freed_cb_t)(enum bt_buf_type type_mask);
162+
163+
/** Set the callback to notify about freed buffer in the incoming data pool.
164+
*
165+
* @param cb Callback to notify about freed buffer in the incoming data pool. If NULL, the callback
166+
* is disabled.
167+
*/
168+
void bt_buf_rx_freed_cb_set(bt_buf_rx_freed_cb_t cb);
169+
149170
/** Allocate a buffer for outgoing data
150171
*
151172
* This will set the buffer type so bt_buf_set_type() does not need to

subsys/bluetooth/host/buf.c

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,26 @@
2222
*/
2323
#define SYNC_EVT_SIZE (BT_BUF_RESERVE + BT_HCI_EVT_HDR_SIZE + 255)
2424

25+
static bt_buf_rx_freed_cb_t buf_rx_freed_cb;
26+
27+
static void buf_rx_freed_notify(enum bt_buf_type mask)
28+
{
29+
k_sched_lock();
30+
31+
if (buf_rx_freed_cb) {
32+
buf_rx_freed_cb(mask);
33+
}
34+
35+
k_sched_unlock();
36+
}
37+
38+
#if defined(CONFIG_BT_ISO_RX)
39+
static void iso_rx_freed_cb(void)
40+
{
41+
buf_rx_freed_notify(BT_BUF_ISO_IN);
42+
}
43+
#endif
44+
2545
/* Pool for RX HCI buffers that are always freed by `bt_recv`
2646
* before it returns.
2747
*
@@ -37,17 +57,37 @@ NET_BUF_POOL_FIXED_DEFINE(discardable_pool, CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT,
3757
sizeof(struct bt_buf_data), NULL);
3858

3959
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
40-
NET_BUF_POOL_DEFINE(acl_in_pool, BT_BUF_ACL_RX_COUNT,
41-
BT_BUF_ACL_SIZE(CONFIG_BT_BUF_ACL_RX_SIZE),
42-
sizeof(struct acl_data), bt_hci_host_num_completed_packets);
60+
static void acl_in_pool_destroy(struct net_buf *buf)
61+
{
62+
bt_hci_host_num_completed_packets(buf);
63+
buf_rx_freed_notify(BT_BUF_ACL_IN);
64+
}
65+
66+
static void evt_pool_destroy(struct net_buf *buf)
67+
{
68+
net_buf_destroy(buf);
69+
buf_rx_freed_notify(BT_BUF_EVT);
70+
}
4371

44-
NET_BUF_POOL_FIXED_DEFINE(evt_pool, CONFIG_BT_BUF_EVT_RX_COUNT,
45-
BT_BUF_EVT_RX_SIZE, sizeof(struct bt_buf_data),
46-
NULL);
72+
NET_BUF_POOL_DEFINE(acl_in_pool, BT_BUF_ACL_RX_COUNT, BT_BUF_ACL_SIZE(CONFIG_BT_BUF_ACL_RX_SIZE),
73+
sizeof(struct acl_data), acl_in_pool_destroy);
74+
75+
NET_BUF_POOL_FIXED_DEFINE(evt_pool, CONFIG_BT_BUF_EVT_RX_COUNT, BT_BUF_EVT_RX_SIZE,
76+
sizeof(struct bt_buf_data), evt_pool_destroy);
4777
#else
48-
NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, BT_BUF_RX_COUNT,
49-
BT_BUF_RX_SIZE, sizeof(struct acl_data),
50-
NULL);
78+
static void hci_rx_pool_destroy(struct net_buf *buf)
79+
{
80+
net_buf_destroy(buf);
81+
82+
/* When ACL Flow Control is disabled, a single pool is used for events and acl data.
83+
* Therefore the callback will always notify about both types of buffers, BT_BUF_EVT and
84+
* BT_BUF_ACL_IN.
85+
*/
86+
buf_rx_freed_notify(BT_BUF_EVT | BT_BUF_ACL_IN);
87+
}
88+
89+
NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, BT_BUF_RX_COUNT, BT_BUF_RX_SIZE, sizeof(struct acl_data),
90+
hci_rx_pool_destroy);
5191
#endif /* CONFIG_BT_HCI_ACL_FLOW_CONTROL */
5292

5393
struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout)
@@ -79,6 +119,19 @@ struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout)
79119
return buf;
80120
}
81121

122+
void bt_buf_rx_freed_cb_set(bt_buf_rx_freed_cb_t cb)
123+
{
124+
k_sched_lock();
125+
126+
buf_rx_freed_cb = cb;
127+
128+
#if defined(CONFIG_BT_ISO_RX)
129+
bt_iso_buf_rx_freed_cb_set(cb != NULL ? iso_rx_freed_cb : NULL);
130+
#endif
131+
132+
k_sched_unlock();
133+
}
134+
82135
struct net_buf *bt_buf_get_evt(uint8_t evt, bool discardable,
83136
k_timeout_t timeout)
84137
{

subsys/bluetooth/host/hci_raw.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,20 @@ static uint8_t raw_mode = BT_HCI_RAW_MODE_H4;
4343
static uint8_t raw_mode;
4444
#endif
4545

46-
NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, BT_BUF_RX_COUNT,
47-
BT_BUF_RX_SIZE, sizeof(struct bt_buf_data), NULL);
46+
static bt_buf_rx_freed_cb_t buf_rx_freed_cb;
47+
48+
static void hci_rx_buf_destroy(struct net_buf *buf)
49+
{
50+
net_buf_destroy(buf);
51+
52+
if (buf_rx_freed_cb) {
53+
/* bt_buf_get_rx is used for all types of RX buffers */
54+
buf_rx_freed_cb(BT_BUF_EVT | BT_BUF_ACL_IN | BT_BUF_ISO_IN);
55+
}
56+
}
57+
58+
NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, BT_BUF_RX_COUNT, BT_BUF_RX_SIZE, sizeof(struct bt_buf_data),
59+
hci_rx_buf_destroy);
4860
NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, BT_BUF_CMD_TX_COUNT,
4961
BT_BUF_CMD_SIZE(CONFIG_BT_BUF_CMD_TX_SIZE),
5062
sizeof(struct bt_buf_data), NULL);
@@ -106,6 +118,11 @@ struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout)
106118
return buf;
107119
}
108120

121+
void bt_buf_rx_freed_cb_set(bt_buf_rx_freed_cb_t cb)
122+
{
123+
buf_rx_freed_cb = cb;
124+
}
125+
109126
struct net_buf *bt_buf_get_tx(enum bt_buf_type type, k_timeout_t timeout,
110127
const void *data, size_t size)
111128
{

subsys/bluetooth/host/iso.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,20 @@ LOG_MODULE_REGISTER(bt_iso);
3535
#define iso_chan(_iso) ((_iso)->iso.chan);
3636

3737
#if defined(CONFIG_BT_ISO_RX)
38+
static bt_iso_buf_rx_freed_cb_t buf_rx_freed_cb;
39+
40+
static void iso_rx_buf_destroy(struct net_buf *buf)
41+
{
42+
net_buf_destroy(buf);
43+
44+
if (buf_rx_freed_cb) {
45+
buf_rx_freed_cb();
46+
}
47+
}
48+
3849
NET_BUF_POOL_FIXED_DEFINE(iso_rx_pool, CONFIG_BT_ISO_RX_BUF_COUNT,
39-
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_RX_MTU),
40-
sizeof(struct iso_data), NULL);
50+
BT_ISO_SDU_BUF_SIZE(CONFIG_BT_ISO_RX_MTU), sizeof(struct iso_data),
51+
iso_rx_buf_destroy);
4152

4253
static struct bt_iso_recv_info iso_info_data[CONFIG_BT_ISO_RX_BUF_COUNT];
4354
#define iso_info(buf) (&iso_info_data[net_buf_id(buf)])
@@ -583,6 +594,11 @@ struct net_buf *bt_iso_get_rx(k_timeout_t timeout)
583594
return buf;
584595
}
585596

597+
void bt_iso_buf_rx_freed_cb_set(bt_iso_buf_rx_freed_cb_t cb)
598+
{
599+
buf_rx_freed_cb = cb;
600+
}
601+
586602
void bt_iso_recv(struct bt_conn *iso, struct net_buf *buf, uint8_t flags)
587603
{
588604
struct bt_hci_iso_data_hdr *hdr;

subsys/bluetooth/host/iso_internal.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,16 @@ void hci_iso(struct net_buf *buf);
7878
/* Allocates RX buffer */
7979
struct net_buf *bt_iso_get_rx(k_timeout_t timeout);
8080

81+
/** A callback used to notify about freed buffer in the iso rx pool. */
82+
typedef void (*bt_iso_buf_rx_freed_cb_t)(void);
83+
84+
/** Set a callback to notify about freed buffer in the iso rx pool.
85+
*
86+
* @param cb Callback to notify about freed buffer in the iso rx pool. If NULL, the callback is
87+
* disabled.
88+
*/
89+
void bt_iso_buf_rx_freed_cb_set(bt_iso_buf_rx_freed_cb_t cb);
90+
8191
/* Process CIS Established event */
8292
void hci_le_cis_established(struct net_buf *buf);
8393

0 commit comments

Comments
 (0)