Skip to content

Commit 789628a

Browse files
niag-Oticoncarlescufi
authored andcommitted
Bluetooth: Controller: Implemented buffering of SDU fragments in ISO-AL
Implements: -- SDU fragments can be buffered in the ISO-AL so that the correct size of the SDU can be computed such that it can be released for inclusion in the first fragment's header -- Changed SDU emit interface to allow the same structure to be used to buffer as well as release fragments -- New configuration BT_CTLR_ISO_RX_SDU_BUFFERS to specify the number of SDU buffers for each sink (Buffering disabled when BT_CTLR_ISO_RX_SDU_BUFFERS=0) Signed-off-by: Nirosharn Amarasinghe <[email protected]>
1 parent 6c855b4 commit 789628a

File tree

5 files changed

+200
-21
lines changed

5 files changed

+200
-21
lines changed

subsys/bluetooth/controller/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,19 @@ config BT_CTLR_ISOAL_SINKS
242242
Set the number of concurrently active sinks supported by the
243243
ISO AL.
244244

245+
config BT_CTLR_ISO_RX_SDU_BUFFERS
246+
int "Number of SDU fragments that the ISO-AL can buffer"
247+
depends on BT_CTLR_SYNC_ISO || BT_CTLR_CONN_ISO
248+
default 0
249+
range 0 64
250+
help
251+
Set the number of Isochronous Rx SDU fragments to be buffered in the
252+
ISO-AL per sink. Buffering is required to compute the size and status
253+
of the received SDU across all the fragments before each is released.
254+
The number of buffers and maximum SDU fragment size will limit the
255+
maximum size of an SDU that can be accurately declared in the HCI ISO
256+
Data header.
257+
245258
config BT_CTLR_ISO_VENDOR_DATA_PATH
246259
bool "Vendor-specific ISO data path"
247260
depends on BT_CTLR_SYNC_ISO || BT_CTLR_CONN_ISO

subsys/bluetooth/controller/hci/hci_driver.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -105,35 +105,38 @@ isoal_status_t sink_sdu_alloc_hci(const struct isoal_sink *sink_ctx,
105105
}
106106

107107

