diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index cf335e9b5e..d5c4f2bb48 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -18,6 +18,7 @@ if(NOT "${target}" STREQUAL "esp32c3") # should test arch here not target, TODO set(include_dirs include + include/esp_additions port/xtensa/include) set(private_include_dirs @@ -34,6 +35,7 @@ else() # RISC-V set(include_dirs include + include/esp_additions port/riscv/include) set(private_include_dirs @@ -57,6 +59,8 @@ list(APPEND srcs "FreeRTOS-openocd.c" "freertos_v8_compat.c") +list(APPEND private_include_dirs "esp_additions/private_include") # For include "freertos_tasks_c_additions.h" + if(CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY) list(APPEND srcs "port/xtensa/xtensa_loadstore_handler.S") endif() diff --git a/components/freertos/component.mk b/components/freertos/component.mk index e72576cbcd..9933318079 100644 --- a/components/freertos/component.mk +++ b/components/freertos/component.mk @@ -6,9 +6,9 @@ ifdef CONFIG_FREERTOS_DEBUG_OCDAWARE COMPONENT_ADD_LDFLAGS += -Wl,--undefined=uxTopUsedPriority endif -COMPONENT_ADD_INCLUDEDIRS := include port/xtensa/include -COMPONENT_PRIV_INCLUDEDIRS := include/freertos port/xtensa/include/freertos port/xtensa . -COMPONENT_SRCDIRS += port port/xtensa +COMPONENT_ADD_INCLUDEDIRS := include include/esp_additions port/xtensa/include +COMPONENT_PRIV_INCLUDEDIRS := esp_additions/private_include include/esp_additions include/freertos port/xtensa/include/freertos port/xtensa . +COMPONENT_SRCDIRS += port port/xtensa esp_additions/ ifndef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY COMPONENT_OBJEXCLUDE := xtensa/xtensa_loadstore_handler.o diff --git a/components/freertos/esp_additions/private_include/freertos_tasks_c_additions.h b/components/freertos/esp_additions/private_include/freertos_tasks_c_additions.h new file mode 100644 index 0000000000..bf8f09a08e --- /dev/null +++ b/components/freertos/esp_additions/private_include/freertos_tasks_c_additions.h @@ -0,0 +1,211 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "freertos/idf_additions_inc.h" + +/** + * This file will be included in `tasks.c` file, thus, it must NOT be included + * by any (other) file. + * The functions below only consist in getters for the static variables in + * `tasks.c` file. + * The only source files that should call these functions are the ones in + * `/additions` directory. + */ + +#if ( INCLUDE_vTaskPrioritySet == 1 ) + +void prvTaskPriorityRaise( prvTaskSavedPriority_t * pxSavedPriority, UBaseType_t uxNewPriority ) +{ + TCB_t * pxTCB; + UBaseType_t uxPriorityUsedOnEntry; + + configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) ); + + /* Ensure the new priority is valid. */ + if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES ) + { + uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U; + } + + taskENTER_CRITICAL( &xTaskQueueMutex ); + { + pxTCB = prvGetTCBFromHandle( NULL ); + + #if ( configUSE_MUTEXES == 1 ) + { + pxSavedPriority->uxPriority = pxTCB->uxPriority; + pxSavedPriority->uxBasePriority = pxTCB->uxBasePriority; + + /* If uxNewPriority < uxBasePriority, then there is nothing else to + * do, as uxBasePriority is always <= uxPriority. */ + if( uxNewPriority > pxTCB->uxBasePriority ) + { + pxTCB->uxBasePriority = uxNewPriority; + + /* Remember the task's current priority before attempting to + * change it. If the task's current priority is changed, it must + * be done so before moving the task between task lists) in order + * for the taskRESET_READY_PRIORITY() macro to function correctly. */ + uxPriorityUsedOnEntry = pxTCB->uxPriority; + + if( uxNewPriority > pxTCB->uxPriority ) + { + pxTCB->uxPriority = uxNewPriority; + + /* Only reset the event list item value if the value is not + * being used for anything else. */ + if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) + { + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + } + + /* If the task is in the blocked or suspended list we need do + * nothing more than change its priority variable. However, if + * the task is in a ready list it needs to be removed and placed + * in the list appropriate to its new priority. */ + if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) + { + /* The task is currently in its ready list - remove before + * adding it to its new ready list. As we are in a critical + * section we can do this even if the scheduler is suspended. */ + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + /* It is known that the task is in its ready list so + * there is no need to check again and the port level + * reset macro can be called directly. */ + portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority ); + } + prvAddTaskToReadyList( pxTCB ); + } + } + } + } + #else /* if ( configUSE_MUTEXES == 1 ) */ + { + pxSavedPriority->uxPriority = pxTCB->uxPriority; + if ( uxNewPriority > pxTCB->uxPriority) + { + vTaskPrioritySet( NULL, uxNewPriority ); + } + } + #endif + } + taskEXIT_CRITICAL( &xTaskQueueMutex ); +} + +void prvTaskPriorityRestore( prvTaskSavedPriority_t * pxSavedPriority ) +{ + TCB_t * pxTCB; + UBaseType_t uxNewPriority; + UBaseType_t uxPriorityUsedOnEntry; + UBaseType_t uxBasePriorityUsedOnEntry; + BaseType_t xYieldRequired = pdFALSE; + + taskENTER_CRITICAL( &xTaskQueueMutex ); + { + pxTCB = prvGetTCBFromHandle( NULL ); + + #if ( configUSE_MUTEXES == 1 ) + { + /* If the saved uxBasePriority == the task's uxBasePriority, it means + * that prvTaskPriorityRaise() never raised the task's uxBasePriority. + * In that case, there is nothing else to do. */ + if( pxSavedPriority->uxBasePriority != pxTCB->uxBasePriority ) + { + uxBasePriorityUsedOnEntry = pxTCB->uxBasePriority; + pxTCB->uxBasePriority = pxSavedPriority->uxBasePriority; + + /* Remember the task's current priority before attempting to + * change it. If the task's current priority is changed, it must + * be done so before moving the task between task lists in order + * for the taskRESET_READY_PRIORITY() macro to function correctly. */ + uxPriorityUsedOnEntry = pxTCB->uxPriority; + + /* Check if the task inherited a priority after prvTaskPriorityRaise(). + * If this is the case, there is nothing else to do. The priority + * will be restored when the task disinherits its priority. */ + if( pxTCB->uxPriority == uxBasePriorityUsedOnEntry ) + { + if( pxTCB->uxMutexesHeld == 0 ) + { + /* The task may have inherited a priority before prvTaskPriorityRaise() + * then disinherited a priority after prvTaskPriorityRaise(). + * Thus we need set the uxPriority to the saved base priority + * so that the task's priority gets restored to the priority + * before any inheritance or raising. */ + pxTCB->uxPriority = pxSavedPriority->uxBasePriority; + } + else + { + /* The task may have inherited a priority before prvTaskPriorityRaise() + * was called. Thus, we need to restore uxPriority to the + * "saved uxPriority" so that the task still retains that + * inherited priority. */ + pxTCB->uxPriority = pxSavedPriority->uxPriority; + } + uxNewPriority = pxTCB->uxPriority; + + if( uxNewPriority < uxPriorityUsedOnEntry ) + { + /* Setting the priority of the running task down means + * there may now be another task of higher priority that + * is ready to execute. */ + xYieldRequired = pdTRUE; + } + + /* Only reset the event list item value if the value is not + * being used for anything else. */ + if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) + { + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + } + + /* If the task is in the blocked or suspended list we need do + * nothing more than change its priority variable. However, if + * the task is in a ready list it needs to be removed and placed + * in the list appropriate to its new priority. */ + if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) + { + /* The task is currently in its ready list - remove before + * adding it to its new ready list. As we are in a critical + * section we can do this even if the scheduler is suspended. */ + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + /* It is known that the task is in its ready list so + * there is no need to check again and the port level + * reset macro can be called directly. */ + portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority ); + } + prvAddTaskToReadyList( pxTCB ); + } + + if( xYieldRequired != pdFALSE ) + { + taskYIELD_IF_USING_PREEMPTION(); + } + } + } + } + #else /* if ( configUSE_MUTEXES == 1 ) */ + { + vTaskPrioritySet( NULL, pxSavedPriority->uxPriority ); + } + #endif + } + taskEXIT_CRITICAL( &xTaskQueueMutex ); +} + +#endif // ( INCLUDE_vTaskPrioritySet == 1 ) diff --git a/components/freertos/include/esp_additions/freertos/idf_additions.h b/components/freertos/include/esp_additions/freertos/idf_additions.h new file mode 100644 index 0000000000..bd1d0bd238 --- /dev/null +++ b/components/freertos/include/esp_additions/freertos/idf_additions.h @@ -0,0 +1,57 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "idf_additions_inc.h" + +#if ( INCLUDE_vTaskPrioritySet == 1 ) + +/** + * INCLUDE_vTaskPrioritySet must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Saves the current priority and current base priority of a task, then raises the tasks + * current and base priority to uxNewPriority if uxNewPriority is of a higher priority. + * Once a task's priority has been raised with this function, the priority can be restored + * by calling prvTaskPriorityRestore() + * - Note that this function differs from vTaskPrioritySet() as the task's current priority + * will be modified even if the task has already inherited a priority. + * - This function is intended for special circumstance where a task must be forced immediately + * to a higher priority. + * + * For configUSE_MUTEXES == 0: A context switch will occur before the function returns if the priority + * being set is higher than the currently executing task. + * + * @note This functions is private is only be called internally within various IDF components. + * Users should never call this function from their application. + * + * @note vTaskPrioritySet() should not be called while a task's priority is already raised via this function + * + * @param pxSavedPriority returns base and current priorities + * + * @param uxNewPriority The priority to which the task will be set. + */ +void prvTaskPriorityRaise( prvTaskSavedPriority_t * pxSavedPriority, UBaseType_t uxNewPriority ); + +/** + * INCLUDE_vTaskPrioritySet must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Restore a task's priority that was previously raised by prvTaskPriorityRaise(). + * + * For configUSE_MUTEXES == 0: A context switch will occur before the function returns if the priority + * being set is higher than the currently executing task. + * + * @note This functions is private is only be called internally within various IDF components. + * Users should never call this function from their application. + * + * @param pxSavedPriority previously saved base and current priorities that need to be restored + */ +void prvTaskPriorityRestore( prvTaskSavedPriority_t * pxSavedPriority ); + +#endif // ( INCLUDE_vTaskPrioritySet == 1) diff --git a/components/freertos/include/esp_additions/freertos/idf_additions_inc.h b/components/freertos/include/esp_additions/freertos/idf_additions_inc.h new file mode 100644 index 0000000000..25b0b6d9a4 --- /dev/null +++ b/components/freertos/include/esp_additions/freertos/idf_additions_inc.h @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#ifndef FREERTOS_ADDITITIONS_INC_H_ +#define FREERTOS_ADDITITIONS_INC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" + +#if ( INCLUDE_vTaskPrioritySet == 1 ) + +typedef struct { + UBaseType_t uxPriority; +#if ( configUSE_MUTEXES == 1 ) + UBaseType_t uxBasePriority; +#endif +} prvTaskSavedPriority_t; + +#endif // ( INCLUDE_vTaskPrioritySet == 1) + +#ifdef __cplusplus +} +#endif + +#endif //FREERTOS_ADDITITIONS_INC_H_ diff --git a/components/freertos/linker.lf b/components/freertos/linker.lf index 60d3505337..fcf6a39e17 100644 --- a/components/freertos/linker.lf +++ b/components/freertos/linker.lf @@ -31,6 +31,8 @@ entries: tasks: xTaskRemoveFromUnorderedEventList (default) tasks: uxTaskPriorityGet (default) tasks: vTaskPrioritySet (default) + tasks: prvTaskPriorityRaise (default) + tasks: prvTaskPriorityRestore (default) tasks: vTaskSetThreadLocalStoragePointerAndDelCallback (default) tasks: pvTaskGetThreadLocalStoragePointer (default) tasks: xTaskGetCurrentTaskHandleForCPU (default) diff --git a/components/freertos/port/riscv/include/freertos/FreeRTOSConfig.h b/components/freertos/port/riscv/include/freertos/FreeRTOSConfig.h index cfae510049..319f8ba128 100644 --- a/components/freertos/port/riscv/include/freertos/FreeRTOSConfig.h +++ b/components/freertos/port/riscv/include/freertos/FreeRTOSConfig.h @@ -302,4 +302,6 @@ extern int xPortSwitchFlag; #endif #endif +#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 1 + #endif // FREERTOS_CONFIG_RISCV_H diff --git a/components/freertos/port/xtensa/include/freertos/FreeRTOSConfig.h b/components/freertos/port/xtensa/include/freertos/FreeRTOSConfig.h index 27f9c691b3..dab869f1a9 100644 --- a/components/freertos/port/xtensa/include/freertos/FreeRTOSConfig.h +++ b/components/freertos/port/xtensa/include/freertos/FreeRTOSConfig.h @@ -360,4 +360,6 @@ extern uint32_t port_switch_flag[]; #endif #endif +#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 1 + #endif // FREERTOS_CONFIG_XTENSA_H diff --git a/components/spi_flash/cache_utils.c b/components/spi_flash/cache_utils.c index 436118c8a5..1394e0b589 100644 --- a/components/spi_flash/cache_utils.c +++ b/components/spi_flash/cache_utils.c @@ -11,6 +11,7 @@ #include #include +#include #include #if CONFIG_IDF_TARGET_ESP32 #include "soc/dport_reg.h" @@ -150,8 +151,9 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu(void) } else { // Temporarily raise current task priority to prevent a deadlock while // waiting for IPC task to start on the other CPU - int old_prio = uxTaskPriorityGet(NULL); - vTaskPrioritySet(NULL, configMAX_PRIORITIES - 1); + prvTaskSavedPriority_t SavedPriority; + prvTaskPriorityRaise(&SavedPriority, configMAX_PRIORITIES - 1); + // Signal to the spi_flash_op_block_task on the other CPU that we need it to // disable cache there and block other tasks from executing. s_flash_op_can_start = false; @@ -164,7 +166,7 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu(void) // Disable scheduler on the current CPU vTaskSuspendAll(); // Can now set the priority back to the normal one - vTaskPrioritySet(NULL, old_prio); + prvTaskPriorityRestore(&SavedPriority); // This is guaranteed to run on CPU because the other CPU is now // occupied by highest priority task assert(xPortGetCoreID() == cpuid);