Bluetooth: controller: Implement cross connection CPR mutual exclusion
Porting mechanism as used in legacy LLCP to refactored CPR. Signed-off-by: Erik Brockhoff <erbr@oticon.com>
This commit is contained in:
parent
4ae3dc8cb2
commit
9498310c53
|
@ -97,6 +97,7 @@ enum {
|
|||
enum {
|
||||
RP_CU_STATE_IDLE,
|
||||
RP_CU_STATE_WAIT_RX_CONN_PARAM_REQ,
|
||||
RP_CU_STATE_WAIT_CONN_PARAM_REQ_AVAILABLE,
|
||||
RP_CU_STATE_WAIT_NTF_CONN_PARAM_REQ,
|
||||
RP_CU_STATE_WAIT_CONN_PARAM_REQ_REPLY,
|
||||
RP_CU_STATE_WAIT_CONN_PARAM_REQ_REPLY_CONTINUE,
|
||||
|
@ -202,7 +203,7 @@ static void lp_cu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t opcode)
|
|||
llcp_pdu_encode_conn_param_req(ctx, pdu);
|
||||
break;
|
||||
case PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND:
|
||||
llcp_pdu_encode_reject_ext_ind(pdu, PDU_DATA_LLCTRL_TYPE_CONN_PARAM_RSP,
|
||||
llcp_pdu_encode_reject_ext_ind(pdu, ctx->data.cu.rejected_opcode,
|
||||
ctx->data.cu.error);
|
||||
break;
|
||||
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
|
||||
|
@ -253,14 +254,27 @@ static void lp_cu_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
|
|||
ll_rx_sched();
|
||||
}
|
||||
|
||||
static void lp_cu_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
|
||||
static void lp_cu_complete(struct ll_conn *conn, struct proc_ctx *ctx)
|
||||
{
|
||||
llcp_lr_complete(conn);
|
||||
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
|
||||
if (ctx->proc == PROC_CONN_PARAM_REQ &&
|
||||
!(conn->lll.role && ull_cp_remote_cpr_pending(conn))) {
|
||||
/* For a peripheral without a remote initiated CPR */
|
||||
cpr_active_check_and_reset(conn);
|
||||
}
|
||||
#endif /* defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) */
|
||||
ctx->state = LP_CU_STATE_IDLE;
|
||||
}
|
||||
|
||||
static void lp_cu_wait_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
|
||||
void *param)
|
||||
{
|
||||
if (!llcp_ntf_alloc_is_available()) {
|
||||
ctx->state = LP_CU_STATE_WAIT_NTF;
|
||||
} else {
|
||||
lp_cu_ntf(conn, ctx);
|
||||
llcp_lr_complete(conn);
|
||||
ctx->state = LP_CU_STATE_IDLE;
|
||||
lp_cu_complete(conn, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,16 +287,15 @@ static void lp_cu_send_reject_ext_ind(struct ll_conn *conn, struct proc_ctx *ctx
|
|||
} else {
|
||||
llcp_rr_set_incompat(conn, INCOMPAT_NO_COLLISION);
|
||||
lp_cu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND);
|
||||
llcp_lr_complete(conn);
|
||||
ctx->state = LP_CU_STATE_IDLE;
|
||||
lp_cu_complete(conn, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static void lp_cu_send_conn_param_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
|
||||
void *param)
|
||||
{
|
||||
if (llcp_lr_ispaused(conn) || llcp_rr_get_collision(conn) ||
|
||||
!llcp_tx_alloc_peek(conn, ctx)) {
|
||||
if (cpr_active_is_set(conn) || llcp_lr_ispaused(conn) ||
|
||||
llcp_rr_get_collision(conn) || !llcp_tx_alloc_peek(conn, ctx)) {
|
||||
ctx->state = LP_CU_STATE_WAIT_TX_CONN_PARAM_REQ;
|
||||
} else {
|
||||
uint16_t event_counter = ull_conn_event_counter(conn);
|
||||
|
@ -298,6 +311,9 @@ static void lp_cu_send_conn_param_req(struct ll_conn *conn, struct proc_ctx *ctx
|
|||
ctx->data.cu.offset4 = 0xffffU;
|
||||
ctx->data.cu.offset5 = 0xffffU;
|
||||
|
||||
/* Mark CPR as active */
|
||||
cpr_active_set(conn);
|
||||
|
||||
lp_cu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ);
|
||||
|
||||
switch (conn->lll.role) {
|
||||
|
@ -409,6 +425,7 @@ static void lp_cu_st_wait_rx_conn_param_rsp(struct ll_conn *conn, struct proc_ct
|
|||
llcp_rr_set_incompat(conn, INCOMPAT_RESERVED);
|
||||
/* Perform Param check and possibly reject (LL_REJECT_EXT_IND) */
|
||||
if (!cu_check_conn_parameters(conn, ctx)) {
|
||||
ctx->data.cu.rejected_opcode = PDU_DATA_LLCTRL_TYPE_CONN_PARAM_RSP;
|
||||
ctx->data.cu.error = BT_HCI_ERR_INVALID_LL_PARAM;
|
||||
lp_cu_send_reject_ext_ind(conn, ctx, evt, param);
|
||||
break;
|
||||
|
@ -431,7 +448,7 @@ static void lp_cu_st_wait_rx_conn_param_rsp(struct ll_conn *conn, struct proc_ct
|
|||
} else {
|
||||
llcp_rr_set_incompat(conn, INCOMPAT_NO_COLLISION);
|
||||
ctx->data.cu.error = pdu->llctrl.reject_ext_ind.error_code;
|
||||
lp_cu_complete(conn, ctx, evt, param);
|
||||
lp_cu_wait_complete(conn, ctx, evt, param);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -468,11 +485,11 @@ static void lp_cu_st_wait_rx_conn_update_ind(struct ll_conn *conn, struct proc_c
|
|||
break;
|
||||
case LP_CU_EVT_UNKNOWN:
|
||||
ctx->data.cu.error = BT_HCI_ERR_UNSUPP_REMOTE_FEATURE;
|
||||
lp_cu_complete(conn, ctx, evt, param);
|
||||
lp_cu_wait_complete(conn, ctx, evt, param);
|
||||
break;
|
||||
case LP_CU_EVT_REJECT:
|
||||
ctx->data.cu.error = pdu->llctrl.reject_ext_ind.error_code;
|
||||
lp_cu_complete(conn, ctx, evt, param);
|
||||
lp_cu_wait_complete(conn, ctx, evt, param);
|
||||
break;
|
||||
default:
|
||||
/* Ignore other evts */
|
||||
|
@ -505,10 +522,9 @@ static void lp_cu_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint
|
|||
notify = cu_should_notify_host(ctx);
|
||||
if (notify) {
|
||||
ctx->data.cu.error = BT_HCI_ERR_SUCCESS;
|
||||
lp_cu_complete(conn, ctx, evt, param);
|
||||
lp_cu_wait_complete(conn, ctx, evt, param);
|
||||
} else {
|
||||
llcp_lr_complete(conn);
|
||||
ctx->state = LP_CU_STATE_IDLE;
|
||||
lp_cu_complete(conn, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -530,7 +546,7 @@ static void lp_cu_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_
|
|||
{
|
||||
switch (evt) {
|
||||
case LP_CU_EVT_RUN:
|
||||
lp_cu_complete(conn, ctx, evt, param);
|
||||
lp_cu_wait_complete(conn, ctx, evt, param);
|
||||
break;
|
||||
default:
|
||||
/* Ignore other evts */
|
||||
|
@ -605,8 +621,7 @@ void llcp_lp_cu_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pd
|
|||
/* Invalid behaviour */
|
||||
/* Invalid PDU received so terminate connection */
|
||||
conn->llcp_terminate.reason_final = BT_HCI_ERR_LMP_PDU_NOT_ALLOWED;
|
||||
llcp_lr_complete(conn);
|
||||
ctx->state = LP_CU_STATE_IDLE;
|
||||
lp_cu_complete(conn, ctx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -648,7 +663,7 @@ static void rp_cu_tx(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t opcode)
|
|||
break;
|
||||
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
|
||||
case PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND:
|
||||
llcp_pdu_encode_reject_ext_ind(pdu, PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ,
|
||||
llcp_pdu_encode_reject_ext_ind(pdu, ctx->data.cu.rejected_opcode,
|
||||
ctx->data.cu.error);
|
||||
break;
|
||||
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
|
||||
|
@ -719,14 +734,25 @@ static void rp_cu_conn_param_req_ntf(struct ll_conn *conn, struct proc_ctx *ctx)
|
|||
}
|
||||
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
|
||||
|
||||
static void rp_cu_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt, void *param)
|
||||
static void rp_cu_complete(struct ll_conn *conn, struct proc_ctx *ctx)
|
||||
{
|
||||
llcp_rr_complete(conn);
|
||||
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
|
||||
if (ctx->proc == PROC_CONN_PARAM_REQ) {
|
||||
cpr_active_check_and_reset(conn);
|
||||
}
|
||||
#endif /* defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) */
|
||||
ctx->state = RP_CU_STATE_IDLE;
|
||||
}
|
||||
|
||||
static void rp_cu_wait_complete(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
|
||||
void *param)
|
||||
{
|
||||
if (!llcp_ntf_alloc_is_available()) {
|
||||
ctx->state = RP_CU_STATE_WAIT_NTF;
|
||||
} else {
|
||||
rp_cu_ntf(conn, ctx);
|
||||
llcp_rr_complete(conn);
|
||||
ctx->state = RP_CU_STATE_IDLE;
|
||||
rp_cu_complete(conn, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -754,8 +780,7 @@ static void rp_cu_send_reject_ext_ind(struct ll_conn *conn, struct proc_ctx *ctx
|
|||
ctx->state = RP_CU_STATE_WAIT_TX_REJECT_EXT_IND;
|
||||
} else {
|
||||
rp_cu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_REJECT_EXT_IND);
|
||||
llcp_rr_complete(conn);
|
||||
ctx->state = RP_CU_STATE_IDLE;
|
||||
rp_cu_complete(conn, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -790,8 +815,7 @@ static void rp_cu_send_unknown_rsp(struct ll_conn *conn, struct proc_ctx *ctx, u
|
|||
ctx->state = RP_CU_STATE_WAIT_TX_UNKNOWN_RSP;
|
||||
} else {
|
||||
rp_cu_tx(conn, ctx, PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP);
|
||||
llcp_rr_complete(conn);
|
||||
ctx->state = RP_CU_STATE_IDLE;
|
||||
rp_cu_complete(conn, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -821,6 +845,44 @@ static void rp_cu_st_idle(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t ev
|
|||
}
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
|
||||
static void rp_cu_st_wait_conn_param_req_available(struct ll_conn *conn, struct proc_ctx *ctx,
|
||||
uint8_t evt, void *param)
|
||||
{
|
||||
/* Check if CPR is already active on other connection.
|
||||
* If so check if possible to send reject right away
|
||||
* otherwise stay in wait state in case CPR becomes
|
||||
* available before we can send send reject
|
||||
*/
|
||||
switch (evt) {
|
||||
case RP_CU_EVT_CONN_PARAM_REQ:
|
||||
case RP_CU_EVT_RUN:
|
||||
if (cpr_active_is_set(conn)) {
|
||||
ctx->state = RP_CU_STATE_WAIT_CONN_PARAM_REQ_AVAILABLE;
|
||||
if (!llcp_rr_ispaused(conn) && llcp_tx_alloc_peek(conn, ctx)) {
|
||||
/* We're good to reject immediately */
|
||||
ctx->data.cu.rejected_opcode = PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ;
|
||||
ctx->data.cu.error = BT_HCI_ERR_UNSUPP_LL_PARAM_VAL;
|
||||
rp_cu_send_reject_ext_ind(conn, ctx, evt, param);
|
||||
}
|
||||
} else {
|
||||
cpr_active_set(conn);
|
||||
const bool params_changed =
|
||||
cu_have_params_changed(conn, ctx->data.cu.interval_max,
|
||||
ctx->data.cu.latency, ctx->data.cu.timeout);
|
||||
|
||||
/* notify Host if conn parameters changed, else respond */
|
||||
if (params_changed) {
|
||||
rp_cu_send_conn_param_req_ntf(conn, ctx, evt, param);
|
||||
} else {
|
||||
ctx->state = RP_CU_STATE_WAIT_CONN_PARAM_REQ_REPLY;
|
||||
}
|
||||
}
|
||||
default:
|
||||
/* Ignore other evts */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void rp_cu_st_wait_rx_conn_param_req(struct ll_conn *conn, struct proc_ctx *ctx, uint8_t evt,
|
||||
void *param)
|
||||
{
|
||||
|
@ -830,21 +892,13 @@ static void rp_cu_st_wait_rx_conn_param_req(struct ll_conn *conn, struct proc_ct
|
|||
|
||||
/* Perform Param check and reject if invalid (LL_REJECT_EXT_IND) */
|
||||
if (!cu_check_conn_parameters(conn, ctx)) {
|
||||
ctx->data.cu.rejected_opcode = PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ;
|
||||
ctx->data.cu.error = BT_HCI_ERR_INVALID_LL_PARAM;
|
||||
rp_cu_send_reject_ext_ind(conn, ctx, evt, param);
|
||||
break;
|
||||
}
|
||||
|
||||
const bool params_changed =
|
||||
cu_have_params_changed(conn, ctx->data.cu.interval_max,
|
||||
ctx->data.cu.latency, ctx->data.cu.timeout);
|
||||
|
||||
/* notify Host if conn parameters changed, else respond */
|
||||
if (params_changed) {
|
||||
rp_cu_send_conn_param_req_ntf(conn, ctx, evt, param);
|
||||
} else {
|
||||
ctx->state = RP_CU_STATE_WAIT_CONN_PARAM_REQ_REPLY;
|
||||
}
|
||||
rp_cu_st_wait_conn_param_req_available(conn, ctx, evt, param);
|
||||
break;
|
||||
default:
|
||||
/* Ignore other evts */
|
||||
|
@ -875,6 +929,7 @@ static void rp_cu_state_wait_conn_param_req_reply(struct ll_conn *conn, struct p
|
|||
break;
|
||||
case RP_CU_EVT_CONN_PARAM_REQ_NEG_REPLY:
|
||||
/* Send reject in next prepare run */
|
||||
ctx->data.cu.rejected_opcode = PDU_DATA_LLCTRL_TYPE_CONN_PARAM_REQ;
|
||||
ctx->state = RP_CU_STATE_WAIT_TX_REJECT_EXT_IND;
|
||||
break;
|
||||
default:
|
||||
|
@ -967,10 +1022,9 @@ static void rp_cu_check_instant(struct ll_conn *conn, struct proc_ctx *ctx, uint
|
|||
notify = cu_should_notify_host(ctx);
|
||||
if (notify) {
|
||||
ctx->data.cu.error = BT_HCI_ERR_SUCCESS;
|
||||
rp_cu_complete(conn, ctx, evt, param);
|
||||
rp_cu_wait_complete(conn, ctx, evt, param);
|
||||
} else {
|
||||
llcp_rr_complete(conn);
|
||||
ctx->state = RP_CU_STATE_IDLE;
|
||||
rp_cu_complete(conn, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1018,7 +1072,7 @@ static void rp_cu_st_wait_ntf(struct ll_conn *conn, struct proc_ctx *ctx, uint8_
|
|||
{
|
||||
switch (evt) {
|
||||
case RP_CU_EVT_RUN:
|
||||
rp_cu_complete(conn, ctx, evt, param);
|
||||
rp_cu_wait_complete(conn, ctx, evt, param);
|
||||
break;
|
||||
default:
|
||||
/* Ignore other evts */
|
||||
|
@ -1036,6 +1090,9 @@ static void rp_cu_execute_fsm(struct ll_conn *conn, struct proc_ctx *ctx, uint8_
|
|||
case RP_CU_STATE_WAIT_RX_CONN_PARAM_REQ:
|
||||
rp_cu_st_wait_rx_conn_param_req(conn, ctx, evt, param);
|
||||
break;
|
||||
case RP_CU_STATE_WAIT_CONN_PARAM_REQ_AVAILABLE:
|
||||
rp_cu_st_wait_conn_param_req_available(conn, ctx, evt, param);
|
||||
break;
|
||||
case RP_CU_STATE_WAIT_NTF_CONN_PARAM_REQ:
|
||||
rp_cu_state_wait_ntf_conn_param_req(conn, ctx, evt, param);
|
||||
break;
|
||||
|
@ -1088,8 +1145,7 @@ void llcp_rp_cu_rx(struct ll_conn *conn, struct proc_ctx *ctx, struct node_rx_pd
|
|||
/* Invalid behaviour */
|
||||
/* Invalid PDU received so terminate connection */
|
||||
conn->llcp_terminate.reason_final = BT_HCI_ERR_LMP_PDU_NOT_ALLOWED;
|
||||
llcp_rr_complete(conn);
|
||||
ctx->state = RP_CU_STATE_IDLE;
|
||||
rp_cu_complete(conn, ctx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -196,6 +196,7 @@ struct proc_ctx {
|
|||
/* Connection Update & Connection Parameter Request */
|
||||
struct {
|
||||
uint8_t error;
|
||||
uint8_t rejected_opcode;
|
||||
uint8_t params_changed;
|
||||
uint16_t instant;
|
||||
uint8_t win_size;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -31,6 +31,8 @@
|
|||
#include "lll/lll_df_types.h"
|
||||
#include "lll_conn.h"
|
||||
|
||||
#include "ull_conn_internal.h"
|
||||
|
||||
#define EVENT_DONE_MAX 3
|
||||
/* Backing storage for elements in mfifo_done */
|
||||
static struct {
|
||||
|
@ -292,6 +294,11 @@ static inline int init_reset(void)
|
|||
mem_link_rx.quota_pdu = RX_CNT;
|
||||
rx_alloc(UINT8_MAX);
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
|
||||
/* Reset CPR mutex */
|
||||
cpr_active_reset();
|
||||
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue