Bluetooth: controller: Introduce config for avoiding SDU fragmentation
The CIS Central uses the algorithm described in BT Core 5.4 Vol 6, Part G, Section 2.2 to calculate the Max_PDU value for framed mode. However, HAP needs the Max_PDU to be calculated according to "Core enhancement for ISOAL CR" coming with the "Atlanta" update. With this update, the fragmentation is controlled via a parameter at CIG creation. Enabling CONFIG_BT_CTLR_CONN_ISO_AVOID_SEGMENTATION will set the ISO_Interval to 7.5 ms for a 10 ms framed CIG, and calculate Max_PDU to 45/65 for 16/24 kHz. Signed-off-by: Morten Priess <mtpr@oticon.com>
This commit is contained in:
parent
02afefe34a
commit
79ab982f46
2 changed files with 56 additions and 14 deletions
|
@ -902,6 +902,17 @@ config BT_CTLR_CONN_ISO_STREAMS_MAX_FT
|
|||
help
|
||||
Maximum number of CIS flush timeout events.
|
||||
|
||||
config BT_CTLR_CONN_ISO_AVOID_SEGMENTATION
|
||||
bool "Avoid SDU fragmentation for framed mode"
|
||||
depends on BT_CTLR_CENTRAL_ISO
|
||||
help
|
||||
When creating a CIG, the Max_PDU size is calculated according to BT
|
||||
Core 5.4 Vol 6, Part G, Section 2.2. However, HAP specifies a need for
|
||||
avoiding segmentation by forcing the Max_PDU to the appropriate value.
|
||||
Since there is no way to control the Max_PDU using the non-test
|
||||
interface, the config provides a way to force the Max_PDU to Max_SDU +
|
||||
5 (header + offset).
|
||||
|
||||
config BT_CTLR_ISO
|
||||
bool
|
||||
default BT_CTLR_BROADCAST_ISO || BT_CTLR_CONN_ISO
|
||||
|
|
|
@ -234,6 +234,15 @@ uint8_t ll_cig_parameters_commit(uint8_t cig_id, uint16_t *handles)
|
|||
cig->iso_interval = BT_HCI_ISO_INTERVAL_MIN;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_CONN_ISO_AVOID_SEGMENTATION)
|
||||
/* Check if this is a HAP usecase which requires higher link bandwidth to ensure
|
||||
* segmentation is not invoked in ISO-AL.
|
||||
*/
|
||||
if (cig->central.framing && cig->c_sdu_interval == 10000U) {
|
||||
cig->iso_interval = 6; /* 7500 us */
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!cig->central.framing && (cig->c_sdu_interval % ISO_INT_UNIT_US)) {
|
||||
/* Framing not requested but requirement for unframed is not met. Force
|
||||
* CIG into framed mode.
|
||||
|
@ -1131,29 +1140,51 @@ static void set_bn_max_pdu(bool framed, uint32_t iso_interval,
|
|||
uint8_t *max_pdu)
|
||||
{
|
||||
if (framed) {
|
||||
uint32_t ceil_f_x_max_sdu;
|
||||
uint16_t max_pdu_bn1;
|
||||
uint32_t max_drift;
|
||||
uint32_t max_drift_us;
|
||||
uint32_t ceil_f;
|
||||
|
||||
/* Framed (From ES-18002):
|
||||
/* BT Core 5.4 Vol 6, Part G, Section 2.2:
|
||||
* Max_PDU >= ((ceil(F) x 5 + ceil(F x Max_SDU)) / BN) + 2
|
||||
* F = (1 + MaxDrift) x ISO_Interval / SDU_Interval
|
||||
* SegmentationHeader + TimeOffset = 5 bytes
|
||||
* Continuation header = 2 bytes
|
||||
* MaxDrift (Max. allowed SDU delivery timing drift) = 100 ppm
|
||||
*/
|
||||
max_drift = DIV_ROUND_UP(SDU_MAX_DRIFT_PPM * sdu_interval, 1000000U);
|
||||
ceil_f = DIV_ROUND_UP(iso_interval + max_drift, sdu_interval);
|
||||
ceil_f_x_max_sdu = DIV_ROUND_UP(max_sdu * (iso_interval + max_drift),
|
||||
sdu_interval);
|
||||
|
||||
/* Strategy: Keep lowest possible BN.
|
||||
* TODO: Implement other strategies, possibly as policies.
|
||||
max_drift_us = DIV_ROUND_UP(SDU_MAX_DRIFT_PPM * sdu_interval, USEC_PER_SEC);
|
||||
ceil_f = DIV_ROUND_UP((USEC_PER_SEC + max_drift_us) * (uint64_t)iso_interval,
|
||||
USEC_PER_SEC * (uint64_t)sdu_interval);
|
||||
if (false) {
|
||||
#if defined(CONFIG_BT_CTLR_CONN_ISO_AVOID_SEGMENTATION)
|
||||
/* To avoid segmentation according to HAP, if the ISO_Interval is less than
|
||||
* the SDU_Interval, we assume BN=1 and calculate the Max_PDU as:
|
||||
* Max_PDU = celi(F / BN) x (5 / Max_SDU)
|
||||
*
|
||||
* This is in accordance with the "Core enhancement for ISOAL CR".
|
||||
*
|
||||
* This ensures that the drift can be contained in the difference between
|
||||
* SDU_Interval and link bandwidth. For BN=1, ceil(F) == ceil(F/BN).
|
||||
*/
|
||||
max_pdu_bn1 = ceil_f * 5 + ceil_f_x_max_sdu;
|
||||
*bn = DIV_ROUND_UP(max_pdu_bn1, LL_CIS_OCTETS_TX_MAX);
|
||||
*max_pdu = DIV_ROUND_UP(max_pdu_bn1, *bn) + 2;
|
||||
} else if (iso_interval < sdu_interval) {
|
||||
*bn = 1;
|
||||
*max_pdu = ceil_f * (PDU_ISO_SEG_HDR_SIZE + PDU_ISO_SEG_TIMEOFFSET_SIZE +
|
||||
max_sdu);
|
||||
#endif
|
||||
} else {
|
||||
uint32_t ceil_f_x_max_sdu;
|
||||
uint16_t max_pdu_bn1;
|
||||
|
||||
ceil_f_x_max_sdu = DIV_ROUND_UP(max_sdu * ((USEC_PER_SEC + max_drift_us) *
|
||||
(uint64_t)iso_interval),
|
||||
USEC_PER_SEC * (uint64_t)sdu_interval);
|
||||
|
||||
/* Strategy: Keep lowest possible BN.
|
||||
* TODO: Implement other strategies, possibly as policies.
|
||||
*/
|
||||
max_pdu_bn1 = ceil_f * (PDU_ISO_SEG_HDR_SIZE +
|
||||
PDU_ISO_SEG_TIMEOFFSET_SIZE) + ceil_f_x_max_sdu;
|
||||
*bn = DIV_ROUND_UP(max_pdu_bn1, LL_CIS_OCTETS_TX_MAX);
|
||||
*max_pdu = DIV_ROUND_UP(max_pdu_bn1, *bn) + PDU_ISO_SEG_HDR_SIZE;
|
||||
}
|
||||
} else {
|
||||
/* For unframed, ISO_Interval must be N x SDU_Interval */
|
||||
LL_ASSERT(iso_interval % sdu_interval == 0);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue