Bluetooth: controller: Fix post DLE/PHY update event length

Fix the controller implementation to perform connection
event length reservation based on the completed Data Length
Update and/or PHY Update Procedure.

This fix with avoid states/roles from stepping on each
others event length. Connection would have supervision timed
out or have stalled data transmissions due to insufficient
reserved air time.

Relates to #15171.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2019-06-28 10:21:31 +05:30 committed by Carles Cufí
commit fa4b4932b9
2 changed files with 98 additions and 17 deletions

View file

@ -276,11 +276,11 @@ static void ticker_update_adv_assert(u32_t status, void *params);
#if defined(CONFIG_BT_CONN)
#if defined(CONFIG_BT_PERIPHERAL)
static void ticker_stop_adv_assert(u32_t status, void *params);
static void ticker_update_slave_assert(u32_t status, void *params);
#endif /* CONFIG_BT_PERIPHERAL */
#if defined(CONFIG_BT_CENTRAL)
static void ticker_stop_scan_assert(u32_t status, void *params);
#endif /* CONFIG_BT_CENTRAL */
static void ticker_update_conn_assert(u32_t status, void *params);
static void ticker_stop_conn_assert(u32_t status, void *params);
static void ticker_start_conn_assert(u32_t status, void *params);
#endif /* CONFIG_BT_CONN */
@ -2380,6 +2380,11 @@ static inline u8_t isr_rx_conn_pkt_ctrl_dle(struct pdu_data *pdu_data_rx,
eff_tx_time;
#endif /* CONFIG_BT_CTLR_PHY */
/* flag an event length update*/
_radio.conn_curr->evt_len_upd = 1U;
_radio.conn_curr->evt_len_adv = 1U;
/* Request Rx buffer resize */
_radio.conn_curr->llcp_length.ack =
(_radio.conn_curr->llcp_length.req - 1);
_radio.conn_curr->llcp_length.state =
@ -2420,6 +2425,10 @@ static inline u8_t isr_rx_conn_pkt_ctrl_dle(struct pdu_data *pdu_data_rx,
_radio.conn_curr->max_tx_time = eff_tx_time;
#endif /* CONFIG_BT_CTLR_PHY */
/* flag an event length update*/
_radio.conn_curr->evt_len_upd = 1U;
_radio.conn_curr->evt_len_adv = 0U;
/* prepare event params */
lr->max_rx_octets = eff_rx_octets;
lr->max_tx_octets = eff_tx_octets;
@ -4318,8 +4327,10 @@ static inline u32_t isr_close_scan(void)
#if defined(CONFIG_BT_CONN)
static inline void isr_close_conn(void)
{
u32_t ticks_drift_plus;
u32_t ticks_drift_minus;
u32_t ticks_drift_plus;
u32_t ticks_slot_minus;
u32_t ticks_slot_plus;
u16_t latency_event;
u16_t elapsed_event;
u8_t reason_peer;
@ -4345,10 +4356,12 @@ static inline void isr_close_conn(void)
return;
}
ticks_drift_plus = 0U;
ticks_drift_minus = 0U;
latency_event = _radio.conn_curr->latency_event;
elapsed_event = latency_event + 1;
ticks_drift_minus = 0U;
ticks_drift_plus = 0U;
ticks_slot_minus = 0U;
ticks_slot_plus = 0U;
/* calculate drift if anchor point sync-ed */
if (_radio.packet_counter &&
@ -4579,8 +4592,65 @@ static inline void isr_close_conn(void)
lazy = _radio.conn_curr->latency_event + 1;
}
#if defined(CONFIG_BT_PERIPHERAL)
#if defined(CONFIG_BT_CTLR_DATA_LENGTH) || defined(CONFIG_BT_CTLR_PHY)
/* TODO: Design connection event length use. for only reserve for single
* trx.
*/
if (_radio.conn_curr->evt_len_upd) {
u32_t ready_delay, rx_time, tx_time, ticks_slot;
struct connection *conn = _radio.conn_curr;
/* Reset event length update flag */
conn->evt_len_upd = 0U;
#if defined(CONFIG_BT_CTLR_PHY)
ready_delay = (conn->role) ?
radio_rx_ready_delay_get(conn->phy_rx, 1) :
radio_tx_ready_delay_get(conn->phy_tx,
conn->phy_flags);
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
tx_time = conn->max_tx_time;
if (conn->evt_len_adv) {
rx_time = conn->llcp_length.rx_time;
} else {
rx_time = conn->max_rx_time;
}
#else /* !CONFIG_BT_CTLR_DATA_LENGTH */
tx_time = MAX(RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN, 0),
RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN,
conn->phy_tx));
rx_time = MAX(RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN, 0),
RADIO_PKT_TIME(PDU_DC_PAYLOAD_SIZE_MIN,
conn->phy_rx));
#endif /* !CONFIG_BT_CTLR_DATA_LENGTH */
#else /* !CONFIG_BT_CTLR_PHY */
ready_delay = (conn->role) ?
radio_rx_ready_delay_get(0, 0) :
radio_tx_ready_delay_get(0, 0);
tx_time = RADIO_PKT_TIME(conn->max_tx_octets, 0);
if (conn->evt_len_adv) {
rx_time = RADIO_PKT_TIME(conn->llcp_length.rx_octets,
0);
} else {
rx_time = RADIO_PKT_TIME(conn->max_rx_octets, 0);
}
#endif /* !CONFIG_BT_CTLR_PHY */
ticks_slot = HAL_TICKER_US_TO_TICKS(RADIO_TICKER_START_PART_US +
ready_delay + RADIO_TIFS +
rx_time + tx_time + 4);
if (ticks_slot > conn->hdr.ticks_slot) {
ticks_slot_plus = ticks_slot - conn->hdr.ticks_slot;
} else {
ticks_slot_minus = conn->hdr.ticks_slot - ticks_slot;
}
conn->hdr.ticks_slot = ticks_slot;
}
#endif
if ((ticks_drift_plus != 0) || (ticks_drift_minus != 0) ||
(ticks_slot_plus != 0) || (ticks_slot_minus != 0) ||
(lazy != 0) || (force != 0)) {
u32_t ticker_status;
u8_t ticker_id = RADIO_TICKER_ID_FIRST_CONNECTION +
@ -4596,14 +4666,14 @@ static inline void isr_close_conn(void)
ticker_update(RADIO_TICKER_INSTANCE_ID_RADIO,
RADIO_TICKER_USER_ID_WORKER,
ticker_id,
ticks_drift_plus, ticks_drift_minus, 0, 0,
lazy, force, ticker_update_slave_assert,
ticks_drift_plus, ticks_drift_minus,
ticks_slot_plus, ticks_slot_minus,
lazy, force, ticker_update_conn_assert,
(void *)(u32_t)ticker_id);
LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
(ticker_status == TICKER_STATUS_BUSY) ||
(_radio.ticker_id_stop == ticker_id));
}
#endif /* CONFIG_BT_PERIPHERAL */
}
#endif /* CONFIG_BT_CONN */
@ -4809,15 +4879,6 @@ static void ticker_stop_adv_assert(u32_t status, void *params)
LL_ASSERT(_radio.ticker_id_prepare != RADIO_TICKER_ID_ADV);
}
}
static void ticker_update_slave_assert(u32_t status, void *params)
{
u8_t ticker_id = (u32_t)params & 0xFF;
LL_ASSERT((status == TICKER_STATUS_SUCCESS) ||
(_radio.ticker_id_stop == ticker_id) ||
(_radio.ticker_id_upd == ticker_id));
}
#endif /* CONFIG_BT_PERIPHERAL */
#if defined(CONFIG_BT_CENTRAL)
@ -4847,6 +4908,15 @@ static void ticker_stop_scan_assert(u32_t status, void *params)
}
#endif /* CONFIG_BT_CENTRAL */
static void ticker_update_conn_assert(u32_t status, void *params)
{
u8_t ticker_id = (u32_t)params & 0xFF;
LL_ASSERT((status == TICKER_STATUS_SUCCESS) ||
(_radio.ticker_id_stop == ticker_id) ||
(_radio.ticker_id_upd == ticker_id));
}
static void ticker_stop_conn_assert(u32_t status, void *params)
{
LL_ASSERT(status == TICKER_STATUS_SUCCESS);
@ -8105,6 +8175,9 @@ static inline int event_len_prep(struct connection *conn)
conn->max_rx_time = conn->llcp_length.rx_time;
#endif /* CONFIG_BT_CTLR_PHY */
/* Reset event length update advanced flag */
conn->evt_len_adv = 0U;
/** TODO This design is exception as memory initialization
* and allocation is done in radio context here, breaking the
* rule that the rx buffers are allocated in application
@ -8492,6 +8565,9 @@ static inline void event_phy_upd_ind_prep(struct connection *conn,
conn->max_tx_time = eff_tx_time;
conn->max_rx_time = eff_rx_time;
/* flag an event length update*/
conn->evt_len_upd = 1U;
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
/* Prepare the rx packet structure */
node_rx = packet_rx_reserve_get(2);

View file

@ -295,6 +295,11 @@ struct connection {
/* Detect empty L2CAP start frame */
u8_t start_empty:1;
#if defined(CONFIG_BT_CTLR_DATA_LENGTH) || defined(CONFIG_BT_CTLR_PHY)
u8_t evt_len_upd:1;
u8_t evt_len_adv:1;
#endif
#if defined(CONFIG_BT_CTLR_CONN_RSSI)
u8_t rssi_latest;
u8_t rssi_reported;