Skip to content

Commit 8b0d695

Browse files
niag-Oticoncarlescufi
authored andcommitted
Bluetooth: controller: Implemented PDU release timeout
Implemented: -- Combining segments from multiple SDUs in a single PDU for TX -- Release of PDU based on remaining capacity below threshold -- Release of any PDUs in production on receiving a timeout for the upcoming event -- Release of PDUs in production if source if destroyed -- Synchronization flag to exclude multiple contexts in ISO-AL -- New Kconfig BT_CTLR_ISO_TX_SEG_PLAYLOAD_MIN to allow definition of minimum TX segment size Signed-off-by: Nirosharn Amarasinghe <[email protected]>
1 parent 896049b commit 8b0d695

File tree

6 files changed

+165
-13
lines changed

6 files changed

+165
-13
lines changed

subsys/bluetooth/controller/Kconfig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,15 @@ config BT_CTLR_ISO_RX_SDU_BUFFERS
255255
maximum size of an SDU that can be accurately declared in the HCI ISO
256256
Data header.
257257

258+
config BT_CTLR_ISO_TX_SEG_PLAYLOAD_MIN
259+
int "Minimum number of playload data bytes in a new segment"
260+
depends on BT_CTLR_ADV_ISO || BT_CTLR_CONN_ISO
261+
default 1
262+
range 1 64
263+
help
264+
Minimum number of payload bytes that would make inserting a new
265+
segment into a PDU worthwhile.
266+
258267
config BT_CTLR_ISO_VENDOR_DATA_PATH
259268
bool "Vendor-specific ISO data path"
260269
depends on BT_CTLR_SYNC_ISO || BT_CTLR_CONN_ISO

subsys/bluetooth/controller/ll_sw/isoal.c

Lines changed: 113 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@
2828
#include "common/log.h"
2929
#include "hal/debug.h"
3030

