Skip to content

Commit f887f44

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 1e9d7b6 commit f887f44

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
@@ -113,6 +113,27 @@ struct bt_buf_data {
113113
*/
114114
struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout);
115115

116+
/** A callback to notify about freed buffer in the incoming data pool.
117+
*
118+
* This callback is called when a buffer of a given type is freed and can be requested through the
119+
* @ref bt_buf_get_rx function. However, this callback is called from the context of the buffer
120+
* freeing operation and must not attempt to allocate a new buffer from the same pool.
121+
*
122+
* @warning When this callback is called, the scheduler is locked and the callee must not perform
123+
* any action that makes the current thread unready. This callback must only be used for very
124+
* short non-blocking operation (e.g. submitting a work item).
125+
*
126+
* @param type_mask A bit mask of buffer types that have been freed.
127+
*/
128+
typedef void (*bt_buf_rx_freed_cb_t)(enum bt_buf_type type_mask);
129+
130+
/** Set the callback to notify about freed buffer in the incoming data pool.
131+
*
132+
* @param cb Callback to notify about freed buffer in the incoming data pool. If NULL, the callback
133+
* is disabled.
134+
*/
135+
void bt_buf_rx_freed_cb_set(bt_buf_rx_freed_cb_t cb);
136+
116137
/** Allocate a buffer for outgoing data
117138
*
118139
* 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
@@ -21,6 +21,26 @@
2121
*/
2222
#define SYNC_EVT_SIZE (BT_BUF_RESERVE + BT_HCI_EVT_HDR_SIZE + 255)
2323

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

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

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

5292
struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout)
@@ -78,6 +118,19 @@ struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout)
78118
return buf;
79119
}
80120

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

subsys/bluetooth/host/hci_raw.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,20 @@ static uint8_t raw_mode = BT_HCI_RAW_MODE_H4;
4040
static uint8_t raw_mode;
4141
#endif
4242

43-
NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, BT_BUF_RX_COUNT,
44-
BT_BUF_RX_SIZE, sizeof(struct bt_buf_data), NULL);
43+
static bt_buf_rx_freed_cb_t buf_rx_freed_cb;
44+
45+
static void hci_rx_buf_destroy(struct net_buf *buf)
46+
{
47+
net_buf_destroy(buf);
48+
49+
if (buf_rx_freed_cb) {
50+
/* bt_buf_get_rx is used for all types of RX buffers */
51+
buf_rx_freed_cb(BT_BUF_EVT | BT_BUF_ACL_IN | BT_BUF_ISO_IN);
52+
}
53+
}
54+
55+
NET_BUF_POOL_FIXED_DEFINE(hci_rx_pool, BT_BUF_RX_COUNT, BT_BUF_RX_SIZE, sizeof(struct bt_buf_data),
56+
hci_rx_buf_destroy);
4557
NET_BUF_POOL_FIXED_DEFINE(hci_cmd_pool, CONFIG_BT_BUF_CMD_TX_COUNT,
4658
BT_BUF_CMD_SIZE(CONFIG_BT_BUF_CMD_TX_SIZE),
4759
sizeof(struct bt_buf_data), NULL);
@@ -103,6 +115,11 @@ struct net_buf *bt_buf_get_rx(enum bt_buf_type type, k_timeout_t timeout)
103115
return buf;
104116
}
105117

118+
void bt_buf_rx_freed_cb_set(bt_buf_rx_freed_cb_t cb)
119+
{
120+
buf_rx_freed_cb = cb;
121+
}
122+
106123
struct net_buf *bt_buf_get_tx(enum bt_buf_type type, k_timeout_t timeout,
107124
const void *data, size_t size)
108125
{

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)