From 9c14567ce2d75cf2095277cc7ae2ee144d612282 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Wed, 18 Sep 2019 23:17:39 +0530 Subject: [PATCH] Bluetooth: controller: Fix conn update to be cacheable Fix connection update procedure to be cacheable if any other local or remote control procedure is in progress. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ctrl.c | 227 ++++++++---------- .../controller/ll_sw/ctrl_internal.h | 31 ++- 2 files changed, 122 insertions(+), 136 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ctrl.c b/subsys/bluetooth/controller/ll_sw/ctrl.c index d32eca3c754..330868bb54d 100644 --- a/subsys/bluetooth/controller/ll_sw/ctrl.c +++ b/subsys/bluetooth/controller/ll_sw/ctrl.c @@ -2123,21 +2123,18 @@ isr_rx_conn_pkt_ctrl_rej_conn_upd(struct radio_pdu_node_rx *node_rx, /* Unsupported remote feature */ if (!conn->role && (rej_ext_ind->error_code == BT_HCI_ERR_UNSUPP_REMOTE_FEATURE)) { - LL_ASSERT(conn->llcp_req == conn->llcp_ack); + LL_ASSERT(conn->llcp_cu.req == conn->llcp_cu.ack); conn->llcp_conn_param.state = LLCP_CPR_STATE_UPD; - conn->llcp.conn_upd.win_size = 1U; - conn->llcp.conn_upd.win_offset_us = 0U; - conn->llcp.conn_upd.interval = - conn->llcp_conn_param.interval_max; - conn->llcp.conn_upd.latency = conn->llcp_conn_param.latency; - conn->llcp.conn_upd.timeout = conn->llcp_conn_param.timeout; - /* conn->llcp.conn_upd.instant = 0; */ - conn->llcp.conn_upd.state = LLCP_CUI_STATE_USE; - conn->llcp.conn_upd.is_internal = !conn->llcp_conn_param.cmd; - conn->llcp_type = LLCP_CONN_UPD; - conn->llcp_ack--; + conn->llcp_cu.win_size = 1U; + conn->llcp_cu.win_offset_us = 0U; + conn->llcp_cu.interval = conn->llcp_conn_param.interval_max; + conn->llcp_cu.latency = conn->llcp_conn_param.latency; + conn->llcp_cu.timeout = conn->llcp_conn_param.timeout; + conn->llcp_cu.state = LLCP_CUI_STATE_USE; + conn->llcp_cu.cmd = conn->llcp_conn_param.cmd; + conn->llcp_cu.ack--; return; } @@ -3267,25 +3264,23 @@ isr_rx_conn_pkt_ctrl(struct radio_pdu_node_rx *node_rx, /* TODO: check for unsupported remote feature reason */ if (!conn->role) { - LL_ASSERT(conn->llcp_req == conn->llcp_ack); + LL_ASSERT(conn->llcp_cu.req == + conn->llcp_cu.ack); conn->llcp_conn_param.state = LLCP_CPR_STATE_UPD; - conn->llcp.conn_upd.win_size = 1U; - conn->llcp.conn_upd.win_offset_us = 0U; - conn->llcp.conn_upd.interval = + conn->llcp_cu.win_size = 1U; + conn->llcp_cu.win_offset_us = 0U; + conn->llcp_cu.interval = conn->llcp_conn_param.interval_max; - conn->llcp.conn_upd.latency = + conn->llcp_cu.latency = conn->llcp_conn_param.latency; - conn->llcp.conn_upd.timeout = + conn->llcp_cu.timeout = conn->llcp_conn_param.timeout; - /* conn->llcp.conn_upd.instant = 0; */ - conn->llcp.conn_upd.state = LLCP_CUI_STATE_USE; - conn->llcp.conn_upd.is_internal = - !conn->llcp_conn_param.cmd; - conn->llcp_type = LLCP_CONN_UPD; - conn->llcp_ack--; + conn->llcp_cu.state = LLCP_CUI_STATE_USE; + conn->llcp_cu.cmd = conn->llcp_conn_param.cmd; + conn->llcp_cu.ack--; break; } @@ -5708,9 +5703,9 @@ static void mayfly_sched_win_offset_use(void *params) sched_after_mstr_free_offset_get(conn->conn_interval, conn->hdr.ticks_slot, conn->llcp.conn_upd.ticks_anchor, - &conn->llcp.conn_upd.win_offset_us); + &conn->llcp_cu.win_offset_us); - win_offset = conn->llcp.conn_upd.win_offset_us / 1250; + win_offset = conn->llcp_cu.win_offset_us / 1250; memcpy(conn->llcp.conn_upd.pdu_win_offset, &win_offset, sizeof(u16_t)); } @@ -5993,15 +5988,13 @@ static void mayfly_sched_win_offset_select(void *params) } if (offset_index_s < OFFSET_S_MAX) { - conn->llcp.conn_upd.win_offset_us = - win_offset_s * 1250; - memcpy(conn->llcp.conn_upd.pdu_win_offset, - &win_offset_s, sizeof(u16_t)); + conn->llcp_cu.win_offset_us = win_offset_s * 1250; + memcpy(conn->llcp.conn_upd.pdu_win_offset, &win_offset_s, + sizeof(u16_t)); } else if (!has_offset_s) { - conn->llcp.conn_upd.win_offset_us = - win_offset_m[0] * 1250; - memcpy(conn->llcp.conn_upd.pdu_win_offset, - &win_offset_m[0], sizeof(u16_t)); + conn->llcp_cu.win_offset_us = win_offset_m[0] * 1250; + memcpy(conn->llcp.conn_upd.pdu_win_offset, &win_offset_m[0], + sizeof(u16_t)); } else { struct pdu_data *pdu_ctrl_tx; @@ -7240,7 +7233,7 @@ static inline void event_conn_upd_init(struct connection *conn, void (*fp_mayfly_select_or_use)(void *)) { /* move to in progress */ - conn->llcp.conn_upd.state = LLCP_CUI_STATE_INPROG; + conn->llcp_cu.state = LLCP_CUI_STATE_INPROG; /* set instant */ conn->llcp.conn_upd.instant = @@ -7251,16 +7244,12 @@ static inline void event_conn_upd_init(struct connection *conn, pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, conn_update_ind) + sizeof(struct pdu_data_llctrl_conn_update_ind); pdu_ctrl_tx->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_CONN_UPDATE_IND; - pdu_ctrl_tx->llctrl.conn_update_ind.win_size = - conn->llcp.conn_upd.win_size; - pdu_ctrl_tx->llctrl.conn_update_ind. - win_offset = conn->llcp.conn_upd.win_offset_us / 1250; - pdu_ctrl_tx->llctrl.conn_update_ind.interval = - conn->llcp.conn_upd.interval; - pdu_ctrl_tx->llctrl.conn_update_ind.latency = - conn->llcp.conn_upd.latency; - pdu_ctrl_tx->llctrl.conn_update_ind.timeout = - conn->llcp.conn_upd.timeout; + pdu_ctrl_tx->llctrl.conn_update_ind.win_size = conn->llcp_cu.win_size; + pdu_ctrl_tx->llctrl.conn_update_ind.win_offset = + conn->llcp_cu.win_offset_us / 1250; + pdu_ctrl_tx->llctrl.conn_update_ind.interval = conn->llcp_cu.interval; + pdu_ctrl_tx->llctrl.conn_update_ind.latency = conn->llcp_cu.latency; + pdu_ctrl_tx->llctrl.conn_update_ind.timeout = conn->llcp_cu.timeout; pdu_ctrl_tx->llctrl.conn_update_ind.instant = conn->llcp.conn_upd.instant; @@ -7319,7 +7308,7 @@ static inline u32_t event_conn_upd_prep(struct connection *conn, instant_latency = (event_counter - conn->llcp.conn_upd.instant) & 0xffff; - if (conn->llcp.conn_upd.state != LLCP_CUI_STATE_INPROG) { + if (conn->llcp_cu.state != LLCP_CUI_STATE_INPROG) { #if defined(CONFIG_BT_CTLR_SCHED_ADVANCED) static memq_link_t s_link; static struct mayfly s_mfy_sched_offset = {0, 0, @@ -7337,7 +7326,7 @@ static inline u32_t event_conn_upd_prep(struct connection *conn, pdu_ctrl_tx = (void *)node_tx->pdu_data; #if defined(CONFIG_BT_CTLR_SCHED_ADVANCED) - switch (conn->llcp.conn_upd.state) { + switch (conn->llcp_cu.state) { case LLCP_CUI_STATE_USE: fp_mayfly_select_or_use = mayfly_sched_win_offset_use; break; @@ -7378,6 +7367,7 @@ static inline u32_t event_conn_upd_prep(struct connection *conn, u16_t latency; /* procedure request acked */ + conn->llcp_cu.ack = conn->llcp_cu.req; conn->llcp_ack = conn->llcp_req; #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) @@ -7396,13 +7386,10 @@ static inline u32_t event_conn_upd_prep(struct connection *conn, } /* Prepare the rx packet structure */ - if ((conn->llcp.conn_upd.interval != - conn->conn_interval) || - (conn->llcp.conn_upd.latency != conn->latency) || - (RADIO_CONN_EVENTS(conn->llcp.conn_upd.timeout * - 10000, - conn->conn_interval * - 1250) != + if ((conn->llcp_cu.interval != conn->conn_interval) || + (conn->llcp_cu.latency != conn->latency) || + (RADIO_CONN_EVENTS(conn->llcp_cu.timeout * 10000, + conn->conn_interval * 1250) != conn->supervision_reload)) { node_rx = packet_rx_reserve_get(2); LL_ASSERT(node_rx); @@ -7414,11 +7401,11 @@ static inline u32_t event_conn_upd_prep(struct connection *conn, radio_le_conn_update_cmplt = (void *) node_rx->pdu_data; radio_le_conn_update_cmplt->status = 0x00; radio_le_conn_update_cmplt->interval = - conn->llcp.conn_upd.interval; + conn->llcp_cu.interval; radio_le_conn_update_cmplt->latency = - conn->llcp.conn_upd.latency; + conn->llcp_cu.latency; radio_le_conn_update_cmplt->timeout = - conn->llcp.conn_upd.timeout; + conn->llcp_cu.timeout; /* enqueue connection update complete structure * into queue. @@ -7448,10 +7435,8 @@ static inline u32_t event_conn_upd_prep(struct connection *conn, /* compensate for instant_latency due to laziness */ conn_interval_old = instant_latency * conn->conn_interval; - latency = conn_interval_old / - conn->llcp.conn_upd.interval; - conn_interval_new = latency * - conn->llcp.conn_upd.interval; + latency = conn_interval_old / conn->llcp_cu.interval; + conn_interval_new = latency * conn->llcp_cu.interval; if (conn_interval_new > conn_interval_old) { ticks_at_expire += HAL_TICKER_US_TO_TICKS( (conn_interval_new - conn_interval_old) * 1250); @@ -7464,7 +7449,7 @@ static inline u32_t event_conn_upd_prep(struct connection *conn, /* calculate the offset, window widening and interval */ ticks_slot_offset = MAX(conn->hdr.ticks_active_to_start, conn->hdr.ticks_xtal_to_start); - conn_interval_us = conn->llcp.conn_upd.interval * 1250; + conn_interval_us = conn->llcp_cu.interval * 1250; periodic_us = conn_interval_us; if (conn->role) { conn->slave.window_widening_prepare_us -= @@ -7478,7 +7463,7 @@ static inline u32_t event_conn_upd_prep(struct connection *conn, conn->slave.window_widening_max_us = (conn_interval_us >> 1) - RADIO_TIFS; conn->slave.window_size_prepare_us = - conn->llcp.conn_upd.win_size * 1250; + conn->llcp_cu.win_size * 1250; conn->slave.ticks_to_offset = 0U; conn->slave.window_widening_prepare_us += @@ -7494,12 +7479,11 @@ static inline u32_t event_conn_upd_prep(struct connection *conn, conn->slave.window_widening_periodic_us * latency); ticks_win_offset = HAL_TICKER_US_TO_TICKS( - (conn->llcp.conn_upd.win_offset_us / 1250) * - 1250); + (conn->llcp_cu.win_offset_us / 1250) * 1250); periodic_us -= conn->slave.window_widening_periodic_us; } else { ticks_win_offset = HAL_TICKER_US_TO_TICKS( - conn->llcp.conn_upd.win_offset_us); + conn->llcp_cu.win_offset_us); /* Workaround: Due to the missing remainder param in * ticker_start function for first interval; add a @@ -7507,11 +7491,11 @@ static inline u32_t event_conn_upd_prep(struct connection *conn, */ ticks_win_offset += 1; } - conn->conn_interval = conn->llcp.conn_upd.interval; - conn->latency = conn->llcp.conn_upd.latency; + conn->conn_interval = conn->llcp_cu.interval; + conn->latency = conn->llcp_cu.latency; conn->supervision_reload = - RADIO_CONN_EVENTS((conn->llcp.conn_upd.timeout - * 10 * 1000), conn_interval_us); + RADIO_CONN_EVENTS((conn->llcp_cu.timeout * 10 * 1000), + conn_interval_us); conn->procedure_reload = RADIO_CONN_EVENTS((40 * 1000 * 1000), conn_interval_us); @@ -7528,7 +7512,7 @@ static inline u32_t event_conn_upd_prep(struct connection *conn, conn->apto_reload; #endif /* CONFIG_BT_CTLR_LE_PING */ - if (!conn->llcp.conn_upd.is_internal) { + if (conn->llcp_cu.cmd) { conn->supervision_expire = 0U; } @@ -8092,7 +8076,7 @@ static inline void event_conn_param_rsp(struct connection *conn) /* master respond with connection update */ if (!conn->role) { - if (conn->llcp_req != conn->llcp_ack) { + if (conn->llcp_cu.req != conn->llcp_cu.ack) { return; } @@ -8100,25 +8084,23 @@ static inline void event_conn_param_rsp(struct connection *conn) conn->llcp_conn_param.state = LLCP_CPR_STATE_UPD; /* Initiate connection update procedure */ - conn->llcp.conn_upd.win_size = 1U; - conn->llcp.conn_upd.win_offset_us = 0U; + conn->llcp_cu.win_size = 1U; + conn->llcp_cu.win_offset_us = 0U; if (conn->llcp_conn_param.preferred_periodicity) { - conn->llcp.conn_upd.interval = + conn->llcp_cu.interval = ((conn->llcp_conn_param.interval_min / conn->llcp_conn_param.preferred_periodicity) + 1) * conn->llcp_conn_param.preferred_periodicity; } else { - conn->llcp.conn_upd.interval = + conn->llcp_cu.interval = conn->llcp_conn_param.interval_max; } - conn->llcp.conn_upd.latency = conn->llcp_conn_param.latency; - conn->llcp.conn_upd.timeout = conn->llcp_conn_param.timeout; - /* conn->llcp.conn_upd.instant = 0; */ - conn->llcp.conn_upd.state = LLCP_CUI_STATE_SELECT; - conn->llcp.conn_upd.is_internal = !conn->llcp_conn_param.cmd; - conn->llcp_type = LLCP_CONN_UPD; - conn->llcp_ack--; + conn->llcp_cu.latency = conn->llcp_conn_param.latency; + conn->llcp_cu.timeout = conn->llcp_conn_param.timeout; + conn->llcp_cu.state = LLCP_CUI_STATE_SELECT; + conn->llcp_cu.cmd = conn->llcp_conn_param.cmd; + conn->llcp_cu.ack--; return; } @@ -8910,7 +8892,14 @@ static void event_connection_prepare(u32_t ticks_at_expire, * Encryption setup. */ if ((conn->llcp_ack == conn->llcp_req) && !conn->pause_rx) { - if (conn->llcp_feature.ack != conn->llcp_feature.req) { + if (conn->llcp_cu.ack != conn->llcp_cu.req) { + /* Previous event will be stop in the switch clause + * below. + */ + conn->llcp_type = LLCP_CONN_UPD; + conn->llcp_ack--; + + } else if (conn->llcp_feature.ack != conn->llcp_feature.req) { /* Stop previous event, to avoid Radio DMA corrupting * the rx queue. */ @@ -10358,23 +10347,17 @@ static u8_t conn_update(struct connection *conn, struct pdu_data *pdu_data_rx) _radio.conn_upd = conn; } - conn->llcp.conn_upd.win_size = - pdu_data_rx->llctrl.conn_update_ind.win_size; - conn->llcp.conn_upd.win_offset_us = + conn->llcp_cu.win_size = pdu_data_rx->llctrl.conn_update_ind.win_size; + conn->llcp_cu.win_offset_us = pdu_data_rx->llctrl.conn_update_ind.win_offset * 1250; - conn->llcp.conn_upd.interval = - pdu_data_rx->llctrl.conn_update_ind.interval; - conn->llcp.conn_upd.latency = - pdu_data_rx->llctrl.conn_update_ind.latency; - conn->llcp.conn_upd.timeout = - pdu_data_rx->llctrl.conn_update_ind.timeout; + conn->llcp_cu.interval = pdu_data_rx->llctrl.conn_update_ind.interval; + conn->llcp_cu.latency = pdu_data_rx->llctrl.conn_update_ind.latency; + conn->llcp_cu.timeout = pdu_data_rx->llctrl.conn_update_ind.timeout; conn->llcp.conn_upd.instant = pdu_data_rx->llctrl.conn_update_ind.instant; - conn->llcp.conn_upd.state = LLCP_CUI_STATE_INPROG; - conn->llcp.conn_upd.is_internal = 0U; - - conn->llcp_type = LLCP_CONN_UPD; - conn->llcp_ack--; + conn->llcp_cu.state = LLCP_CUI_STATE_INPROG; + conn->llcp_cu.cmd = 1U; + conn->llcp_cu.ack--; #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) if ((conn->llcp_conn_param.req != conn->llcp_conn_param.ack) && @@ -10390,7 +10373,7 @@ static u8_t conn_update(struct connection *conn, struct pdu_data *pdu_data_rx) defined(CONFIG_BT_CTLR_SCHED_ADVANCED) static u32_t conn_update_req(struct connection *conn) { - if (conn->llcp_req != conn->llcp_ack) { + if (conn->llcp_cu.req != conn->llcp_cu.ack) { return 1; } @@ -10401,19 +10384,15 @@ static u32_t conn_update_req(struct connection *conn) #endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */ if (!conn->role) { - conn->llcp.conn_upd.win_size = 1U; - conn->llcp.conn_upd.win_offset_us = 0U; - conn->llcp.conn_upd.interval = conn->conn_interval; - conn->llcp.conn_upd.latency = conn->latency; - conn->llcp.conn_upd.timeout = conn->conn_interval * - conn->supervision_reload * - 125 / 1000; - /* conn->llcp.conn_upd.instant = 0; */ - conn->llcp.conn_upd.state = LLCP_CUI_STATE_USE; - conn->llcp.conn_upd.is_internal = 1U; - - conn->llcp_type = LLCP_CONN_UPD; - conn->llcp_ack--; + conn->llcp_cu.win_size = 1U; + conn->llcp_cu.win_offset_us = 0U; + conn->llcp_cu.interval = conn->conn_interval; + conn->llcp_cu.latency = conn->latency; + conn->llcp_cu.timeout = conn->conn_interval * + conn->supervision_reload * 125 / 1000; + conn->llcp_cu.state = LLCP_CUI_STATE_USE; + conn->llcp_cu.cmd = 0U; + conn->llcp_cu.ack--; return 0; @@ -11426,6 +11405,8 @@ u32_t radio_adv_enable(u16_t interval, u8_t chan_map, u8_t filter_policy, conn->llcp_req = 0U; conn->llcp_ack = 0U; + conn->llcp_cu.req = 0U; + conn->llcp_cu.ack = 0U; conn->llcp_feature.req = 0U; conn->llcp_feature.ack = 0U; conn->llcp_version.req = 0U; @@ -11971,6 +11952,8 @@ u32_t radio_connect_enable(u8_t adv_addr_type, u8_t *adv_addr, u16_t interval, conn->llcp_req = 0U; conn->llcp_ack = 0U; + conn->llcp_cu.req = 0U; + conn->llcp_cu.ack = 0U; conn->llcp_feature.req = 0U; conn->llcp_feature.ack = 0U; conn->llcp_version.req = 0U; @@ -12093,21 +12076,19 @@ u8_t ll_conn_update(u16_t handle, u8_t cmd, u8_t status, u16_t interval_min, } if (!cmd) { - if (conn->llcp_req != conn->llcp_ack) { + if (conn->llcp_cu.req != conn->llcp_cu.ack) { return BT_HCI_ERR_CMD_DISALLOWED; } - conn->llcp.conn_upd.win_size = 1U; - conn->llcp.conn_upd.win_offset_us = 0U; - conn->llcp.conn_upd.interval = interval_max; - conn->llcp.conn_upd.latency = latency; - conn->llcp.conn_upd.timeout = timeout; - /* conn->llcp.conn_upd.instant = 0; */ - conn->llcp.conn_upd.state = LLCP_CUI_STATE_USE; - conn->llcp.conn_upd.is_internal = 0U; + conn->llcp_cu.win_size = 1U; + conn->llcp_cu.win_offset_us = 0U; + conn->llcp_cu.interval = interval_max; + conn->llcp_cu.latency = latency; + conn->llcp_cu.timeout = timeout; + conn->llcp_cu.state = LLCP_CUI_STATE_USE; + conn->llcp_cu.cmd = 1U; - conn->llcp_type = LLCP_CONN_UPD; - conn->llcp_req++; + conn->llcp_cu.req++; } else { #if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ) cmd--; diff --git a/subsys/bluetooth/controller/ll_sw/ctrl_internal.h b/subsys/bluetooth/controller/ll_sw/ctrl_internal.h index 2b11d791ba6..b24f4c0b0a1 100644 --- a/subsys/bluetooth/controller/ll_sw/ctrl_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ctrl_internal.h @@ -136,24 +136,13 @@ struct connection { enum llcp llcp_type; union { struct { - enum { - LLCP_CUI_STATE_INPROG, - LLCP_CUI_STATE_USE, - LLCP_CUI_STATE_SELECT - } state:2 __packed; - u8_t is_internal:1; - u16_t interval; - u16_t latency; - u16_t timeout; u16_t instant; - u32_t win_offset_us; - u8_t win_size; u16_t *pdu_win_offset; u32_t ticks_anchor; } conn_upd; struct { - u8_t initiate; + u8_t initiate:1; u8_t chm[5]; u16_t instant; } chan_map; @@ -170,13 +159,29 @@ struct connection { #if defined(CONFIG_BT_CTLR_LE_ENC) struct { - u8_t initiate; + u8_t initiate:1; u8_t error_code; u8_t skd[16]; } encryption; #endif /* CONFIG_BT_CTLR_LE_ENC */ } llcp; + struct { + u8_t req; + u8_t ack; + enum { + LLCP_CUI_STATE_INPROG, + LLCP_CUI_STATE_USE, + LLCP_CUI_STATE_SELECT + } state:2 __packed; + u8_t cmd:1; + u16_t interval; + u16_t latency; + u16_t timeout; + u32_t win_offset_us; + u8_t win_size; + } llcp_cu; + struct { u8_t req; u8_t ack;