From c001cfa603ef0dcb95196f1942ce2e4d5bd6385b Mon Sep 17 00:00:00 2001 From: Damien George Date: Thu, 30 Jun 2022 14:53:05 +1000 Subject: [PATCH] rp2/mpnetworkport: Convert network task scheduling to use PendSV IRQ. It is more reliable and scales better when more components need it. Work done in collaboration with Graham Sanderson and Peter Harper. Signed-off-by: Damien George --- ports/rp2/CMakeLists.txt | 2 ++ ports/rp2/mpnetworkport.c | 60 ++++++++------------------------- ports/rp2/pendsv.c | 70 +++++++++++++++++++++++++++++++++++++++ ports/rp2/pendsv.h | 49 +++++++++++++++++++++++++++ 4 files changed, 134 insertions(+), 47 deletions(-) create mode 100644 ports/rp2/pendsv.c create mode 100644 ports/rp2/pendsv.h diff --git a/ports/rp2/CMakeLists.txt b/ports/rp2/CMakeLists.txt index 9f71f6584079..50afa55a9766 100644 --- a/ports/rp2/CMakeLists.txt +++ b/ports/rp2/CMakeLists.txt @@ -111,6 +111,7 @@ set(MICROPY_SOURCE_PORT mphalport.c mpnetworkport.c mpthreadport.c + pendsv.c rp2_flash.c rp2_pio.c tusb_port.c @@ -141,6 +142,7 @@ set(MICROPY_SOURCE_QSTR ) set(PICO_SDK_COMPONENTS + cmsis_core hardware_adc hardware_base hardware_clocks diff --git a/ports/rp2/mpnetworkport.c b/ports/rp2/mpnetworkport.c index 124907f53870..2b01b62192d0 100644 --- a/ports/rp2/mpnetworkport.c +++ b/ports/rp2/mpnetworkport.c @@ -26,6 +26,7 @@ #include "py/runtime.h" #include "py/mphal.h" +#include "pendsv.h" #if MICROPY_PY_LWIP @@ -36,14 +37,14 @@ #define LWIP_TICK_RATE_MS 64 static alarm_id_t lwip_alarm_id = -1; -static bool lwip_can_poll = true; -static bool lwip_poll_pending = false; #if MICROPY_PY_NETWORK_WIZNET5K -static bool wiznet_poll_pending = false; - void wiznet5k_poll(void); void wiznet5k_deinit(void); + +void wiznet5k_try_poll(void) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_WIZNET, wiznet5k_poll); +} #endif u32_t sys_now(void) { @@ -51,62 +52,27 @@ u32_t sys_now(void) { return mp_hal_ticks_ms(); } -STATIC uint32_t lwip_poll(void) { +STATIC void lwip_poll(void) { // Run the lwIP internal updates sys_check_timeouts(); - - return MAX(5, MIN(sys_timeouts_sleeptime(), LWIP_TICK_RATE_MS)); } void lwip_lock_acquire(void) { - lwip_can_poll = false; + // Prevent PendSV from running. + pendsv_suspend(); } void lwip_lock_release(void) { - lwip_can_poll = false; - #if MICROPY_PY_NETWORK_WIZNET5K - if (wiznet_poll_pending) { - wiznet5k_poll(); - wiznet_poll_pending = false; - } - #endif - - if (lwip_poll_pending) { - lwip_poll(); - lwip_poll_pending = false; - } - lwip_can_poll = true; + // Allow PendSV to run again. + pendsv_resume(); } -uint32_t lwip_try_poll(void) { - uint32_t ret = LWIP_TICK_RATE_MS; - if (lwip_can_poll) { - lwip_can_poll = false; - ret = lwip_poll(); - lwip_can_poll = true; - } else { - lwip_poll_pending = true; - } - return ret; -} - -#if MICROPY_PY_NETWORK_WIZNET5K -void wiznet5k_try_poll(void) { - if (lwip_can_poll) { - lwip_can_poll = false; - wiznet5k_poll(); - lwip_can_poll = true; - } else { - wiznet_poll_pending = true; - } -} -#endif - STATIC int64_t alarm_callback(alarm_id_t id, void *user_data) { + pendsv_schedule_dispatch(PENDSV_DISPATCH_LWIP, lwip_poll); #if MICROPY_PY_NETWORK_WIZNET5K - wiznet5k_try_poll(); + pendsv_schedule_dispatch(PENDSV_DISPATCH_WIZNET, wiznet5k_poll); #endif - return (int64_t)lwip_try_poll() * 1000; + return LWIP_TICK_RATE_MS * 1000; } void mod_network_lwip_init(void) { diff --git a/ports/rp2/pendsv.c b/ports/rp2/pendsv.c new file mode 100644 index 000000000000..006303d46fbf --- /dev/null +++ b/ports/rp2/pendsv.c @@ -0,0 +1,70 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include "pendsv.h" +#include "RP2040.h" + +static pendsv_dispatch_t pendsv_dispatch_table[PENDSV_DISPATCH_NUM_SLOTS]; +static int pendsv_lock; + +void pendsv_suspend(void) { + pendsv_lock++; +} + +void pendsv_resume(void) { + pendsv_lock--; + assert(pendsv_lock >= 0); + // Run pendsv if needed. Find an entry with a dispatch and call pendsv dispatch + // with it. If pendsv runs it will service all slots. + int count = PENDSV_DISPATCH_NUM_SLOTS; + while (count--) { + if (pendsv_dispatch_table[count]) { + pendsv_schedule_dispatch(count, pendsv_dispatch_table[count]); + break; + } + } +} + +void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f) { + assert(pendsv_lock >= 0); + pendsv_dispatch_table[slot] = f; + if (pendsv_lock == 0) { + SCB->ICSR = SCB_ICSR_PENDSVSET_Msk; + } +} + +// PendSV interrupt handler to perform background processing. +void PendSV_Handler(void) { + assert(pendsv_lock == 0); + for (size_t i = 0; i < PENDSV_DISPATCH_NUM_SLOTS; ++i) { + if (pendsv_dispatch_table[i] != NULL) { + pendsv_dispatch_t f = pendsv_dispatch_table[i]; + pendsv_dispatch_table[i] = NULL; + f(); + } + } +} diff --git a/ports/rp2/pendsv.h b/ports/rp2/pendsv.h new file mode 100644 index 000000000000..7bb43208ab8a --- /dev/null +++ b/ports/rp2/pendsv.h @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2022 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#ifndef MICROPY_INCLUDED_RP2_PENDSV_H +#define MICROPY_INCLUDED_RP2_PENDSV_H + +#include + +enum { + #if MICROPY_PY_LWIP + PENDSV_DISPATCH_LWIP, + #endif + #if MICROPY_PY_NETWORK_WIZNET5K + PENDSV_DISPATCH_WIZNET, + #endif + PENDSV_DISPATCH_MAX +}; + +#define PENDSV_DISPATCH_NUM_SLOTS PENDSV_DISPATCH_MAX + +typedef void (*pendsv_dispatch_t)(void); + +void pendsv_suspend(void); +void pendsv_resume(void); +void pendsv_schedule_dispatch(size_t slot, pendsv_dispatch_t f); + +#endif // MICROPY_INCLUDED_RP2_PENDSV_H