Bluetooth: controller: Prevent invalid compiler code reordering

In ull_disable, it is imperative that the callback is set up before a
second reference counter check, otherwise it may happen that an LLL done
event has already passed when the disable callback and semaphore is
assigned.

This causes the HCI thread to wait until timeout and assert after
ull_ticker_stop_with_mark.

For certain compilers, due to compiler optimizations, it can be seen
from the assembler code that the callback is assigned after the second
reference counter check.

By adding memory barriers, the code correctly reorders code to the
expected sequence.

Signed-off-by: Morten Priess <mtpr@oticon.com>
This commit is contained in:
Morten Priess 2024-05-06 16:08:42 +02:00 committed by Carles Cufí
commit 7f82b6a219

View file

@ -1953,12 +1953,15 @@ int ull_disable(void *lll)
if (!ull_ref_get(hdr)) { if (!ull_ref_get(hdr)) {
return -EALREADY; return -EALREADY;
} }
cpu_dmb(); /* Ensure synchronized data access */
k_sem_init(&sem, 0, 1); k_sem_init(&sem, 0, 1);
hdr->disabled_param = &sem; hdr->disabled_param = &sem;
hdr->disabled_cb = disabled_cb; hdr->disabled_cb = disabled_cb;
cpu_dmb(); /* Ensure synchronized data access */
/* ULL_HIGH can run after we have call `ull_ref_get` and it can /* ULL_HIGH can run after we have call `ull_ref_get` and it can
* decrement the ref count. Hence, handle this race condition by * decrement the ref count. Hence, handle this race condition by
* ensuring that `disabled_cb` has been set while the ref count is still * ensuring that `disabled_cb` has been set while the ref count is still