Commit 79ab982f authored by Morten Priess's avatar Morten Priess Committed by Carles Cufi
Browse files

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: default avatarMorten Priess <mtpr@oticon.com>
parent 02afefe3
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -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
+45 −14
Original line number Diff line number Diff line
@@ -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);
		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).
		 */
		} 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 * 5 + ceil_f_x_max_sdu;
			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) + 2;
			*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);