Skip to content
Permalink
Browse files

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>
  • Loading branch information...
cvinayak authored and carlescufi committed Jun 28, 2019
1 parent 70a8987 commit fa4b4932b92609fb408cce19ca178b24c31d9b1e
Showing with 98 additions and 17 deletions.
  1. +93 −17 subsys/bluetooth/controller/ll_sw/ctrl.c
  2. +5 −0 subsys/bluetooth/controller/ll_sw/ctrl_internal.h
@@ -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);
@@ -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;

0 comments on commit fa4b493

Please sign in to comment.
You can’t perform that action at this time.