31+
#if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO)
32+
/* Given the minimum payload, this defines the minimum number of bytes that
33+
* should be remaining in a TX PDU such that it would make inserting a new
34+
* segment worthwhile during the segmentation process.
35+
* [Payload (min) + Segmentation Header + Time Offset]
36+
*/
37+
#define ISOAL_TX_SEGMENT_MIN_SIZE (CONFIG_BT_CTLR_ISO_TX_SEG_PLAYLOAD_MIN + \
38+
PDU_ISO_SEG_HDR_SIZE + \
39+
PDU_ISO_SEG_TIMEOFFSET_SIZE)
40+
#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */
41+
3142
/** Allocation state */
3243
typedef uint8_t isoal_alloc_state_t;
3344
#define ISOAL_ALLOC_STATE_FREE ((isoal_alloc_state_t) 0x00)
@@ -1106,6 +1117,21 @@ static isoal_status_t isoal_source_allocate(isoal_source_handle_t *hdl)
11061117
*/
11071118
static void isoal_source_deallocate(isoal_source_handle_t hdl)
11081119
{
1120+
struct isoal_pdu_production *pp;
1121+
struct isoal_source *source;
1122+
1123+
source = &isoal_global.source_state[hdl];
1124+
pp = &source->pdu_production;
1125+
1126+
if (pp->pdu_available > 0) {
1127+
/* There is a pending PDU that should be released */
1128+
if (source && source->session.pdu_release) {
1129+
source->session.pdu_release(pp->pdu.contents.handle,
1130+
source->session.handle,
1131+
ISOAL_STATUS_ERR_PDU_EMIT);
1132+
}
1133+
}
1134+
11091135
isoal_global.source_allocated[hdl] = ISOAL_ALLOC_STATE_FREE;
11101136
(void)memset(&isoal_global.source_state[hdl], 0, sizeof(struct isoal_source));
11111137
}
@@ -1884,18 +1910,11 @@ static isoal_status_t isoal_tx_framed_produce(struct isoal_source *source,
18841910
/* LLID is fixed for framed PDUs */
18851911
ll_id = PDU_BIS_LLID_FRAMED;
18861912

1887-
/* NOTE: Ideally even if the end of the SDU is reached, the PDU
1888-
* should not be emitted as long as there is space left. If the
1889-
* PDU is not released, it might require a flush timeout to
1890-
* trigger the release as receiving an SDU per SDU interval is
1891-
* not guaranteed. As there is no trigger for this in the
1892-
* ISO-AL, the PDU is released. This does mean that the
1893-
* bandwidth of this implementation will be less that the ideal
1894-
* supported by framed PDUs. Ideally ISOAL_SEGMENT_MIN_SIZE
1895-
* should be used to assess if there is sufficient usable space
1896-
* left in the PDU.
1913+
/* If there isn't sufficient usable space then release the
1914+
* PDU when the end of the SDU is reached, instead of waiting
1915+
* for the next SDU.
18971916
*/
1898-
bool release_pdu = end_of_sdu;
1917+
bool release_pdu = end_of_sdu && (pp->pdu_available <= ISOAL_TX_SEGMENT_MIN_SIZE);
18991918
const isoal_status_t err_emit = isoal_tx_try_emit_pdu(source, release_pdu, ll_id);
19001919

19011920
err |= err_emit;
@@ -1918,6 +1937,41 @@ static isoal_status_t isoal_tx_framed_produce(struct isoal_source *source,
19181937
return err;
19191938
}
19201939

1940+
/**
1941+
* @brief Handle preparation of the given source before commencing TX on the
1942+
* specified event (only for framed sources)
1943+
* @param source_hdl Handle of source to prepare
1944+
* @param event_count Event number source should be prepared for
1945+
* @return Status of operation
1946+
*/
1947+
static isoal_status_t isoal_tx_framed_event_prepare_handle(isoal_source_handle_t source_hdl,
1948+
uint64_t event_count)
1949+
{
1950+
struct isoal_source_session *session;
1951+
struct isoal_pdu_production *pp;
1952+
struct isoal_source *source;
1953+
uint64_t last_event_payload;
1954+
isoal_status_t err;
1955+
1956+
err = ISOAL_STATUS_OK;
1957+
1958+
source = &isoal_global.source_state[source_hdl];
1959+
session = &source->session;
1960+
pp = &source->pdu_production;
1961+
last_event_payload = (session->burst_number * (event_count + 1)) - 1;
1962+
1963+
if (pp->pdu_available > 0 &&
1964+
pp->payload_number <= last_event_payload) {
1965+
/* Pending PDU that should be released for framed TX */
1966+
err = isoal_tx_try_emit_pdu(source, true, PDU_BIS_LLID_FRAMED);
1967+
}
1968+
1969+
if (pp->payload_number < last_event_payload + 1) {
1970+
pp->payload_number = last_event_payload + 1;
1971+
}
1972+
1973+
return err;
1974+
}
19211975

19221976
/**
19231977
* @brief Deep copy a SDU, fragment into PDU(s)
@@ -1930,12 +1984,19 @@ static isoal_status_t isoal_tx_framed_produce(struct isoal_source *source,
19301984
isoal_status_t isoal_tx_sdu_fragment(isoal_source_handle_t source_hdl,
19311985
struct isoal_sdu_tx *tx_sdu)
19321986
{
1987+
struct isoal_source_session *session;
19331988
struct isoal_source *source;
19341989
isoal_status_t err;
19351990

19361991
source = &isoal_global.source_state[source_hdl];
1992+
session = &source->session;
19371993
err = ISOAL_STATUS_ERR_PDU_ALLOC;
19381994

1995+
/* Set source context active to mutually exclude ISO Event prepare
1996+
* kick.
1997+
*/
1998+
source->context_active = true;
1999+
19392000
if (source->pdu_production.mode != ISOAL_PRODUCTION_MODE_DISABLED) {
19402001
/* BT Core V5.3 : Vol 6 Low Energy Controller : Part G IS0-AL:
19412002
* 2 ISOAL Features :
@@ -1954,6 +2015,16 @@ isoal_status_t isoal_tx_sdu_fragment(isoal_source_handle_t source_hdl,
19542015
}
19552016
}
19562017

2018+
source->context_active = false;
2019+
2020+
if (source->timeout_trigger) {
2021+
source->timeout_trigger = false;
2022+
if (session->framed) {
2023+
isoal_tx_framed_event_prepare_handle(source_hdl,
2024+
source->timeout_event_count);
2025+
}
2026+
}
2027+
19572028
return err;
19582029
}
19592030

@@ -2003,4 +2074,35 @@ isoal_status_t isoal_tx_get_sync_info(isoal_source_handle_t source_hdl,
20032074
return ISOAL_STATUS_ERR_UNSPECIFIED;
20042075
}
20052076

2077+
/**
2078+
* @brief Incoming prepare request before commencing TX for the specified
2079+
* event
2080+
* @param source_hdl Handle of source to prepare
2081+
* @param event_count Event number source should be prepared for
2082+
* @return Status of operation
2083+
*/
2084+
void isoal_tx_event_prepare(isoal_source_handle_t source_hdl,
2085+
uint64_t event_count)
2086+
{
2087+
struct isoal_source_session *session;
2088+
struct isoal_source *source;
2089+
2090+
source = &isoal_global.source_state[source_hdl];
2091+
session = &source->session;
2092+
2093+
/* Store prepare timeout information and check if fragmentation context
2094+
* is active.
2095+
*/
2096+
source->timeout_event_count = event_count;
2097+
source->timeout_trigger = true;
2098+
if (source->context_active) {
2099+
return;
2100+
}
2101+
source->timeout_trigger = false;
2102+
2103+
if (session->framed) {
2104+
isoal_tx_framed_event_prepare_handle(source_hdl, event_count);
2105+
}
2106+
}
2107+
20062108
#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */

subsys/bluetooth/controller/ll_sw/isoal.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,11 @@ struct isoal_source {
411411

412412
/* State for PDU production */
413413
struct isoal_pdu_production pdu_production;
414+
415+
/* Context Control */
416+
uint64_t timeout_event_count:39;
417+
uint64_t timeout_trigger:1;
418+
uint64_t context_active:1;
414419
};
415420

416421
isoal_status_t isoal_init(void);
@@ -489,3 +494,6 @@ isoal_status_t isoal_tx_get_sync_info(isoal_source_handle_t source_hdl,
489494
uint16_t *seq,
490495
uint32_t *timestamp,
491496
uint32_t *offset);
497+
498+
void isoal_tx_event_prepare(isoal_source_handle_t source_hdl,
499+
uint64_t event_number);

subsys/bluetooth/controller/ll_sw/lll.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,7 @@ void ull_iso_rx_put(memq_link_t *link, void *rx);
586586
void ull_iso_rx_sched(void);
587587
void *ull_iso_tx_ack_dequeue(void);
588588
void ull_iso_lll_ack_enqueue(uint16_t handle, struct node_tx_iso *tx);
589+
void ull_iso_lll_event_prepare(uint16_t handle, uint64_t event_count);
589590
struct event_done_extra *ull_event_done_extra_get(void);
590591
struct event_done_extra *ull_done_extra_type_set(uint8_t type);
591592
void *ull_event_done(void *param);

subsys/bluetooth/controller/ll_sw/ull_iso.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -916,7 +916,9 @@ static isoal_status_t ll_iso_test_pdu_release(struct node_tx_iso *node_tx,
916916
const isoal_status_t status)
917917
{
918918
/* Release back to memory pool */
919-
ll_iso_link_tx_release(node_tx->link);
919+
if (node_tx->link) {
920+
ll_iso_link_tx_release(node_tx->link);
921+
}
920922
ll_iso_tx_mem_release(node_tx);
921923

922924
return ISOAL_STATUS_OK;
@@ -1292,6 +1294,30 @@ void ull_iso_lll_ack_enqueue(uint16_t handle, struct node_tx_iso *node_tx)
12921294
LL_ASSERT(0);
12931295
}
12941296
}
1297+
1298+
void ull_iso_lll_event_prepare(uint16_t handle, uint64_t event_count)
1299+
{
1300+
if (IS_CIS_HANDLE(handle)) {
1301+
struct ll_iso_datapath *dp = NULL;
1302+
struct ll_conn_iso_stream *cis;
1303+
1304+
cis = ll_iso_stream_connected_get(handle);
1305+
1306+
if (cis) {
1307+
dp = cis->hdr.datapath_in;
1308+
}
1309+
1310+
if (dp) {
1311+
isoal_tx_event_prepare(dp->source_hdl, event_count);
1312+
}
1313+
} else if (IS_ADV_ISO_HANDLE(handle)) {
1314+
/* Send event deadline trigger to ISO-AL.
1315+
* TODO: Can be unified with CIS implementation.
1316+
*/
1317+
} else {
1318+
LL_ASSERT(0);
1319+
}
1320+
}
12951321
#endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */
12961322

12971323
#if defined(CONFIG_BT_CTLR_SYNC_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO)
@@ -1542,6 +1568,8 @@ static isoal_status_t ll_iso_pdu_alloc(struct isoal_pdu_buffer *pdu_buffer)
15421568
return ISOAL_STATUS_ERR_PDU_ALLOC;
15431569
}
15441570

1571+
node_tx->link = NULL;
1572+
15451573
/* node_tx handle will be required to emit the PDU later */
15461574
pdu_buffer->handle = (void *)node_tx;
15471575
pdu_buffer->pdu = (void *)node_tx->pdu;
@@ -1625,7 +1653,9 @@ static isoal_status_t ll_iso_pdu_release(struct node_tx_iso *node_tx,
16251653
ll_rx_sched();
16261654
} else {
16271655
/* Release back to memory pool */
1628-
ll_iso_link_tx_release(node_tx->link);
1656+
if (node_tx->link) {
1657+
ll_iso_link_tx_release(node_tx->link);
1658+
}
16291659
ll_iso_tx_mem_release(node_tx);
16301660
}
16311661

subsys/bluetooth/controller/ll_sw/ull_peripheral_iso.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,8 @@ static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
313313

314314
leading_event_count = MAX(leading_event_count,
315315
cis->lll.event_count);
316+
317+
ull_iso_lll_event_prepare(cis->lll.handle, cis->lll.event_count);
316318
}
317319

318320
/* Latch datapath validity entering event */

0 commit comments

Comments
 (0)