diff --git a/subsys/bluetooth/controller/include/ll_feat.h b/subsys/bluetooth/controller/include/ll_feat.h index 9e5cd3144b7ae..2a05d94ac6907 100644 --- a/subsys/bluetooth/controller/include/ll_feat.h +++ b/subsys/bluetooth/controller/include/ll_feat.h @@ -253,6 +253,9 @@ * !CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT */ +/* FIXME: Conditional Compilation for FSU feature, and handle feature bits > 64 bits */ +#define LL_FEAT_BIT_FRAME_SPACE 0U + /* All defined feature bits */ #define LL_FEAT_BIT_MASK 0xFFFFFFFFFFULL @@ -296,7 +299,9 @@ LL_FEAT_BIT_SYNC_RECEIVER | \ LL_FEAT_BIT_PERIODIC_ADI_SUPPORT | \ LL_FEAT_BIT_SYNC_TRANSFER_RECEIVER | \ - LL_FEAT_BIT_SYNC_TRANSFER_SENDER) + LL_FEAT_BIT_SYNC_TRANSFER_SENDER | \ + LL_FEAT_BIT_FRAME_SPACE | \ + 0U) /* Connected Isochronous Stream (Host Support) bit is controlled by host */ #if defined(CONFIG_BT_CTLR_CONN_ISO) diff --git a/subsys/bluetooth/controller/ll_sw/lll_conn.h b/subsys/bluetooth/controller/ll_sw/lll_conn.h index 98177652ba0a6..1260ad556b0e5 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_conn.h +++ b/subsys/bluetooth/controller/ll_sw/lll_conn.h @@ -53,6 +53,13 @@ struct data_pdu_length { }; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ +struct data_pdu_fsu { + uint16_t fsu_min; + uint16_t fsu_max; + uint8_t phys; + uint16_t spacing_type; +}; + struct lll_conn { struct lll_hdr hdr; @@ -133,6 +140,12 @@ struct lll_conn { uint8_t update; } dle; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + struct { + struct data_pdu_fsu local; + struct data_pdu_fsu perphy[4]; /* store frame-space for each PHY */ + struct data_pdu_fsu eff; + uint8_t update; + } fsu; #if defined(CONFIG_BT_CTLR_PHY) uint8_t phy_tx:3; diff --git a/subsys/bluetooth/controller/ll_sw/pdu.h b/subsys/bluetooth/controller/ll_sw/pdu.h index 430704c84514f..c012a18646035 100644 --- a/subsys/bluetooth/controller/ll_sw/pdu.h +++ b/subsys/bluetooth/controller/ll_sw/pdu.h @@ -286,6 +286,12 @@ #define PHY_FLAGS_S2 0 #define PHY_FLAGS_S8 BIT(0) +#define T_IFS_ACL_CP BIT(0) +#define T_IFS_ACL_PC BIT(1) +#define T_MCES BIT(2) +#define T_IFS_CIS BIT(3) +#define T_MSS_CIS BIT(4) + /* Macros for getting/setting did/sid from pdu_adv_adi */ #define PDU_ADV_ADI_DID_GET(adi) ((adi)->did_sid_packed[0] | \ (((adi)->did_sid_packed[1] & 0x0F) << 8)) @@ -624,6 +630,9 @@ enum pdu_data_llctrl_type { PDU_DATA_LLCTRL_TYPE_CIS_RSP = 0x20, PDU_DATA_LLCTRL_TYPE_CIS_IND = 0x21, PDU_DATA_LLCTRL_TYPE_CIS_TERMINATE_IND = 0x22, + PDU_DATA_LLCTRL_TYPE_FRAME_SPACE_REQ = 0x3B, + PDU_DATA_LLCTRL_TYPE_FRAME_SPACE_RSP = 0x3C, + PDU_DATA_LLCTRL_TYPE_UNUSED = 0xFF }; @@ -788,6 +797,19 @@ struct pdu_data_llctrl_length_req_rsp_common { uint16_t max_tx_time; } __packed; +struct pdu_data_llctrl_fsu_req { + uint16_t fsu_min; + uint16_t fsu_max; + uint8_t phys; + uint16_t spacing_type; +} __packed; + +struct pdu_data_llctrl_fsu_rsp { + uint16_t fsu; + uint8_t phys; + uint16_t spacing_type; +} __packed; + struct pdu_data_llctrl_phy_req { uint8_t tx_phys; uint8_t rx_phys; @@ -936,6 +958,8 @@ struct pdu_data_llctrl { struct pdu_data_llctrl_ping_rsp ping_rsp; struct pdu_data_llctrl_length_req length_req; struct pdu_data_llctrl_length_rsp length_rsp; + struct pdu_data_llctrl_fsu_req fsu_req; + struct pdu_data_llctrl_fsu_rsp fsu_rsp; struct pdu_data_llctrl_phy_req phy_req; struct pdu_data_llctrl_phy_rsp phy_rsp; struct pdu_data_llctrl_phy_upd_ind phy_upd_ind; diff --git a/subsys/bluetooth/controller/ll_sw/ull_central.c b/subsys/bluetooth/controller/ll_sw/ull_central.c index 58c201b636c82..28fe773a82d4a 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central.c @@ -227,7 +227,7 @@ uint8_t ll_create_connection(uint16_t scan_interval, uint16_t scan_window, #if defined(CONFIG_BT_CTLR_DATA_LENGTH) ull_dle_init(conn, PHY_1M); #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ - + ull_fsu_init(conn); #if defined(CONFIG_BT_CTLR_CONN_RSSI) conn_lll->rssi_latest = BT_HCI_LE_RSSI_NOT_AVAILABLE; #if defined(CONFIG_BT_CTLR_CONN_RSSI_EVENT) diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c index 3e6908417b0ae..e953ef82c3b5d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c @@ -2380,6 +2380,13 @@ void ull_conn_update_parameters(struct ll_conn *conn, uint8_t is_cu_proc, uint8_ lll->tifs_tx_us = EVENT_IFS_DEFAULT_US; lll->tifs_rx_us = EVENT_IFS_DEFAULT_US; lll->tifs_hcto_us = EVENT_IFS_DEFAULT_US; + for (size_t i = 0; i < 3; i++) { + conn->lll.fsu.perphy[i].fsu_min = EVENT_IFS_DEFAULT_US; + conn->lll.fsu.perphy[i].fsu_max = EVENT_IFS_DEFAULT_US; + conn->lll.fsu.perphy[i].phys = PHY_1M | PHY_2M | PHY_CODED; + conn->lll.fsu.perphy[i].spacing_type = + T_IFS_ACL_PC | T_IFS_ACL_CP | T_IFS_CIS; + } #if defined(CONFIG_BT_CTLR_DATA_LENGTH) && \ defined(CONFIG_BT_CTLR_SLOT_RESERVATION_UPDATE) @@ -2417,6 +2424,14 @@ void ull_conn_update_parameters(struct ll_conn *conn, uint8_t is_cu_proc, uint8_ lll->tifs_tx_us = CONFIG_BT_CTLR_EVENT_IFS_LOW_LAT_US; lll->tifs_rx_us = CONFIG_BT_CTLR_EVENT_IFS_LOW_LAT_US; lll->tifs_hcto_us = CONFIG_BT_CTLR_EVENT_IFS_LOW_LAT_US; + for (size_t i = 0; i < 3; i++) { + conn->lll.fsu.perphy[i].fsu_min = + CONFIG_BT_CTLR_EVENT_IFS_LOW_LAT_US; + conn->lll.fsu.perphy[i].fsu_max = EVENT_IFS_US; + conn->lll.fsu.perphy[i].phys = PHY_1M | PHY_2M | PHY_CODED; + conn->lll.fsu.perphy[i].spacing_type = + T_IFS_ACL_PC | T_IFS_ACL_CP | T_IFS_CIS; + } /* Reserve only the processing overhead, on overlap the * is_abort_cb mechanism will ensure to continue the event so * as to not loose anchor point sync. @@ -2832,6 +2847,132 @@ void ull_conn_default_tx_time_set(uint16_t tx_time) } #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ +uint8_t ull_fsu_update_eff(struct ll_conn *conn) +{ + uint8_t fsu_changed = 0U; + uint8_t phy_tx; + uint8_t phy_rx; + +#if defined(CONFIG_BT_PHY_UPDATE) + phy_tx = conn->lll.phy_tx; + phy_rx = conn->lll.phy_rx; +#else + phy_tx = PHY_1M; + phy_rx = PHY_1M; +#endif /* CONFIG_BT_PHY_UPDATE */ + + fsu_changed = ull_fsu_update_eff_from_local(conn); + + if (fsu_changed) { + /* TODO: confirm that we do not need to do something here? */ + } + + if ((conn->lll.fsu.local.spacing_type & T_IFS_CIS) == T_IFS_CIS) { + + if (conn->lll.tifs_cis_us == conn->lll.fsu.eff.fsu_min) { + fsu_changed = 1; + } + conn->lll.tifs_cis_us = conn->lll.fsu.eff.fsu_min; + } + + if ((conn->lll.fsu.local.spacing_type & T_IFS_ACL_CP) == T_IFS_ACL_CP) { + if (conn->lll.role == BT_HCI_ROLE_PERIPHERAL) { + if (conn->lll.fsu.local.phys & phy_tx) { + if (conn->lll.tifs_tx_us == + conn->lll.fsu.eff.fsu_min) { + fsu_changed = 1; + } + conn->lll.tifs_tx_us = conn->lll.fsu.eff.fsu_min; + } + } else { + if (conn->lll.fsu.local.phys & phy_rx) { + if (conn->lll.tifs_rx_us == + conn->lll.fsu.eff.fsu_min) { + fsu_changed = 1; + } + conn->lll.tifs_rx_us = conn->lll.fsu.eff.fsu_min; + } + } + } + + if ((conn->lll.fsu.local.spacing_type & T_IFS_ACL_PC) == T_IFS_ACL_PC) { + if (conn->lll.role == BT_HCI_ROLE_PERIPHERAL) { + if (conn->lll.fsu.local.phys & phy_rx) { + if (conn->lll.tifs_rx_us == + conn->lll.fsu.eff.fsu_min) { + fsu_changed = 1; + } + conn->lll.tifs_rx_us = conn->lll.fsu.eff.fsu_min; + } + } else { + if (conn->lll.fsu.local.phys & phy_tx) { + if (conn->lll.tifs_tx_us == + conn->lll.fsu.eff.fsu_min) { + fsu_changed = 1; + } + conn->lll.tifs_tx_us = conn->lll.fsu.eff.fsu_min; + } + } + } + if (fsu_changed == 1) { + conn->lll.fsu.local.phys = 0; + conn->lll.fsu.local.spacing_type = 0; + } + + return fsu_changed; +} + +uint8_t ull_fsu_update_eff_from_local(struct ll_conn *conn) +{ + uint8_t fsu_changed = 0U; + uint16_t fsu_min, fsu_max; + + fsu_min = MAX(conn->lll.fsu.local.fsu_min, CONFIG_BT_CTLR_EVENT_IFS_LOW_LAT_US); + fsu_max = MAX(conn->lll.fsu.local.fsu_max, CONFIG_BT_CTLR_EVENT_IFS_LOW_LAT_US); + + conn->lll.fsu.eff.fsu_min = fsu_min; + conn->lll.fsu.eff.fsu_max = fsu_max; + conn->lll.fsu.local.fsu_min = fsu_min; + conn->lll.fsu.local.fsu_max = fsu_max; + + return fsu_changed; +} + +void ull_fsu_local_tx_update(struct ll_conn *conn, uint16_t fsu_min, + uint16_t fsu_max, uint8_t phys, uint16_t spacing_type) +{ + conn->lll.fsu.local.fsu_min = fsu_min; + if (conn->lll.tifs_rx_us > fsu_max) { + fsu_max = conn->lll.tifs_rx_us; + } + if (conn->lll.tifs_tx_us > fsu_max) { + fsu_max = conn->lll.tifs_tx_us; + } + conn->lll.fsu.local.fsu_max = fsu_max; + conn->lll.fsu.local.phys = phys; + conn->lll.fsu.local.spacing_type = spacing_type; +} + +uint8_t ull_fsu_init(struct ll_conn *conn) +{ + conn->lll.tifs_rx_us = EVENT_IFS_US; + conn->lll.tifs_tx_us = EVENT_IFS_US; + conn->lll.tifs_cis_us = EVENT_IFS_US; + conn->lll.fsu.local.fsu_min = CONFIG_BT_CTLR_EVENT_IFS_LOW_LAT_US; + conn->lll.fsu.local.fsu_max = EVENT_IFS_MAX_US; + conn->lll.fsu.eff.fsu_min = EVENT_IFS_US; + conn->lll.fsu.eff.fsu_max = EVENT_IFS_US; + for (size_t i = 0; i < 3; i++) { + conn->lll.fsu.perphy[i].fsu_min = EVENT_IFS_US; + conn->lll.fsu.perphy[i].fsu_max = EVENT_IFS_US; + conn->lll.fsu.perphy[i].phys = PHY_1M | PHY_2M | PHY_CODED; + conn->lll.fsu.perphy[i].spacing_type = + T_IFS_ACL_PC | T_IFS_ACL_CP | T_IFS_CIS; + } + + return 0; +} + #if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER) static bool ticker_op_id_match_func(uint8_t ticker_id, uint32_t ticks_slot, uint32_t ticks_to_expire, void *op_context) diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h b/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h index 59b45579f0b01..1cd28b39dce8f 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_internal.h @@ -109,8 +109,15 @@ uint8_t ull_dle_update_eff(struct ll_conn *conn); uint8_t ull_dle_update_eff_tx(struct ll_conn *conn); uint8_t ull_dle_update_eff_rx(struct ll_conn *conn); +uint8_t ull_fsu_update_eff(struct ll_conn *conn); +uint8_t ull_fsu_update_eff_from_local(struct ll_conn *conn); +uint8_t ull_fsu_init(struct ll_conn *conn); + void ull_dle_local_tx_update(struct ll_conn *conn, uint16_t tx_octets, uint16_t tx_time); +void ull_fsu_local_tx_update(struct ll_conn *conn, uint16_t fsu_min, + uint16_t fsu_max, uint8_t phys, uint16_t spacing_type); + void ull_conn_default_phy_tx_set(uint8_t tx); void ull_conn_default_phy_rx_set(uint8_t rx); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp.c b/subsys/bluetooth/controller/ll_sw/ull_llcp.c index f40e98ad96c7f..f14cbb6c90a5c 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp.c @@ -89,6 +89,9 @@ static uint8_t MALIGN(4) buffer_mem_remote_ctx[PROC_CTX_BUF_SIZE * CONFIG_BT_CTLR_LLCP_REMOTE_PROC_CTX_BUF_NUM]; static struct llcp_mem_pool mem_remote_ctx = { .pool = buffer_mem_remote_ctx }; +uint8_t ull_cp_fsu(struct ll_conn *conn, uint16_t fsu_min, uint16_t fsu_max, + uint8_t phys, uint16_t spacing_type); + /* * LLCP Resource Management */ @@ -856,6 +859,20 @@ uint8_t ull_cp_cis_create(struct ll_conn *conn, struct ll_conn_iso_stream *cis) } #endif /* defined(CONFIG_BT_CTLR_CENTRAL_ISO) */ +uint8_t bt_ull_cp_fsu(uint16_t handle, uint16_t fsu_min, uint16_t fsu_max, + uint8_t phys, uint16_t spacing_type) +{ + struct ll_conn *conn; + uint8_t err; + + conn = ll_connected_get(handle); + if (!conn) { + return BT_HCI_ERR_UNKNOWN_CONN_ID; + } + err = ull_cp_fsu(conn, fsu_min, fsu_max, phys, spacing_type); + return err; +} + #if defined(CONFIG_BT_CENTRAL) uint8_t ull_cp_chan_map_update(struct ll_conn *conn, const uint8_t chm[5]) { @@ -926,6 +943,27 @@ uint8_t ull_cp_data_length_update(struct ll_conn *conn, uint16_t max_tx_octets, } #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ +uint8_t ull_cp_fsu(struct ll_conn *conn, uint16_t fsu_min, uint16_t fsu_max, + uint8_t phys, uint16_t spacing_type) +{ + struct proc_ctx *ctx; + + if (!feature_fsu(conn)) { + return BT_HCI_ERR_SUCCESS; + } + + ctx = llcp_create_local_procedure(PROC_FRAME_SPACE); + if (!ctx) { + return BT_HCI_ERR_CMD_DISALLOWED; + } + + ull_fsu_local_tx_update(conn, fsu_min, fsu_max, phys, spacing_type); + + llcp_lr_enqueue(conn, ctx); + + return BT_HCI_ERR_SUCCESS; +} + #if defined(CONFIG_BT_CTLR_SCA_UPDATE) uint8_t ull_cp_req_peer_sca(struct ll_conn *conn) { @@ -1153,6 +1191,15 @@ uint8_t ull_cp_remote_dle_pending(struct ll_conn *conn) } #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ +uint8_t ull_cp_remote_fsu_pending(struct ll_conn *conn) +{ + struct proc_ctx *ctx; + + ctx = llcp_rr_peek(conn); + + return (ctx && ctx->proc == PROC_FRAME_SPACE); +} + #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) void ull_cp_conn_param_req_reply(struct ll_conn *conn) { @@ -1770,6 +1817,16 @@ static bool pdu_validate_length_rsp(struct pdu_data *pdu) return VALIDATE_PDU_LEN(pdu, length_rsp); } +static bool pdu_validate_fsu_req(struct pdu_data *pdu) +{ + return VALIDATE_PDU_LEN(pdu, fsu_req); +} + +static bool pdu_validate_fsu_rsp(struct pdu_data *pdu) +{ + return VALIDATE_PDU_LEN(pdu, fsu_rsp); +} + #if defined(CONFIG_BT_CTLR_PHY) static bool pdu_validate_phy_req(struct pdu_data *pdu) { @@ -1881,6 +1938,8 @@ static const struct pdu_validate pdu_validate[] = { [PDU_DATA_LLCTRL_TYPE_LENGTH_REQ] = { pdu_validate_length_req }, #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ [PDU_DATA_LLCTRL_TYPE_LENGTH_RSP] = { pdu_validate_length_rsp }, + [PDU_DATA_LLCTRL_TYPE_FRAME_SPACE_REQ] = { pdu_validate_fsu_req }, + [PDU_DATA_LLCTRL_TYPE_FRAME_SPACE_RSP] = { pdu_validate_fsu_rsp }, #if defined(CONFIG_BT_CTLR_PHY) [PDU_DATA_LLCTRL_TYPE_PHY_REQ] = { pdu_validate_phy_req }, #endif /* CONFIG_BT_CTLR_PHY */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp.h b/subsys/bluetooth/controller/ll_sw/ull_llcp.h index 3b5a6c2131c15..13b25f987bd2d 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp.h +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp.h @@ -143,6 +143,11 @@ void ull_cp_conn_param_req_neg_reply(struct ll_conn *conn, uint8_t error_code); */ uint8_t ull_cp_remote_dle_pending(struct ll_conn *conn); +/** + * @brief Check if a remote frame space update is pending + */ +uint8_t ull_cp_remote_fsu_pending(struct ll_conn *conn); + /** * @brief Check if a remote connection param reg is in the * works. @@ -251,6 +256,12 @@ bool ull_lp_cc_is_enqueued(struct ll_conn *conn, const struct ll_conn_iso_stream */ uint8_t ull_cp_chan_map_update(struct ll_conn *conn, const uint8_t chm[5]); +/** + * @brief Initiate frame space update procedure + */ +uint8_t ull_cp_fsu(struct ll_conn *conn, uint16_t fsu_min, uint16_t fsu_max, + uint8_t phys, uint16_t spacing_type); + /** * @brief Check if Channel Map Update Procedure is pending */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c index 84098f1b149fd..fe1f03db0aa4a 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_common.c @@ -204,6 +204,10 @@ static void lp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx) ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_LENGTH_RSP; break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + case PROC_FRAME_SPACE: + llcp_pdu_encode_fsu_req(conn, pdu); + ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_FRAME_SPACE_RSP; + break; #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) case PROC_CTE_REQ: llcp_pdu_encode_cte_req(ctx, pdu); @@ -280,6 +284,12 @@ static void lp_comm_ntf_length_change(struct ll_conn *conn, struct proc_ctx *ctx } #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ +static void lp_comm_ntf_fsu_change(struct ll_conn *conn, struct proc_ctx *ctx, + struct pdu_data *pdu) +{ + llcp_ntf_encode_fsu_change(conn, pdu); +} + #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) static void lp_comm_complete_cte_req_finalize(struct ll_conn *conn) @@ -413,6 +423,9 @@ static void lp_comm_ntf(struct ll_conn *conn, struct proc_ctx *ctx) lp_comm_ntf_length_change(conn, ctx, pdu); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + case PROC_FRAME_SPACE: + lp_comm_ntf_fsu_change(conn, ctx, pdu); + break; #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) case PROC_CTE_REQ: lp_comm_ntf_cte_req(conn, ctx, pdu); @@ -548,6 +561,27 @@ static void lp_comm_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t } break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + case PROC_FRAME_SPACE: + if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_FRAME_SPACE_RSP) { + uint8_t fsu_changed = ull_fsu_update_eff(conn); + + if (fsu_changed) { + lp_comm_ntf(conn, ctx); + } + llcp_lr_complete(conn); + ctx->state = LP_COMMON_STATE_IDLE; + + } else if (ctx->response_opcode == PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP) { + /* unmask support for Frame Spacing */ + llcp_lr_complete(conn); + ctx->state = LP_COMMON_STATE_IDLE; + } else { + /* Illegal response opcode */ + lp_comm_terminate_invalid_pdu(conn, ctx); + break; + } + + break; #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) case PROC_CTE_REQ: lp_comm_complete_cte_req(conn, ctx); @@ -684,6 +718,24 @@ static void lp_comm_send_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t } break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + case PROC_FRAME_SPACE: + if (feature_fsu(conn) && !ull_cp_remote_fsu_pending(conn)) { + if (llcp_lr_ispaused(conn) || !llcp_tx_alloc_peek(conn, ctx)) { + ctx->state = LP_COMMON_STATE_WAIT_TX; + } else { + /* llcp_tx_pause_data(conn, LLCP_TX_QUEUE_PAUSE_DATA_FRAME_SPACE); + */ + lp_comm_tx(conn, ctx); + ctx->state = LP_COMMON_STATE_WAIT_RX; + } + } else { + /* REQ was received from peer and RSP not yet sent, lets piggy-back on RSP + * instead of sending REQ + */ + llcp_lr_complete(conn); + ctx->state = LP_COMMON_STATE_IDLE; + } + break; #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) case PROC_CTE_REQ: if (conn->llcp.cte_req.is_enabled && @@ -826,6 +878,9 @@ static void lp_comm_rx_decode(struct ll_conn *conn, struct proc_ctx *ctx, struct llcp_pdu_decode_length_rsp(conn, pdu); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + case PDU_DATA_LLCTRL_TYPE_FRAME_SPACE_RSP: + llcp_pdu_decode_fsu_rsp(conn, pdu); + break; #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) case PDU_DATA_LLCTRL_TYPE_CTE_RSP: llcp_pdu_decode_cte_rsp(ctx, pdu); @@ -1022,6 +1077,13 @@ static void rp_comm_rx_decode(struct ll_conn *conn, struct proc_ctx *ctx, struct llcp_rx_node_retain(ctx); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + case PDU_DATA_LLCTRL_TYPE_FRAME_SPACE_REQ: + /* receive req from remote */ + llcp_pdu_decode_fsu_req(conn, pdu); + ull_fsu_update_eff(conn); + + llcp_rx_node_retain(ctx); + break; #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) case PDU_DATA_LLCTRL_TYPE_CTE_REQ: llcp_pdu_decode_cte_req(ctx, pdu); @@ -1072,6 +1134,21 @@ static void rp_comm_tx(struct ll_conn *conn, struct proc_ctx *ctx) ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + case PROC_FRAME_SPACE: + if ((conn->lll.fsu.local.phys & 0x04)) { + llcp_pdu_encode_reject_ext_ind(pdu, PDU_DATA_LLCTRL_TYPE_FRAME_SPACE_REQ, + BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL); + } else if (!IS_ENABLED(CONFIG_BT_ISO) && + ((conn->lll.fsu.local.spacing_type & (T_IFS_CIS | T_MSS_CIS)))) { + llcp_pdu_encode_reject_ext_ind(pdu, PDU_DATA_LLCTRL_TYPE_FRAME_SPACE_REQ, + BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL); + } else { + llcp_pdu_encode_fsu_rsp(conn, pdu); + } + ctx->node_ref.tx_ack = tx; + ctx->rx_opcode = PDU_DATA_LLCTRL_TYPE_UNUSED; + + break; #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) case PROC_CTE_REQ: { uint8_t err_code = 0; @@ -1138,11 +1215,10 @@ static void rp_comm_st_idle(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t break; } } -#if defined(CONFIG_BT_CTLR_DATA_LENGTH) + static void rp_comm_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t generate_ntf) { struct node_rx_pdu *ntf; - struct pdu_data *pdu; /* Allocate ntf node */ ntf = ctx->node_ref.rx; @@ -1155,18 +1231,22 @@ static void rp_comm_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t gene /* And release memory if no NTF to be generated */ ntf->hdr.type = NODE_RX_TYPE_RELEASE; +#if defined(CONFIG_BT_CTLR_DATA_LENGTH) + if (generate_ntf) { + struct pdu_data *pdu; + ntf->hdr.type = NODE_RX_TYPE_DC_PDU; ntf->hdr.handle = conn->lll.handle; pdu = (struct pdu_data *)ntf->pdu; LL_ASSERT_DBG(ctx->proc == PROC_DATA_LENGTH_UPDATE); llcp_ntf_encode_length_change(conn, pdu); } +#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ /* Enqueue notification towards LL - releases mem if no ntf */ ll_rx_put_sched(ntf->hdr.link, ntf); } -#endif /* CONFIG_BT_CTLR_DATA_LENGTH */ static bool rp_comm_tx_proxy(struct ll_conn *conn, struct proc_ctx *ctx, const bool complete) { @@ -1270,6 +1350,9 @@ static void rp_comm_send_rsp(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t rp_comm_tx_proxy(conn, ctx, false); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + case PROC_FRAME_SPACE: + rp_comm_tx_proxy(conn, ctx, false); + break; #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) case PROC_CTE_REQ: if (llcp_rr_ispaused(conn) || @@ -1360,6 +1443,17 @@ static void rp_comm_st_wait_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, u break; } #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + case PROC_FRAME_SPACE: { + uint8_t fsu_changed = ull_fsu_update_eff(conn); + + fsu_changed |= ctx->data.fsu.ntf_fsu; + + rp_comm_ntf(conn, ctx, fsu_changed); + + llcp_rr_complete(conn); + ctx->state = RP_COMMON_STATE_IDLE; + break; + } #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) case PROC_CTE_REQ: { /* add PHY update pause = false here */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_features.h b/subsys/bluetooth/controller/ll_sw/ull_llcp_features.h index c06d4978f2c65..d3dd6a0c835ad 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_features.h +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_features.h @@ -68,6 +68,11 @@ static inline bool feature_dle(struct ll_conn *conn) #endif } +static inline bool feature_fsu(struct ll_conn *conn) +{ + return (conn->llcp.fex.features_used & LL_FEAT_BIT_FRAME_SPACE) != 0; +} + static inline bool feature_privacy(struct ll_conn *conn) { #if defined(CONFIG_BT_CTLR_PRIVACY) diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h b/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h index 9719ea8fc72ed..176c03e5835ff 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_internal.h @@ -30,6 +30,7 @@ enum llcp_proc { PROC_CIS_TERMINATE, PROC_SCA_UPDATE, PROC_PERIODIC_SYNC, + PROC_FRAME_SPACE, /* A helper enum entry, to use in pause procedure context */ PROC_NONE = 0x0, }; @@ -225,6 +226,9 @@ struct proc_ctx { uint8_t ntf_dle; } dle; #endif + struct { + uint8_t ntf_fsu; + } fsu; /* Connection Update & Connection Parameter Request */ struct { @@ -740,6 +744,15 @@ void llcp_ntf_encode_length_change(struct ll_conn *conn, #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ +/* + * Frame Space Procedure Helper + */ +void llcp_pdu_encode_fsu_req(struct ll_conn *conn, struct pdu_data *pdu); +void llcp_pdu_encode_fsu_rsp(struct ll_conn *conn, struct pdu_data *pdu); +void llcp_pdu_decode_fsu_req(struct ll_conn *conn, struct pdu_data *pdu); +void llcp_pdu_decode_fsu_rsp(struct ll_conn *conn, struct pdu_data *pdu); +void llcp_ntf_encode_fsu_change(struct ll_conn *conn, struct pdu_data *pdu); + #if defined(CONFIG_BT_CTLR_SCA_UPDATE) /* * Sleep Clock Accuracy Update Procedure Helper diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c index ecce8fd9013aa..c1a01aeae676f 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_local.c @@ -332,6 +332,9 @@ void llcp_lr_rx(struct ll_conn *conn, struct proc_ctx *ctx, memq_link_t *link, llcp_lp_comm_rx(conn, ctx, rx); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + case PROC_FRAME_SPACE: + llcp_lp_comm_rx(conn, ctx, rx); + break; #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) case PROC_CTE_REQ: llcp_lp_comm_rx(conn, ctx, rx); @@ -382,6 +385,9 @@ void llcp_lr_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node_tx * llcp_lp_comm_tx_ack(conn, ctx, tx); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + case PROC_FRAME_SPACE: + llcp_lp_comm_tx_ack(conn, ctx, tx); + break; #ifdef CONFIG_BT_CTLR_PHY case PROC_PHY_UPDATE: llcp_lp_pu_tx_ack(conn, ctx, tx); @@ -475,6 +481,9 @@ static void lr_act_run(struct ll_conn *conn) llcp_lp_comm_run(conn, ctx, NULL); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + case PROC_FRAME_SPACE: + llcp_lp_comm_run(conn, ctx, NULL); + break; #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) case PROC_CTE_REQ: /* 3rd partam null? */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c index 409200f4116dd..31793e1adc1dc 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_pdu.c @@ -730,6 +730,99 @@ void llcp_pdu_decode_length_rsp(struct ll_conn *conn, struct pdu_data *pdu) } #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ +void llcp_pdu_encode_fsu_req(struct ll_conn *conn, struct pdu_data *pdu) +{ + struct pdu_data_llctrl_fsu_req *p; + + pdu->ll_id = PDU_DATA_LLID_CTRL; + pdu->len = sizeof(struct pdu_data_llctrl_fsu_req) + 1U; + pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_FRAME_SPACE_REQ; + p = &pdu->llctrl.fsu_req; + + p->fsu_min = sys_cpu_to_le16(conn->lll.fsu.local.fsu_min); + p->fsu_max = sys_cpu_to_le16(conn->lll.fsu.local.fsu_max); + p->phys = conn->lll.fsu.local.phys; + p->spacing_type = sys_cpu_to_le16(conn->lll.fsu.local.spacing_type); +} + +void llcp_pdu_encode_fsu_rsp(struct ll_conn *conn, struct pdu_data *pdu) +{ + struct pdu_data_llctrl_fsu_rsp *p; + + pdu->ll_id = PDU_DATA_LLID_CTRL; + pdu->len = sizeof(struct pdu_data_llctrl_fsu_rsp) + 1U; + pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_FRAME_SPACE_RSP; + p = &pdu->llctrl.fsu_rsp; + + p->fsu = sys_cpu_to_le16(conn->lll.fsu.local.fsu_min); + p->phys = conn->lll.fsu.local.phys; + p->spacing_type = sys_cpu_to_le16(conn->lll.fsu.local.spacing_type); + printk("%s: fsu %u\n", __func__, p->fsu); +} + +void llcp_ntf_encode_fsu_change(struct ll_conn *conn, struct pdu_data *pdu) +{ + struct pdu_data_llctrl_fsu_rsp *p; + + pdu->ll_id = PDU_DATA_LLID_CTRL; + pdu->len = sizeof(struct pdu_data_llctrl_fsu_rsp) + 1U; + pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_FRAME_SPACE_RSP; + p = &pdu->llctrl.fsu_rsp; + + p->fsu = sys_cpu_to_le16(conn->lll.fsu.eff.fsu_min); + p->phys = conn->lll.fsu.local.phys; + p->spacing_type = sys_cpu_to_le16(conn->lll.fsu.eff.spacing_type); +} + +void llcp_pdu_decode_fsu_req(struct ll_conn *conn, struct pdu_data *pdu) +{ + struct pdu_data_llctrl_fsu_req *p; + + p = &pdu->llctrl.fsu_req; + conn->lll.fsu.local.fsu_min = sys_le16_to_cpu(p->fsu_min); + conn->lll.fsu.local.fsu_max = sys_le16_to_cpu(p->fsu_max); + conn->lll.fsu.local.phys = p->phys & 0x07; /* mask out RFU bits */ + conn->lll.fsu.local.spacing_type = + sys_le16_to_cpu(p->spacing_type & 0x1F); /* mask out RFU bits */ + /* nitpic, perphy is confusing, call it phy*/ + for (size_t i = 0; i < 3; i++) { + if (p->phys & BIT(i)) { + conn->lll.fsu.perphy[i].fsu_min = + sys_le16_to_cpu(p->fsu_min); + conn->lll.fsu.perphy[i].fsu_max = + sys_le16_to_cpu(p->fsu_max); + conn->lll.fsu.perphy[i].phys = p->phys & 0x07; + conn->lll.fsu.perphy[i].spacing_type = + sys_le16_to_cpu(p->spacing_type & 0x1F); + } + } +} + +void llcp_pdu_decode_fsu_rsp(struct ll_conn *conn, struct pdu_data *pdu) +{ + struct pdu_data_llctrl_fsu_rsp *p; + + p = &pdu->llctrl.fsu_rsp; + + conn->lll.fsu.local.fsu_min = sys_le16_to_cpu(p->fsu); + conn->lll.fsu.local.fsu_max = sys_le16_to_cpu(p->fsu); + conn->lll.fsu.local.phys = p->phys & 0x07; /* mask out RFU bits */ + conn->lll.fsu.local.spacing_type = + sys_le16_to_cpu(p->spacing_type & 0x1F); /* mask out RFU bits */ + + for (size_t i = 0; i < 3; i++) { + if (p->phys & BIT(i)) { + conn->lll.fsu.perphy[i].fsu_min = + sys_le16_to_cpu(p->fsu); + conn->lll.fsu.perphy[i].fsu_max = + sys_le16_to_cpu(p->fsu); + conn->lll.fsu.perphy[i].phys = p->phys & 0x07; + conn->lll.fsu.perphy[i].spacing_type = + sys_le16_to_cpu(p->spacing_type & 0x1F); + } + } +} + #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_REQ) /* * Constant Tone Request Procedure Helper diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c index 9e8ebaf7a4012..51f67cfec24e5 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_phy.c @@ -318,6 +318,49 @@ static uint8_t pu_update_eff_times(struct ll_conn *conn, struct proc_ctx *ctx) } #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ +static uint8_t pu_update_eff_tifs(struct ll_conn *conn, struct proc_ctx *ctx) +{ + uint8_t phy_index_tx, phy_index_rx; + + phy_index_tx = + conn->lll.phy_tx == 4 ? 2 : conn->lll.phy_tx - 1; /* a bit tricky but should work */ + phy_index_rx = + conn->lll.phy_rx == 4 ? 2 : conn->lll.phy_rx - 1; /* a bit tricky but should work */ + + if (((conn->lll.fsu.perphy[phy_index_tx].spacing_type & T_IFS_ACL_CP) == + T_IFS_ACL_CP) && + (conn->lll.role == BT_HCI_ROLE_PERIPHERAL)) { + conn->lll.fsu.eff.fsu_min = + conn->lll.fsu.perphy[phy_index_tx].fsu_min; + conn->lll.tifs_tx_us = conn->lll.fsu.eff.fsu_min; + } + if (((conn->lll.fsu.perphy[phy_index_tx].spacing_type & T_IFS_ACL_PC) == + T_IFS_ACL_PC) && + (conn->lll.role == BT_HCI_ROLE_CENTRAL)) { + conn->lll.fsu.eff.fsu_min = + conn->lll.fsu.perphy[phy_index_tx].fsu_min; + conn->lll.tifs_tx_us = conn->lll.fsu.eff.fsu_min; + } + + if (((conn->lll.fsu.perphy[phy_index_rx].spacing_type & T_IFS_ACL_CP) == + T_IFS_ACL_CP) && + (conn->lll.role == BT_HCI_ROLE_CENTRAL)) { + conn->lll.fsu.eff.fsu_min = + conn->lll.fsu.perphy[phy_index_rx].fsu_min; + conn->lll.tifs_rx_us = conn->lll.fsu.eff.fsu_min; + } + + if (((conn->lll.fsu.perphy[phy_index_rx].spacing_type & T_IFS_ACL_PC) == + T_IFS_ACL_PC) && + (conn->lll.role == BT_HCI_ROLE_PERIPHERAL)) { + conn->lll.fsu.eff.fsu_min = + conn->lll.fsu.perphy[phy_index_rx].fsu_min; + conn->lll.tifs_rx_us = conn->lll.fsu.eff.fsu_min; + } + + return 0; +} + static inline void pu_set_preferred_phys(struct ll_conn *conn, struct proc_ctx *ctx) { conn->phy_pref_rx = ctx->data.pu.rx; @@ -778,6 +821,10 @@ static void lp_pu_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint ctx->data.pu.ntf_dle = pu_update_eff_times(conn, ctx); } #endif + if (phy_changed) { + pu_update_eff_tifs(conn, ctx); + } + llcp_rr_set_incompat(conn, INCOMPAT_NO_COLLISION); ctx->data.pu.error = BT_HCI_ERR_SUCCESS; ctx->data.pu.ntf_pu = (phy_changed || ctx->data.pu.host_initiated); @@ -1201,6 +1248,10 @@ static void rp_pu_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint ctx->data.pu.ntf_dle = pu_update_eff_times(conn, ctx); } #endif + if (phy_changed) { + pu_update_eff_tifs(conn, ctx); + } + /* if PHY settings changed we should generate NTF */ ctx->data.pu.ntf_pu = phy_changed; rp_pu_complete(conn, ctx, evt, param); diff --git a/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c b/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c index 3a90a9d950ba2..c219ac2e8d529 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c +++ b/subsys/bluetooth/controller/ll_sw/ull_llcp_remote.c @@ -91,6 +91,7 @@ static bool proc_with_instant(struct proc_ctx *ctx) case PROC_ENCRYPTION_PAUSE: case PROC_TERMINATE: case PROC_DATA_LENGTH_UPDATE: + case PROC_FRAME_SPACE: case PROC_CTE_REQ: case PROC_CIS_TERMINATE: case PROC_CIS_CREATE: @@ -292,6 +293,9 @@ void llcp_rr_rx(struct ll_conn *conn, struct proc_ctx *ctx, memq_link_t *link, llcp_rp_comm_rx(conn, ctx, rx); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + case PROC_FRAME_SPACE: + llcp_rp_comm_rx(conn, ctx, rx); + break; #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) case PROC_CTE_REQ: llcp_rp_comm_rx(conn, ctx, rx); @@ -339,6 +343,9 @@ void llcp_rr_tx_ack(struct ll_conn *conn, struct proc_ctx *ctx, struct node_tx * llcp_rp_comm_tx_ack(conn, ctx, tx); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + case PROC_FRAME_SPACE: + llcp_rp_comm_tx_ack(conn, ctx, tx); + break; #ifdef CONFIG_BT_CTLR_PHY case PROC_PHY_UPDATE: llcp_rp_pu_tx_ack(conn, ctx, tx); @@ -432,6 +439,9 @@ static void rr_act_run(struct ll_conn *conn) llcp_rp_comm_run(conn, ctx, NULL); break; #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ + case PROC_FRAME_SPACE: + llcp_rp_comm_run(conn, ctx, NULL); + break; #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RSP) case PROC_CTE_REQ: llcp_rp_comm_run(conn, ctx, NULL); @@ -878,6 +888,8 @@ static const struct proc_role new_proc_lut[] = { [PDU_DATA_LLCTRL_TYPE_LENGTH_REQ] = { PROC_DATA_LENGTH_UPDATE, ACCEPT_ROLE_BOTH }, #endif /* CONFIG_BT_CTLR_DATA_LENGTH */ [PDU_DATA_LLCTRL_TYPE_LENGTH_RSP] = { PROC_UNKNOWN, ACCEPT_ROLE_NONE }, + [PDU_DATA_LLCTRL_TYPE_FRAME_SPACE_REQ] = { PROC_FRAME_SPACE, ACCEPT_ROLE_BOTH }, + [PDU_DATA_LLCTRL_TYPE_FRAME_SPACE_RSP] = { PROC_FRAME_SPACE, ACCEPT_ROLE_BOTH }, #if defined(CONFIG_BT_CTLR_PHY) [PDU_DATA_LLCTRL_TYPE_PHY_REQ] = { PROC_PHY_UPDATE, ACCEPT_ROLE_BOTH }, #endif /* CONFIG_BT_CTLR_PHY */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_peripheral.c b/subsys/bluetooth/controller/ll_sw/ull_peripheral.c index aa6db211ed197..e3944fb045230 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_peripheral.c +++ b/subsys/bluetooth/controller/ll_sw/ull_peripheral.c @@ -379,7 +379,7 @@ void ull_periph_setup(struct node_rx_pdu *rx, struct node_rx_ftr *ftr, max_rx_time = PDU_MAX_US(0U, 0U, PHY_1M); #endif /* !CONFIG_BT_CTLR_PHY */ #endif /* !CONFIG_BT_CTLR_PERIPHERAL_RESERVE_MAX */ - + ull_fsu_init(conn); #if defined(CONFIG_BT_CTLR_PHY) ready_delay_us = lll_radio_rx_ready_delay_get(lll->phy_rx, PHY_FLAGS_S8); #else /* CONFIG_BT_CTLR_PHY */