diff --git a/components/bt/esp_ble_mesh/mesh_common/include/mesh_atomic.h b/components/bt/esp_ble_mesh/mesh_common/include/mesh_atomic.h index 6d62840e46e..aafe357f7fc 100644 --- a/components/bt/esp_ble_mesh/mesh_common/include/mesh_atomic.h +++ b/components/bt/esp_ble_mesh/mesh_common/include/mesh_atomic.h @@ -147,6 +147,33 @@ static inline bt_mesh_atomic_val_t bt_mesh_atomic_and(bt_mesh_atomic_t *target, extern bt_mesh_atomic_val_t bt_mesh_atomic_and(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t value); #endif +/** + * @brief Atomic CAS operation. + * + * This compares the contents of @a *target + * with the contents of @a excepted. If equal, + * the operation is a read-modify-write operation + * that writes @a new_val into @a *target and return true. + * If they are not equal, the operation is a read + * and return false. + * + * @param target Address of atomic variable. + * @param excepted Value of excepted. + * @param new_val Write if target value is equal to expected one. + * + * @return + * - true: Target value updated. + * - false: Target value not updated. + */ +#ifdef CONFIG_ATOMIC_OPERATIONS_BUILTIN +static inline bool bt_mesh_atomic_cas(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val) +{ + return __atomic_compare_exchange_n(target, &excepted, &new_val, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); +} +#else +extern bool bt_mesh_atomic_cas(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val); +#endif + /** * @cond INTERNAL_HIDDEN */ diff --git a/components/bt/esp_ble_mesh/mesh_common/mesh_atomic.c b/components/bt/esp_ble_mesh/mesh_common/mesh_atomic.c index 67562bcc93b..232ba3fa78b 100644 --- a/components/bt/esp_ble_mesh/mesh_common/mesh_atomic.c +++ b/components/bt/esp_ble_mesh/mesh_common/mesh_atomic.c @@ -13,7 +13,7 @@ /* * SPDX-FileCopyrightText: 2016 Intel Corporation * SPDX-FileCopyrightText: 2011-2014 Wind River Systems, Inc. - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -170,4 +170,18 @@ bt_mesh_atomic_val_t bt_mesh_atomic_inc(bt_mesh_atomic_t *target) return ret; } +bool bt_mesh_atomic_cas(bt_mesh_atomic_t *target, bt_mesh_atomic_val_t excepted, bt_mesh_atomic_val_t new_val) +{ + bt_mesh_atomic_lock(); + + if (*target == excepted) { + *target = new_val; + bt_mesh_atomic_unlock(); + return true; + } + + bt_mesh_atomic_unlock(); + return false; +} + #endif /* #ifndef CONFIG_ATOMIC_OPERATIONS_BUILTIN */ diff --git a/components/bt/esp_ble_mesh/mesh_core/adv.c b/components/bt/esp_ble_mesh/mesh_core/adv.c index b8bcf38966e..29211267b70 100644 --- a/components/bt/esp_ble_mesh/mesh_core/adv.c +++ b/components/bt/esp_ble_mesh/mesh_core/adv.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -311,8 +311,7 @@ static void adv_thread(void *p) } /* busy == 0 means this was canceled */ - if (BLE_MESH_ADV(*buf)->busy) { - BLE_MESH_ADV(*buf)->busy = 0U; + if (bt_mesh_atomic_cas(&BLE_MESH_ADV_BUSY(*buf), 1, 0)) { #if !defined(CONFIG_BLE_MESH_RELAY_ADV_BUF) if (adv_send(*buf)) { BT_WARN("Failed to send adv packet"); @@ -427,7 +426,7 @@ static void bt_mesh_unref_buf(bt_mesh_msg_t *msg) if (msg->arg) { buf = (struct net_buf *)msg->arg; - BLE_MESH_ADV(buf)->busy = 0U; + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 0); if (buf->ref > 1U) { buf->ref = 1U; } @@ -471,7 +470,7 @@ void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb, BLE_MESH_ADV(buf)->cb = cb; BLE_MESH_ADV(buf)->cb_data = cb_data; - BLE_MESH_ADV(buf)->busy = 1U; + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 1); bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); @@ -573,7 +572,7 @@ void bt_mesh_relay_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *c BLE_MESH_ADV(buf)->cb = cb; BLE_MESH_ADV(buf)->cb_data = cb_data; - BLE_MESH_ADV(buf)->busy = 1U; + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 1); msg.arg = (void *)net_buf_ref(buf); msg.src = src; @@ -736,7 +735,7 @@ static void bt_mesh_ble_adv_send(struct net_buf *buf, const struct bt_mesh_send_ BLE_MESH_ADV(buf)->cb = cb; BLE_MESH_ADV(buf)->cb_data = cb_data; - BLE_MESH_ADV(buf)->busy = 1U; + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 1); bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); @@ -755,7 +754,7 @@ static void ble_adv_tx_reset(struct ble_adv_tx *tx, bool unref) } bt_mesh_atomic_set(tx->flags, 0); memset(&tx->param, 0, sizeof(tx->param)); - BLE_MESH_ADV(tx->buf)->busy = 0U; + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(tx->buf), 0); if (unref) { net_buf_unref(tx->buf); } @@ -946,7 +945,8 @@ int bt_mesh_stop_ble_advertising(uint8_t index) /* busy 1, ref 1; busy 1, ref 2; * busy 0, ref 0; busy 0, ref 1; */ - if (BLE_MESH_ADV(tx->buf)->busy == 1U && + + if (bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(tx->buf)) && tx->buf->ref == 1U) { unref = false; } diff --git a/components/bt/esp_ble_mesh/mesh_core/adv.h b/components/bt/esp_ble_mesh/mesh_core/adv.h index 27108c203a0..bcc333efa12 100644 --- a/components/bt/esp_ble_mesh/mesh_core/adv.h +++ b/components/bt/esp_ble_mesh/mesh_core/adv.h @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,6 +10,7 @@ #ifndef _ADV_H_ #define _ADV_H_ +#include "mesh_atomic.h" #include "mesh_access.h" #include "mesh_bearer_adapt.h" @@ -23,7 +24,8 @@ extern "C" { /* The user data is a pointer (4 bytes) to struct bt_mesh_adv */ #define BLE_MESH_ADV_USER_DATA_SIZE 4 -#define BLE_MESH_ADV(buf) (*(struct bt_mesh_adv **)net_buf_user_data(buf)) +#define BLE_MESH_ADV(buf) (*(struct bt_mesh_adv **)net_buf_user_data(buf)) +#define BLE_MESH_ADV_BUSY(buf) (BLE_MESH_ADV(buf)->busy) typedef struct bt_mesh_msg { bool relay; /* Flag indicates if the packet is a relayed one */ @@ -45,8 +47,10 @@ struct bt_mesh_adv { const struct bt_mesh_send_cb *cb; void *cb_data; - uint8_t type:3, - busy:1; + uint8_t type:3; + + bt_mesh_atomic_t busy; + uint8_t xmit; }; diff --git a/components/bt/esp_ble_mesh/mesh_core/friend.c b/components/bt/esp_ble_mesh/mesh_core/friend.c index b2f57dcccd5..1478fe1554f 100644 --- a/components/bt/esp_ble_mesh/mesh_core/friend.c +++ b/components/bt/esp_ble_mesh/mesh_core/friend.c @@ -174,7 +174,7 @@ static void friend_clear(struct bt_mesh_friend *frnd, uint8_t reason) /* Cancel the sending if necessary */ if (frnd->pending_buf) { bt_mesh_adv_buf_ref_debug(__func__, frnd->last, 2U, BLE_MESH_BUF_REF_EQUAL); - BLE_MESH_ADV(frnd->last)->busy = 0U; + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(frnd->last), 0); } else { bt_mesh_adv_buf_ref_debug(__func__, frnd->last, 1U, BLE_MESH_BUF_REF_EQUAL); } diff --git a/components/bt/esp_ble_mesh/mesh_core/prov.c b/components/bt/esp_ble_mesh/mesh_core/prov.c index 29c39731524..3f8916e2dfa 100644 --- a/components/bt/esp_ble_mesh/mesh_core/prov.c +++ b/components/bt/esp_ble_mesh/mesh_core/prov.c @@ -285,7 +285,7 @@ static void free_segments(void) link.tx.buf[i] = NULL; bt_mesh_adv_buf_ref_debug(__func__, buf, 3U, BLE_MESH_BUF_REF_SMALL); /* Mark as canceled */ - BLE_MESH_ADV(buf)->busy = 0U; + bt_mesh_atomic_set(&BLE_MESH_ADV_BUSY(buf), 0); net_buf_unref(buf); } @@ -1327,7 +1327,7 @@ static void prov_retransmit(struct k_work *work) break; } - if (BLE_MESH_ADV(buf)->busy) { + if (bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(buf))) { continue; } diff --git a/components/bt/esp_ble_mesh/mesh_core/transport.c b/components/bt/esp_ble_mesh/mesh_core/transport.c index 6cbf7d9fd51..d62a6aa7b59 100644 --- a/components/bt/esp_ble_mesh/mesh_core/transport.c +++ b/components/bt/esp_ble_mesh/mesh_core/transport.c @@ -2,7 +2,7 @@ /* * SPDX-FileCopyrightText: 2017 Intel Corporation - * SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2018-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -257,7 +257,15 @@ static void seg_tx_done(struct seg_tx *tx, uint8_t seg_idx) { bt_mesh_adv_buf_ref_debug(__func__, tx->seg[seg_idx], 3U, BLE_MESH_BUF_REF_SMALL); - BLE_MESH_ADV(tx->seg[seg_idx])->busy = 0U; + /** + * When cancelling a segment that is still in the adv sending queue, `tx->seg_pending` + * must else be decremented by one. More detailed information + * can be found in BLEMESH24-26. + */ + if (bt_mesh_atomic_cas(&BLE_MESH_ADV_BUSY(tx->seg[seg_idx]), 1, 0)) { + tx->seg_pending--; + } + net_buf_unref(tx->seg[seg_idx]); tx->seg[seg_idx] = NULL; tx->nack_count--; @@ -388,7 +396,7 @@ static void seg_tx_send_unacked(struct seg_tx *tx) continue; } - if (BLE_MESH_ADV(seg)->busy) { + if (bt_mesh_atomic_get(&BLE_MESH_ADV_BUSY(seg))) { BT_DBG("Skipping segment that's still advertising"); continue; }