From 117a3ed76bd9a5a750243a41542de83b049257fa Mon Sep 17 00:00:00 2001 From: Kamil Gawor Date: Tue, 25 Jul 2023 09:41:36 +0200 Subject: [PATCH] nfc: Fix NFC IRQ context switching Fixed issue where NFC events data could be missed in case when NFC interrupts would be executed faster than the NFC workqueue or the NFC thread. NCSDK-22681 Signed-off-by: Kamil Gawor --- .../releases/release-notes-changelog.rst | 3 ++- subsys/nfc/lib/platform_internal_thread.c | 22 ++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) 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 6332b2317818..cce660ef607f 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 166e8633c107..b6f26348e60e 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: