| 
									
										
										
										
											2021-09-21 23:41:27 +03:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2021-12-21 19:17:11 +08:00
										 |  |  |  * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD | 
					
						
							| 
									
										
										
										
											2021-09-21 23:41:27 +03:00
										 |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: Apache-2.0 | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-09-12 18:54:45 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <stddef.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <assert.h>
 | 
					
						
							|  |  |  | #include "esp_err.h"
 | 
					
						
							|  |  |  | #include "esp_ipc.h"
 | 
					
						
							| 
									
										
										
										
											2021-12-21 19:17:11 +08:00
										 |  |  | #include "esp_private/esp_ipc_isr.h"
 | 
					
						
							| 
									
										
										
										
											2016-09-12 18:54:45 +08:00
										 |  |  | #include "esp_attr.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "freertos/FreeRTOS.h"
 | 
					
						
							|  |  |  | #include "freertos/task.h"
 | 
					
						
							|  |  |  | #include "freertos/semphr.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-12 08:52:15 +03:00
										 |  |  | #if !defined(CONFIG_FREERTOS_UNICORE) || defined(CONFIG_APPTRACE_GCOV_ENABLE)
 | 
					
						
							| 
									
										
										
										
											2021-08-03 14:35:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-18 13:53:13 +08:00
										 |  |  | #if CONFIG_COMPILER_OPTIMIZATION_NONE
 | 
					
						
							|  |  |  | #define IPC_STACK_SIZE (CONFIG_ESP_IPC_TASK_STACK_SIZE + 0x100)
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #define IPC_STACK_SIZE (CONFIG_ESP_IPC_TASK_STACK_SIZE)
 | 
					
						
							|  |  |  | #endif //CONFIG_COMPILER_OPTIMIZATION_NONE
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-13 15:49:06 +05:30
										 |  |  | static DRAM_ATTR StaticSemaphore_t s_ipc_mutex_buffer[portNUM_PROCESSORS]; | 
					
						
							|  |  |  | static DRAM_ATTR StaticSemaphore_t s_ipc_sem_buffer[portNUM_PROCESSORS]; | 
					
						
							|  |  |  | static DRAM_ATTR StaticSemaphore_t s_ipc_ack_buffer[portNUM_PROCESSORS]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-25 00:09:30 +08:00
										 |  |  | static TaskHandle_t s_ipc_task_handle[portNUM_PROCESSORS]; | 
					
						
							| 
									
										
										
										
											2019-09-25 02:13:18 +08:00
										 |  |  | static SemaphoreHandle_t s_ipc_mutex[portNUM_PROCESSORS];    // This mutex is used as a global lock for esp_ipc_* APIs
 | 
					
						
							| 
									
										
										
										
											2018-09-06 11:22:41 +05:30
										 |  |  | static SemaphoreHandle_t s_ipc_sem[portNUM_PROCESSORS];      // Two semaphores used to wake each of ipc tasks
 | 
					
						
							| 
									
										
										
										
											2019-09-25 02:13:18 +08:00
										 |  |  | static SemaphoreHandle_t s_ipc_ack[portNUM_PROCESSORS];      // Semaphore used to acknowledge that task was woken up,
 | 
					
						
							| 
									
										
										
										
											2021-06-29 13:12:01 +03:00
										 |  |  |                                                              // or function has finished running
 | 
					
						
							| 
									
										
										
										
											2019-09-25 02:13:18 +08:00
										 |  |  | static volatile esp_ipc_func_t s_func[portNUM_PROCESSORS];   // Function which should be called by high priority task
 | 
					
						
							|  |  |  | static void * volatile s_func_arg[portNUM_PROCESSORS];       // Argument to pass into s_func
 | 
					
						
							| 
									
										
										
										
											2016-09-12 18:54:45 +08:00
										 |  |  | typedef enum { | 
					
						
							|  |  |  |     IPC_WAIT_FOR_START, | 
					
						
							|  |  |  |     IPC_WAIT_FOR_END | 
					
						
							|  |  |  | } esp_ipc_wait_t; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-25 02:13:18 +08:00
										 |  |  | static volatile esp_ipc_wait_t s_ipc_wait[portNUM_PROCESSORS];// This variable tells high priority task when it should give
 | 
					
						
							| 
									
										
										
										
											2016-09-12 18:54:45 +08:00
										 |  |  |                                                              //   s_ipc_ack semaphore: before s_func is called, or
 | 
					
						
							|  |  |  |                                                              //   after it returns
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-29 13:12:01 +03:00
										 |  |  | #if CONFIG_APPTRACE_GCOV_ENABLE
 | 
					
						
							|  |  |  | static volatile esp_ipc_func_t s_gcov_func = NULL;           // Gcov dump starter function which should be called by high priority task
 | 
					
						
							|  |  |  | static void * volatile s_gcov_func_arg;                      // Argument to pass into s_gcov_func
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-12 18:54:45 +08:00
										 |  |  | static void IRAM_ATTR ipc_task(void* arg) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-11-17 12:48:35 +08:00
										 |  |  |     const int cpuid = (int) arg; | 
					
						
							| 
									
										
										
										
											2016-09-12 18:54:45 +08:00
										 |  |  |     assert(cpuid == xPortGetCoreID()); | 
					
						
							| 
									
										
										
										
											2021-12-21 19:17:11 +08:00
										 |  |  | #ifdef CONFIG_ESP_IPC_ISR_ENABLE
 | 
					
						
							|  |  |  |     esp_ipc_isr_init(); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-09-12 18:54:45 +08:00
										 |  |  |     while (true) { | 
					
						
							|  |  |  |         // Wait for IPC to be initiated.
 | 
					
						
							|  |  |  |         // This will be indicated by giving the semaphore corresponding to
 | 
					
						
							|  |  |  |         // this CPU.
 | 
					
						
							|  |  |  |         if (xSemaphoreTake(s_ipc_sem[cpuid], portMAX_DELAY) != pdTRUE) { | 
					
						
							|  |  |  |             // TODO: when can this happen?
 | 
					
						
							|  |  |  |             abort(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-29 13:12:01 +03:00
										 |  |  | #if CONFIG_APPTRACE_GCOV_ENABLE
 | 
					
						
							|  |  |  |         if (s_gcov_func) { | 
					
						
							|  |  |  |             (*s_gcov_func)(s_gcov_func_arg); | 
					
						
							|  |  |  |             s_gcov_func = NULL; | 
					
						
							| 
									
										
										
										
											2021-09-21 23:41:27 +03:00
										 |  |  |             /* we can not interfer with IPC calls so no need for further processing */ | 
					
						
							|  |  |  |             continue; | 
					
						
							| 
									
										
										
										
											2016-09-12 18:54:45 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-06-29 13:12:01 +03:00
										 |  |  | #endif
 | 
					
						
							|  |  |  |         if (s_func[cpuid]) { | 
					
						
							| 
									
										
										
										
											2022-03-16 19:11:43 +08:00
										 |  |  |             // we need to cache s_func, s_func_arg and s_ipc_wait variables locally because they can be changed by a subsequent IPC call.
 | 
					
						
							| 
									
										
										
										
											2021-06-29 13:12:01 +03:00
										 |  |  |             esp_ipc_func_t func = s_func[cpuid]; | 
					
						
							| 
									
										
										
										
											2022-03-16 19:11:43 +08:00
										 |  |  |             s_func[cpuid] = NULL; | 
					
						
							| 
									
										
										
										
											2021-06-29 13:12:01 +03:00
										 |  |  |             void* arg = s_func_arg[cpuid]; | 
					
						
							| 
									
										
										
										
											2022-03-16 19:11:43 +08:00
										 |  |  |             esp_ipc_wait_t ipc_wait = s_ipc_wait[cpuid]; | 
					
						
							| 
									
										
										
										
											2021-06-29 13:12:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-16 19:11:43 +08:00
										 |  |  |             if (ipc_wait == IPC_WAIT_FOR_START) { | 
					
						
							| 
									
										
										
										
											2021-06-29 13:12:01 +03:00
										 |  |  |                 xSemaphoreGive(s_ipc_ack[cpuid]); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             (*func)(arg); | 
					
						
							| 
									
										
										
										
											2022-03-16 19:11:43 +08:00
										 |  |  |             if (ipc_wait == IPC_WAIT_FOR_END) { | 
					
						
							| 
									
										
										
										
											2021-06-29 13:12:01 +03:00
										 |  |  |                 xSemaphoreGive(s_ipc_ack[cpuid]); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2016-09-12 18:54:45 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-06-29 13:12:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-12 18:54:45 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     // TODO: currently this is unreachable code. Introduce esp_ipc_uninit
 | 
					
						
							|  |  |  |     // function which will signal to both tasks that they can shut down.
 | 
					
						
							|  |  |  |     // Not critical at this point, we don't have a use case for stopping
 | 
					
						
							|  |  |  |     // IPC yet.
 | 
					
						
							|  |  |  |     // Also need to delete the semaphore here.
 | 
					
						
							|  |  |  |     vTaskDelete(NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-18 14:37:12 +08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Initialize inter-processor call module. This function is called automatically | 
					
						
							|  |  |  |  * on CPU start and should not be called from the application. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This function start two tasks, one on each CPU. These tasks are started | 
					
						
							|  |  |  |  * with high priority. These tasks are normally inactive, waiting until one of | 
					
						
							|  |  |  |  * the esp_ipc_call_* functions to be used. One of these tasks will be | 
					
						
							|  |  |  |  * woken up to execute the callback provided to esp_ipc_call_nonblocking or | 
					
						
							|  |  |  |  * esp_ipc_call_blocking. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2019-07-16 16:33:30 +07:00
										 |  |  | static void esp_ipc_init(void) __attribute__((constructor)); | 
					
						
							| 
									
										
										
										
											2018-09-18 14:37:12 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-16 16:33:30 +07:00
										 |  |  | static void esp_ipc_init(void) | 
					
						
							| 
									
										
										
										
											2016-09-12 18:54:45 +08:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-04-07 19:14:37 +08:00
										 |  |  |     char task_name[configMAX_TASK_NAME_LEN]; | 
					
						
							| 
									
										
										
										
											2021-06-29 13:12:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-12 18:54:45 +08:00
										 |  |  |     for (int i = 0; i < portNUM_PROCESSORS; ++i) { | 
					
						
							| 
									
										
										
										
											2018-09-06 11:22:41 +05:30
										 |  |  |         snprintf(task_name, sizeof(task_name), "ipc%d", i); | 
					
						
							| 
									
										
										
										
											2021-12-13 15:49:06 +05:30
										 |  |  |         s_ipc_mutex[i] = xSemaphoreCreateMutexStatic(&s_ipc_mutex_buffer[i]); | 
					
						
							|  |  |  |         s_ipc_ack[i] = xSemaphoreCreateBinaryStatic(&s_ipc_ack_buffer[i]); | 
					
						
							|  |  |  |         s_ipc_sem[i] = xSemaphoreCreateBinaryStatic(&s_ipc_sem_buffer[i]); | 
					
						
							| 
									
										
										
										
											2022-07-18 13:53:13 +08:00
										 |  |  |         portBASE_TYPE res = xTaskCreatePinnedToCore(ipc_task, task_name, IPC_STACK_SIZE, (void*) i, | 
					
						
							| 
									
										
										
										
											2019-09-25 00:09:30 +08:00
										 |  |  |                                                     configMAX_PRIORITIES - 1, &s_ipc_task_handle[i], i); | 
					
						
							| 
									
										
										
										
											2017-07-12 11:33:51 +08:00
										 |  |  |         assert(res == pdTRUE); | 
					
						
							| 
									
										
										
										
											2021-02-12 16:01:05 +11:00
										 |  |  |         (void)res; | 
					
						
							| 
									
										
										
										
											2016-09-12 18:54:45 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static esp_err_t esp_ipc_call_and_wait(uint32_t cpu_id, esp_ipc_func_t func, void* arg, esp_ipc_wait_t wait_for) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (cpu_id >= portNUM_PROCESSORS) { | 
					
						
							|  |  |  |         return ESP_ERR_INVALID_ARG; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (xTaskGetSchedulerState() != taskSCHEDULER_RUNNING) { | 
					
						
							|  |  |  |         return ESP_ERR_INVALID_STATE; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-25 02:13:18 +08:00
										 |  |  | #ifdef CONFIG_ESP_IPC_USES_CALLERS_PRIORITY
 | 
					
						
							| 
									
										
										
										
											2019-09-25 00:09:30 +08:00
										 |  |  |     TaskHandle_t task_handler = xTaskGetCurrentTaskHandle(); | 
					
						
							|  |  |  |     UBaseType_t priority_of_current_task = uxTaskPriorityGet(task_handler); | 
					
						
							| 
									
										
										
										
											2019-09-25 02:13:18 +08:00
										 |  |  |     UBaseType_t priority_of_running_ipc_task = uxTaskPriorityGet(s_ipc_task_handle[cpu_id]); | 
					
						
							|  |  |  |     if (priority_of_running_ipc_task < priority_of_current_task) { | 
					
						
							|  |  |  |         vTaskPrioritySet(s_ipc_task_handle[cpu_id], priority_of_current_task); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     xSemaphoreTake(s_ipc_mutex[cpu_id], portMAX_DELAY); | 
					
						
							| 
									
										
										
										
											2019-09-25 00:09:30 +08:00
										 |  |  |     vTaskPrioritySet(s_ipc_task_handle[cpu_id], priority_of_current_task); | 
					
						
							| 
									
										
										
										
											2019-09-25 02:13:18 +08:00
										 |  |  | #else
 | 
					
						
							|  |  |  |     xSemaphoreTake(s_ipc_mutex[0], portMAX_DELAY); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2019-09-25 00:09:30 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-25 02:13:18 +08:00
										 |  |  |     s_func[cpu_id] = func; | 
					
						
							|  |  |  |     s_func_arg[cpu_id] = arg; | 
					
						
							|  |  |  |     s_ipc_wait[cpu_id] = wait_for; | 
					
						
							| 
									
										
										
										
											2016-09-12 18:54:45 +08:00
										 |  |  |     xSemaphoreGive(s_ipc_sem[cpu_id]); | 
					
						
							| 
									
										
										
										
											2019-09-25 02:13:18 +08:00
										 |  |  |     xSemaphoreTake(s_ipc_ack[cpu_id], portMAX_DELAY); | 
					
						
							|  |  |  | #ifdef CONFIG_ESP_IPC_USES_CALLERS_PRIORITY
 | 
					
						
							|  |  |  |     xSemaphoreGive(s_ipc_mutex[cpu_id]); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     xSemaphoreGive(s_ipc_mutex[0]); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2016-09-12 18:54:45 +08:00
										 |  |  |     return ESP_OK; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | esp_err_t esp_ipc_call(uint32_t cpu_id, esp_ipc_func_t func, void* arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return esp_ipc_call_and_wait(cpu_id, func, arg, IPC_WAIT_FOR_START); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | esp_err_t esp_ipc_call_blocking(uint32_t cpu_id, esp_ipc_func_t func, void* arg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return esp_ipc_call_and_wait(cpu_id, func, arg, IPC_WAIT_FOR_END); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-08-03 14:35:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-29 13:12:01 +03:00
										 |  |  | // currently this is only called from gcov component
 | 
					
						
							|  |  |  | #if CONFIG_APPTRACE_GCOV_ENABLE
 | 
					
						
							|  |  |  | esp_err_t esp_ipc_start_gcov_from_isr(uint32_t cpu_id, esp_ipc_func_t func, void* arg) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-09-21 23:41:27 +03:00
										 |  |  |     portBASE_TYPE ret = pdFALSE; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-29 13:12:01 +03:00
										 |  |  |     if (xTaskGetSchedulerState() != taskSCHEDULER_RUNNING) { | 
					
						
							|  |  |  |         return ESP_ERR_INVALID_STATE; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-09-21 23:41:27 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Lock IPC to avoid interferring with normal IPC calls, e.g.
 | 
					
						
							|  |  |  |        avoid situation when esp_ipc_start_gcov_from_isr() is called from IRQ | 
					
						
							|  |  |  |        in the middle of IPC call between `s_func` and `s_func_arg` modification. See esp_ipc_call_and_wait() */ | 
					
						
							|  |  |  | #ifdef CONFIG_ESP_IPC_USES_CALLERS_PRIORITY
 | 
					
						
							|  |  |  |     ret = xSemaphoreTakeFromISR(s_ipc_mutex[cpu_id], NULL); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     ret = xSemaphoreTakeFromISR(s_ipc_mutex[0], NULL); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  |     if (ret != pdTRUE) { | 
					
						
							|  |  |  |         return ESP_ERR_TIMEOUT; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-29 13:12:01 +03:00
										 |  |  |     s_gcov_func = func; | 
					
						
							|  |  |  |     s_gcov_func_arg = arg; | 
					
						
							| 
									
										
										
										
											2021-09-21 23:41:27 +03:00
										 |  |  |     ret = xSemaphoreGiveFromISR(s_ipc_sem[cpu_id], NULL); | 
					
						
							| 
									
										
										
										
											2021-06-29 13:12:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-21 23:41:27 +03:00
										 |  |  | #ifdef CONFIG_ESP_IPC_USES_CALLERS_PRIORITY
 | 
					
						
							|  |  |  |     xSemaphoreGiveFromISR(s_ipc_mutex[cpu_id], NULL); | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     xSemaphoreGiveFromISR(s_ipc_mutex[0], NULL); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ret == pdTRUE ? ESP_OK : ESP_FAIL; | 
					
						
							| 
									
										
										
										
											2021-06-29 13:12:01 +03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-10-26 21:12:26 +08:00
										 |  |  | #endif // CONFIG_APPTRACE_GCOV_ENABLE
 | 
					
						
							| 
									
										
										
										
											2021-06-29 13:12:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-26 21:12:26 +08:00
										 |  |  | #endif // !defined(CONFIG_FREERTOS_UNICORE) || defined(CONFIG_APPTRACE_GCOV_ENABLE)
 |