From 5e848761c5577106bddbf839ab9be85d94990aa0 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Thu, 15 Dec 2022 10:39:01 +0530 Subject: [PATCH] Bluetooth: Controller: legacy: Fix conn upd instant passed on data tx Fix legacy control procedure implementation to avoid connection update procedure with reason instant passed (0x28). Connection Update Indication PDU is enqueued after data enqueue to LLL context is paused and the enqueue resumes when already enqueued data PDUs are all acknowledged. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_adv.c | 1 + .../bluetooth/controller/ll_sw/ull_central.c | 1 + subsys/bluetooth/controller/ll_sw/ull_conn.c | 32 +++++++++++++++++++ .../controller/ll_sw/ull_conn_types.h | 1 + 4 files changed, 35 insertions(+) diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv.c b/subsys/bluetooth/controller/ll_sw/ull_adv.c index 14eaf08d469..49a82966614 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv.c @@ -1121,6 +1121,7 @@ uint8_t ll_adv_enable(uint8_t enable) conn->llcp_req = conn->llcp_ack = conn->llcp_type = 0; conn->llcp_rx = NULL; conn->llcp_cu.req = conn->llcp_cu.ack = 0; + conn->llcp_cu.pause_tx = 0U; conn->llcp_feature.req = conn->llcp_feature.ack = 0; conn->llcp_feature.features_conn = ll_feat_get(); conn->llcp_feature.features_peer = 0; diff --git a/subsys/bluetooth/controller/ll_sw/ull_central.c b/subsys/bluetooth/controller/ll_sw/ull_central.c index 0d236f34f8f..f78fba071eb 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_central.c +++ b/subsys/bluetooth/controller/ll_sw/ull_central.c @@ -314,6 +314,7 @@ uint8_t ll_create_connection(uint16_t scan_interval, uint16_t scan_window, conn->llcp_req = conn->llcp_ack = conn->llcp_type = 0U; conn->llcp_rx = NULL; conn->llcp_cu.req = conn->llcp_cu.ack = 0; + conn->llcp_cu.pause_tx = 0U; conn->llcp_feature.req = conn->llcp_feature.ack = 0; conn->llcp_feature.features_conn = ll_feat_get(); conn->llcp_feature.features_peer = 0; diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c index 336cfa7ae87..d31c9093008 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c @@ -1204,6 +1204,17 @@ int ull_conn_llcp(struct ll_conn *conn, uint32_t ticks_at_expire, uint16_t lazy) /* check if connection update procedure is requested */ if (conn->llcp_cu.ack != conn->llcp_cu.req) { + /* Delay until all pending Tx in LLL is acknowledged, + * new Tx PDUs will not be enqueued until we proceed to + * initiate connection update and get acknowledged. + * This is required to ensure PDU with instant can be + * transmitted before instant expires. + */ + if (memq_peek(conn->lll.memq_tx.head, + conn->lll.memq_tx.tail, NULL)) { + return 0; + } + /* switch to LLCP_CONN_UPD state machine */ conn->llcp_type = LLCP_CONN_UPD; conn->llcp_ack -= 2U; @@ -2019,6 +2030,7 @@ void ull_conn_tx_lll_enqueue(struct ll_conn *conn, uint8_t count) while (conn->tx_head && (( + (conn->llcp_cu.req == conn->llcp_cu.ack) && #if defined(CONFIG_BT_CTLR_PHY) !conn->llcp_phy.pause_tx && #endif /* CONFIG_BT_CTLR_PHY */ @@ -2938,6 +2950,7 @@ static inline void ctrl_tx_pause_enqueue(struct ll_conn *conn, if ( /* data/ctrl packet is in the head */ conn->tx_head && + !conn->llcp_cu.pause_tx && #if defined(CONFIG_BT_CTLR_LE_ENC) !conn->llcp_enc.pause_tx && #endif /* CONFIG_BT_CTLR_LE_ENC */ @@ -3287,8 +3300,15 @@ static inline int event_conn_upd_prep(struct ll_conn *conn, uint16_t lazy, llctrl.conn_update_ind.win_offset); pdu_ctrl_tx->llctrl.conn_update_ind.instant = sys_cpu_to_le16(conn->llcp.conn_upd.instant); + /* move to in progress */ conn->llcp_cu.state = LLCP_CUI_STATE_INPROG; + + /* Data PDU tx paused, as we ensure PDUs in LLL have all + * been ack-ed. + */ + conn->llcp_cu.pause_tx = 1U; + /* enqueue control PDU */ tx = CONTAINER_OF(pdu_ctrl_tx, struct node_tx, pdu); ctrl_tx_enqueue(conn, tx); @@ -3335,6 +3355,12 @@ static inline int event_conn_upd_prep(struct ll_conn *conn, uint16_t lazy, conn->lll.latency + 6; pdu_ctrl_tx->llctrl.conn_update_ind.instant = sys_cpu_to_le16(conn->llcp.conn_upd.instant); + + /* Data PDU tx paused, as we ensure PDUs in LLL have all been + * ack-ed. + */ + conn->llcp_cu.pause_tx = 1U; + /* enqueue control PDU */ ctrl_tx_enqueue(conn, tx); #endif /* !CONFIG_BT_CTLR_SCHED_ADVANCED */ @@ -6647,6 +6673,12 @@ static inline void ctrl_tx_ack(struct ll_conn *conn, struct node_tx **tx, conn->common.txn_lock = 0U; break; +#if defined(CONFIG_BT_CENTRAL) + case PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND: + conn->llcp_cu.pause_tx = 0U; + break; +#endif /* CONFIG_BT_CENTRAL */ + #if defined(CONFIG_BT_CTLR_LE_ENC) #if defined(CONFIG_BT_CENTRAL) case PDU_DATA_LLCTRL_TYPE_ENC_REQ: diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h index ee791521c9b..437b3c025bd 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h @@ -169,6 +169,7 @@ struct ll_conn { LLCP_CUI_STATE_REJECT, } state:3 __packed; uint8_t cmd:1; + uint8_t pause_tx:1; uint16_t interval; uint16_t latency; uint16_t timeout;