108-
isoal_status_t sink_sdu_emit_hci(const struct isoal_sink *sink_ctx,
109-
const struct isoal_sdu_produced *valid_sdu)
108+
isoal_status_t sink_sdu_emit_hci(const struct isoal_sink *sink_ctx,
109+
const struct isoal_emitted_sdu_frag *sdu_frag,
110+
const struct isoal_emitted_sdu *sdu)
110111
{
111112
struct bt_hci_iso_ts_data_hdr *data_hdr;
112113
uint16_t packet_status_flag;
113114
struct bt_hci_iso_hdr *hdr;
114115
uint16_t handle_packed;
115116
uint16_t slen_packed;
116117
struct net_buf *buf;
118+
uint16_t total_len;
117119
uint16_t handle;
118120
uint8_t ts, pb;
119121
uint16_t len;
120122

121-
buf = (struct net_buf *) valid_sdu->contents.dbuf;
123+
buf = (struct net_buf *) sdu_frag->sdu.contents.dbuf;
122124

123125

124126
if (buf) {
125127
#if defined(CONFIG_BT_CTLR_CONN_ISO_HCI_DATAPATH_SKIP_INVALID_DATA)
126-
if (valid_sdu->status != ISOAL_SDU_STATUS_VALID) {
128+
if (sdu_frag->sdu.status != ISOAL_SDU_STATUS_VALID) {
127129
/* unref buffer if invalid fragment */
128130
net_buf_unref(buf);
129131

130132
return ISOAL_STATUS_OK;
131133
}
132134
#endif /* CONFIG_BT_CTLR_CONN_ISO_HCI_DATAPATH_SKIP_INVALID_DATA */
133135

134-
pb = sink_ctx->sdu_production.sdu_state;
135-
len = sink_ctx->sdu_production.sdu_written;
136-
packet_status_flag = valid_sdu->status;
136+
pb = sdu_frag->sdu_state;
137+
len = sdu_frag->sdu_frag_size;
138+
total_len = sdu->total_sdu_size;
139+
packet_status_flag = sdu->collated_status;
137140

138141
/* BT Core V5.3 : Vol 4 HCI I/F : Part G HCI Func. Spec.:
139142
* 5.4.5 HCI ISO Data packets
@@ -147,6 +150,7 @@ isoal_status_t sink_sdu_emit_hci(const struct isoal_sink *sink_ctx,
147150
net_buf_pull_mem(buf, len);
148151
}
149152
len = 0;
153+
total_len = 0;
150154
}
151155

152156
/*
@@ -169,10 +173,10 @@ isoal_status_t sink_sdu_emit_hci(const struct isoal_sink *sink_ctx,
169173

170174
if (ts) {
171175
data_hdr = net_buf_push(buf, BT_HCI_ISO_TS_DATA_HDR_SIZE);
172-
slen_packed = bt_iso_pkt_len_pack(len, packet_status_flag);
176+
slen_packed = bt_iso_pkt_len_pack(total_len, packet_status_flag);
173177

174-
data_hdr->ts = sys_cpu_to_le32((uint32_t) valid_sdu->timestamp);
175-
data_hdr->data.sn = sys_cpu_to_le16((uint16_t) valid_sdu->seqn);
178+
data_hdr->ts = sys_cpu_to_le32((uint32_t) sdu_frag->sdu.timestamp);
179+
data_hdr->data.sn = sys_cpu_to_le16((uint16_t) sdu_frag->sdu.seqn);
176180
data_hdr->data.slen = sys_cpu_to_le16(slen_packed);
177181

178182
len += BT_HCI_ISO_TS_DATA_HDR_SIZE;

subsys/bluetooth/controller/ll_sw/isoal.c

Lines changed: 122 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,127 @@ static isoal_status_t isoal_rx_allocate_sdu(struct isoal_sink *sink,
328328
return err;
329329
}
330330

331+
/**
332+
* @brief Depending of whether the configuration is enabled, this will either
333+
* buffer and collate information for the SDU across all fragments
334+
* before emitting the batch of fragments, or immediately release the
335+
* fragment.
336+
* @param sink Point to the sink context structure
337+
* @param end_of_sdu Indicates if this is the end fragment of an SDU or forced
338+
* release on an error
339+
* @return Status of operation
340+
*/
341+
static isoal_status_t isoal_rx_buffered_emit_sdu(struct isoal_sink *sink, bool end_of_sdu)
342+
{
343+
struct isoal_emitted_sdu_frag sdu_frag;
344+
struct isoal_emitted_sdu sdu_status;
345+
struct isoal_sink_session *session;
346+
struct isoal_sdu_production *sp;
347+
struct isoal_sdu_produced *sdu;
348+
bool emit_sdu_current;
349+
isoal_status_t err;
350+
351+
err = ISOAL_STATUS_OK;
352+
session = &sink->session;
353+
sp = &sink->sdu_production;
354+
sdu = &sp->sdu;
355+
356+
/* Initialize current SDU fragment buffer */
357+
sdu_frag.sdu_state = sp->sdu_state;
358+
sdu_frag.sdu_frag_size = sp->sdu_written;
359+
sdu_frag.sdu = *sdu;
360+
361+
sdu_status.total_sdu_size = sdu_frag.sdu_frag_size;
362+
sdu_status.collated_status = sdu_frag.sdu.status;
363+
emit_sdu_current = true;
364+
365+
#if defined(ISOAL_BUFFER_RX_SDUS_ENABLE)
366+
uint16_t next_write_indx;
367+
bool sdu_list_empty;
368+
bool emit_sdu_list;
369+
bool sdu_list_max;
370+
bool sdu_list_err;
371+
372+
next_write_indx = sp->sdu_list.next_write_indx;
373+
sdu_list_max = (next_write_indx >= CONFIG_BT_CTLR_ISO_RX_SDU_BUFFERS);
374+
sdu_list_empty = (next_write_indx == 0);
375+
376+
/* There is an error in the sequence of SDUs if the current SDU fragment
377+
* is not an end fragment and either the list at capacity or the current
378+
* fragment is not a continuation (i.e. it is a start of a new SDU).
379+
*/
380+
sdu_list_err = !end_of_sdu &&
381+
(sdu_list_max ||
382+
(!sdu_list_empty && sdu_frag.sdu_state != BT_ISO_CONT));
383+
384+
/* Release the current fragment if it is the end of the SDU or if it is
385+
* not the starting fragment of a multi-fragment SDU.
386+
*/
387+
emit_sdu_current = end_of_sdu || (sdu_list_empty && sdu_frag.sdu_state != BT_ISO_START);
388+
389+
/* Flush the buffered SDUs if this is an end fragment either on account
390+
* of reaching the end of the SDU or on account of an error or if
391+
* there is an error in the sequence of buffered fragments.
392+
*/
393+
emit_sdu_list = emit_sdu_current || sdu_list_err;
394+
395+
/* Total size is cleared if the current fragment is not being emitted
396+
* or if there is an error in the sequence of fragments.
397+
*/
398+
if (!emit_sdu_current || sdu_list_err) {
399+
sdu_status.total_sdu_size = 0;
400+
sdu_status.collated_status = (sdu_list_err ? ISOAL_SDU_STATUS_LOST_DATA :
401+
ISOAL_SDU_STATUS_VALID);
402+
}
403+
404+
if (emit_sdu_list && next_write_indx > 0) {
405+
if (!sdu_list_err) {
406+
/* Collated information is not reliable if there is an
407+
* error in the sequence of the fragments.
408+
*/
409+
for (uint8_t i = 0; i < next_write_indx; i++) {
410+
sdu_status.total_sdu_size +=
411+
sp->sdu_list.list[i].sdu_frag_size;
412+
if (sp->sdu_list.list[i].sdu.status == ISOAL_SDU_STATUS_LOST_DATA ||
413+
sdu_status.collated_status == ISOAL_SDU_STATUS_LOST_DATA) {
414+
sdu_status.collated_status = ISOAL_SDU_STATUS_LOST_DATA;
415+
} else {
416+
sdu_status.collated_status |=
417+
sp->sdu_list.list[i].sdu.status;
418+
}
419+
}
420+
}
421+
422+
for (uint8_t i = 0; i < next_write_indx; i++) {
423+
err |= session->sdu_emit(sink, &sp->sdu_list.list[i],
424+
&sdu_status);
425+
}
426+
427+
next_write_indx = sp->sdu_list.next_write_indx = 0;
428+
}
429+
#endif /* ISOAL_BUFFER_RX_SDUS_ENABLE */
430+
431+
if (emit_sdu_current) {
432+
if (sdu_frag.sdu_state == BT_ISO_SINGLE) {
433+
sdu_status.total_sdu_size = sdu_frag.sdu_frag_size;
434+
sdu_status.collated_status = sdu_frag.sdu.status;
435+
}
436+
437+
err |= session->sdu_emit(sink, &sdu_frag, &sdu_status);
438+
439+
#if defined(ISOAL_BUFFER_RX_SDUS_ENABLE)
440+
} else if (next_write_indx < CONFIG_BT_CTLR_ISO_RX_SDU_BUFFERS) {
441+
sp->sdu_list.list[next_write_indx++] = sdu_frag;
442+
sp->sdu_list.next_write_indx = next_write_indx;
443+
#endif /* ISOAL_BUFFER_RX_SDUS_ENABLE */
444+
} else {
445+
/* Unreachable */
446+
LL_ASSERT(0);
447+
}
448+
449+
return err;
450+
}
451+
331452
static isoal_status_t isoal_rx_try_emit_sdu(struct isoal_sink *sink, bool end_of_sdu)
332453
{
333454
struct isoal_sdu_production *sp;
@@ -369,9 +490,8 @@ static isoal_status_t isoal_rx_try_emit_sdu(struct isoal_sink *sink, bool end_of
369490
break;
370491
}
371492
sdu->status = sp->sdu_status;
372-
struct isoal_sink_session *session = &sink->session;
373493

374-
err = session->sdu_emit(sink, sdu);
494+
err = isoal_rx_buffered_emit_sdu(sink, end_of_sdu);
375495
sp->sdu_allocated = false;
376496

377497
/* update next state */

subsys/bluetooth/controller/ll_sw/isoal.h

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
#include <zephyr/types.h>
99
#include <zephyr/toolchain.h>
1010

11+
#if defined(CONFIG_BT_CTLR_ISO_RX_SDU_BUFFERS) && (CONFIG_BT_CTLR_ISO_RX_SDU_BUFFERS > 0)
12+
#define ISOAL_BUFFER_RX_SDUS_ENABLE
13+
#endif /* CONFIG_BT_CTLR_ISO_RX_SDU_BUFFERS > 0 */
14+
15+
1116
/** Function return error codes */
1217
typedef uint8_t isoal_status_t;
1318
#define ISOAL_STATUS_OK ((isoal_status_t) 0x00) /* No error */
@@ -120,6 +125,35 @@ struct isoal_sdu_produced {
120125
void *ctx;
121126
};
122127

128+
/** @brief Produced ISO SDU fragment and status information to be emitted */
129+
struct isoal_emitted_sdu_frag {
130+
/** Produced SDU to be emitted */
131+
struct isoal_sdu_produced sdu;
132+
/** SDU fragment Packet Boundary flags */
133+
uint8_t sdu_state;
134+
/** Size of the SDU fragment */
135+
isoal_sdu_len_t sdu_frag_size;
136+
};
137+
138+
/** @brief Produced ISO SDU and required status information to be emitted */
139+
struct isoal_emitted_sdu {
140+
/** Size of the SDU across all fragments */
141+
isoal_sdu_len_t total_sdu_size;
142+
/** Status of contents, if valid or SDU was lost.
143+
* This maps directly to the HCI ISO Data packet Packet_Status_Flag.
144+
* BT Core V5.3 : Vol 4 HCI I/F : Part G HCI Func. Spec.:
145+
* 5.4.5 HCI ISO Data packets : Table 5.2 :
146+
* Packet_Status_Flag (in packets sent by the Controller)
147+
*/
148+
isoal_sdu_status_t collated_status;
149+
};
150+
151+
#if defined(ISOAL_BUFFER_RX_SDUS_ENABLE)
152+
struct isoal_emit_sdu_queue {
153+
struct isoal_emitted_sdu_frag list[CONFIG_BT_CTLR_ISO_RX_SDU_BUFFERS];
154+
uint16_t next_write_indx;
155+
};
156+
#endif /* ISOAL_BUFFER_RX_SDUS_ENABLE */
123157

124158
/** @brief Produced ISO PDU encapsulation */
125159
struct isoal_pdu_produced {
@@ -194,9 +228,11 @@ typedef isoal_status_t (*isoal_sink_sdu_alloc_cb)(
194228
*/
195229
typedef isoal_status_t (*isoal_sink_sdu_emit_cb)(
196230
/*!< [in] Sink context */
197-
const struct isoal_sink *sink_ctx,
198-
/*!< [in] Filled valid SDU to be pushed */
199-
const struct isoal_sdu_produced *valid_sdu
231+
const struct isoal_sink *sink_ctx,
232+
/*!< [in] Emitted SDU fragment and status information */
233+
const struct isoal_emitted_sdu_frag *sdu_frag,
234+
/*!< [in] Emitted SDU status information */
235+
const struct isoal_emitted_sdu *sdu
200236
);
201237

202238
/**
@@ -232,6 +268,10 @@ struct isoal_sink_session {
232268
};
233269

234270
struct isoal_sdu_production {
271+
#if defined(ISOAL_BUFFER_RX_SDUS_ENABLE)
272+
/* Buffered SDUs */
273+
struct isoal_emit_sdu_queue sdu_list;
274+
#endif
235275
/* Permit atomic enable/disable of SDU production */
236276
volatile isoal_production_mode_t mode;
237277
/* We are constructing an SDU from {<1 or =1 or >1} PDUs */
@@ -406,8 +446,9 @@ isoal_status_t isoal_rx_pdu_recombine(isoal_sink_handle_t sink_hdl,
406446
isoal_status_t sink_sdu_alloc_hci(const struct isoal_sink *sink_ctx,
407447
const struct isoal_pdu_rx *valid_pdu,
408448
struct isoal_sdu_buffer *sdu_buffer);
409-
isoal_status_t sink_sdu_emit_hci(const struct isoal_sink *sink_ctx,
410-
const struct isoal_sdu_produced *valid_sdu);
449+
isoal_status_t sink_sdu_emit_hci(const struct isoal_sink *sink_ctx,
450+
const struct isoal_emitted_sdu_frag *sdu_frag,
451+
const struct isoal_emitted_sdu *sdu);
411452
isoal_status_t sink_sdu_write_hci(void *dbuf,
412453
const uint8_t *pdu_payload,
413454
const size_t consume_len);

subsys/bluetooth/controller/ll_sw/ull_iso.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -652,15 +652,16 @@ static isoal_status_t ll_iso_test_sdu_alloc(const struct isoal_sink *sink_ctx,
652652
* further in the data path. This injected implementation performs statistics on
653653
* the SDU and then discards it.
654654
*/
655-
static isoal_status_t ll_iso_test_sdu_emit(const struct isoal_sink *sink_ctx,
656-
const struct isoal_sdu_produced *valid_sdu)
655+
static isoal_status_t ll_iso_test_sdu_emit(const struct isoal_sink *sink_ctx,
656+
const struct isoal_emitted_sdu_frag *sdu_frag,
657+
const struct isoal_emitted_sdu *sdu)
657658
{
658659
isoal_status_t status;
659660
struct net_buf *buf;
660661
uint16_t handle;
661662

662663
handle = sink_ctx->session.handle;
663-
buf = (struct net_buf *)valid_sdu->contents.dbuf;
664+
buf = (struct net_buf *)sdu_frag->sdu.contents.dbuf;
664665

665666
if (IS_CIS_HANDLE(handle)) {
666667
struct ll_conn_iso_stream *cis;
@@ -685,7 +686,7 @@ static isoal_status_t ll_iso_test_sdu_emit(const struct isoal_sink *sink_ctx,
685686
sdu_counter = 0U;
686687
}
687688

688-
switch (valid_sdu->status) {
689+
switch (sdu_frag->sdu.status) {
689690
case ISOAL_SDU_STATUS_VALID:
690691
if (framed && cis->hdr.test_mode.rx_sdu_counter == 0U) {
691692
/* BT 5.3, Vol 6, Part B, section 7.2:

0 commit comments

Comments
 (0)