Bluetooth: Mesh: transport: update delayable work

Switch to the new API. Adds early exits for the ack and retransmit
timers, and replaces a remaining_time() + submit() call with schedule().

Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
Signed-off-by: Trond Einar Snekvik <Trond.Einar.Snekvik@nordicsemi.no>
This commit is contained in:
Peter Bigot 2021-03-29 09:03:02 -05:00 committed by Johan Hedberg
parent 1577fec851
commit 4e6cb116f8

View File

@ -115,7 +115,7 @@ static struct seg_tx {
friend_cred:1; /* Using Friend credentials */
const struct bt_mesh_send_cb *cb;
void *cb_data;
struct k_delayed_work retransmit; /* Retransmit timer */
struct k_work_delayable retransmit; /* Retransmit timer */
} seg_tx[CONFIG_BT_MESH_TX_SEG_MSG_COUNT];
static struct seg_rx {
@ -133,7 +133,7 @@ static struct seg_rx {
uint8_t ttl;
uint32_t block;
uint32_t last;
struct k_delayed_work ack;
struct k_work_delayable ack;
} seg_rx[CONFIG_BT_MESH_RX_SEG_MSG_COUNT];
K_MEM_SLAB_DEFINE(segs, BT_MESH_APP_SEG_SDU_MAX, CONFIG_BT_MESH_SEG_BUFS, 4);
@ -247,7 +247,7 @@ static void seg_tx_unblock_check(struct seg_tx *tx)
BT_DBG("Unblocked 0x%04x",
(uint16_t)(blocked->seq_auth & TRANS_SEQ_ZERO_MASK));
blocked->blocked = false;
k_delayed_work_submit(&blocked->retransmit, K_NO_WAIT);
k_work_reschedule(&blocked->retransmit, K_NO_WAIT);
}
}
@ -255,7 +255,8 @@ static void seg_tx_reset(struct seg_tx *tx)
{
int i;
k_delayed_work_cancel(&tx->retransmit);
/* If this call fails, the handler will exit early, as nack_count is 0. */
(void)k_work_cancel_delayable(&tx->retransmit);
tx->cb = NULL;
tx->cb_data = NULL;
@ -315,9 +316,9 @@ static void schedule_retransmit(struct seg_tx *tx)
* called this from inside bt_mesh_net_send), we should continue the
* retransmit immediately, as we just freed up a tx buffer.
*/
k_delayed_work_submit(&tx->retransmit,
tx->seg_o ? K_NO_WAIT :
K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx)));
k_work_reschedule(&tx->retransmit,
tx->seg_o ? K_NO_WAIT :
K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx)));
}
static void seg_send_start(uint16_t duration, int err, void *user_data)
@ -440,8 +441,8 @@ static void seg_tx_send_unacked(struct seg_tx *tx)
end:
if (!tx->seg_pending) {
k_delayed_work_submit(&tx->retransmit,
K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx)));
k_work_reschedule(&tx->retransmit,
K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx)));
}
tx->sending = 0U;
@ -859,8 +860,6 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr,
return -EINVAL;
}
k_delayed_work_cancel(&tx->retransmit);
while ((bit = find_lsb_set(ack))) {
if (tx->seg[bit - 1]) {
BT_DBG("seg %u/%u acked", bit - 1, tx->seg_n);
@ -871,7 +870,11 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr,
}
if (tx->nack_count) {
seg_tx_send_unacked(tx);
/* According to the Bluetooth Mesh Profile specification,
* section 3.5.3.3, we should reset the retransmit timer and
* retransmit immediately when receiving a valid ack message:
*/
k_work_reschedule(&tx->retransmit, K_NO_WAIT);
} else {
BT_DBG("SDU TX complete");
seg_tx_complete(tx, 0);
@ -1090,7 +1093,10 @@ static void seg_rx_reset(struct seg_rx *rx, bool full_reset)
BT_DBG("rx %p", rx);
k_delayed_work_cancel(&rx->ack);
/* If this fails, the handler will exit early on the next execution, as
* it checks rx->in_use.
*/
(void)k_work_cancel_delayable(&rx->ack);
if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && rx->obo &&
rx->block != BLOCK_COMPLETE(rx->seg_n)) {
@ -1127,6 +1133,16 @@ static void seg_ack(struct k_work *work)
struct seg_rx *rx = CONTAINER_OF(work, struct seg_rx, ack);
int32_t timeout;
if (!rx->in_use || rx->block == BLOCK_COMPLETE(rx->seg_n)) {
/* Cancellation of this timer may have failed. If it fails as
* part of seg_reset, in_use will be false.
* If it fails as part of the processing of a fully received
* SDU, the ack is already being sent from the receive handler,
* and the timer based ack sending can be ignored.
*/
return;
}
BT_DBG("rx %p", rx);
if (k_uptime_get_32() - rx->last > (60 * MSEC_PER_SEC)) {
@ -1144,7 +1160,7 @@ static void seg_ack(struct k_work *work)
rx->block, rx->obo);
timeout = ack_timeout(rx);
k_delayed_work_submit(&rx->ack, K_MSEC(timeout));
k_work_schedule(&rx->ack, K_MSEC(timeout));
}
static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n)
@ -1447,11 +1463,10 @@ found_rx:
/* Reset the Incomplete Timer */
rx->last = k_uptime_get_32();
if (!k_delayed_work_remaining_get(&rx->ack) &&
!bt_mesh_lpn_established()) {
if (!bt_mesh_lpn_established()) {
int32_t timeout = ack_timeout(rx);
k_delayed_work_submit(&rx->ack, K_MSEC(timeout));
/* Should only start ack timer if it isn't running already: */
k_work_schedule(&rx->ack, K_MSEC(timeout));
}
/* Allocated segment here */
@ -1487,7 +1502,10 @@ found_rx:
*pdu_type = BT_MESH_FRIEND_PDU_COMPLETE;
k_delayed_work_cancel(&rx->ack);
/* If this fails, the work handler will either exit early because the
* block is fully received, or rx->in_use is false.
*/
(void)k_work_cancel_delayable(&rx->ack);
send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr,
net_rx->ctx.send_ttl, seq_auth, rx->block, rx->obo);
@ -1643,11 +1661,11 @@ void bt_mesh_trans_init(void)
int i;
for (i = 0; i < ARRAY_SIZE(seg_tx); i++) {
k_delayed_work_init(&seg_tx[i].retransmit, seg_retransmit);
k_work_init_delayable(&seg_tx[i].retransmit, seg_retransmit);
}
for (i = 0; i < ARRAY_SIZE(seg_rx); i++) {
k_delayed_work_init(&seg_rx[i].ack, seg_ack);
k_work_init_delayable(&seg_rx[i].ack, seg_ack);
}
}