drivers: mbox: nrf_bellboard: only clear events that raised the IRQ

The current implementation is such that if two or more events are
generated in quick succession, only one is handled. This would
have happened as follows.

At the beginning of the ISR, the contents of INTPEND are read.
Then, the ISR unconditionally clears all events that are set.

When two (or more) events are generated in rapid succession,
it may happen that by the time we enter the ISR, INTPEND is set
only for one event, but while we process the ISR, EVENTS_TRIGGERED
will be set for more than just that one event (more events are
generated).

By unconditionally clearing all events, we can potentially lose
all events that are generated during ISR processing.

This patch changes the ISR so that it only clears those events
that have a corresponding bit set in INTPEND at the time it is read.

Signed-off-by: Emanuele Di Santo <emdi@nordicsemi.no>
This commit is contained in:
Emanuele Di Santo 2024-07-16 10:23:13 +02:00 committed by Anas Nashif
parent 4ba5ad99cc
commit 271ef88e05

View file

@ -8,6 +8,7 @@
#include <zephyr/devicetree.h>
#include <zephyr/drivers/mbox.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/__assert.h>
#include <hal/nrf_bellboard.h>
@ -47,11 +48,20 @@ static void bellboard_rx_isr(const void *parameter)
for (uint8_t i = 0U; i < NRF_BELLBOARD_EVENTS_TRIGGERED_COUNT; i++) {
nrf_bellboard_event_t event = nrf_bellboard_triggered_event_get(i);
if (nrf_bellboard_event_check(bellboard, event)) {
nrf_bellboard_event_clear(bellboard, event);
}
if ((int_pend & BIT(i)) != 0U) {
/* Only clear those events that have their corresponding bit set
* in INTPEND at the time we read it. Otherwise, if two (or more)
* events are generated in quick succession, INTPEND may be set for
* only one of events, but we clear the EVENTS_TRIGGERED bit for
* all of them, thus losing them.
*
* Assume nrf_bellboard_event_check() is true for the event
* that raised this interrupt.
*/
__ASSERT_NO_MSG(nrf_bellboard_event_check(bellboard, event));
nrf_bellboard_event_clear(bellboard, event);
if (cbs[i] != NULL) {
cbs[i](DEVICE_DT_INST_GET(0), i, cbs_ctx[i], NULL);
}