diff --git a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst index 6332b231781..cce660ef607 100644 --- a/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst +++ b/doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst @@ -602,7 +602,8 @@ Libraries for networking Libraries for NFC ----------------- -|no_changes_yet_note| + * Fixed the potential issue where the NFC interrupt context switching could loose interrupts data. + This could happen if interrupts would be executed much faster than the NFC workqueue or thread. Nordic Security Module ---------------------- diff --git a/subsys/nfc/lib/platform_internal_thread.c b/subsys/nfc/lib/platform_internal_thread.c index 166e8633c10..b6f26348e60 100644 --- a/subsys/nfc/lib/platform_internal_thread.c +++ b/subsys/nfc/lib/platform_internal_thread.c @@ -30,13 +30,30 @@ struct nfc_item_header { }; #ifdef CONFIG_NFC_OWN_THREAD -static K_SEM_DEFINE(cb_sem, 0, 1); +/* By using a counting semaphore, NFC events interrupt can go faster than the processing thread. + * All events must be processed. + */ +static K_SEM_DEFINE(cb_sem, 0, K_SEM_MAX_LIMIT); #endif /* CONFIG_NFC_OWN_THREAD */ static bool buf_full; static nfc_lib_cb_resolve_t nfc_cb_resolve; RING_BUF_DECLARE(nfc_cb_ring, CONFIG_NFC_RING_SIZE); +static void work_resubmit(struct k_work *work, struct ring_buf *buf) +{ + if (!IS_ENABLED(CONFIG_NFC_OWN_THREAD)) { + if (!ring_buf_is_empty(buf)) { + int ret = k_work_submit(work); + /* In this case, work can be scheduled either from IRQ or to the queue + * running work items during the run. + */ + __ASSERT_NO_MSG(((ret == 0) || (ret == 2))); + ARG_UNUSED(ret); + } + } +} + static int ring_buf_get_data(struct ring_buf *buf, uint8_t **data, uint32_t size, bool *is_alloc) { uint32_t tmp; @@ -120,6 +137,7 @@ static void cb_work(struct k_work *work) nfc_cb_resolve(ctx, data); if (header.data_size == 0) { + work_resubmit(work, &nfc_cb_ring); return; } @@ -133,6 +151,8 @@ static void cb_work(struct k_work *work) } } + work_resubmit(work, &nfc_cb_ring); + return; error: