/* @file: ppe/sbe/sbefw/sbemain.C * * @brief This file does the following * - SBE Application Main entry point * - PK initialization * - Thread initialization * - Semaphore initialization * - IRQ setup * - Scheduling of the threads and * - Starting of the control loop code flow * */ #include "sbeexeintf.H" #include "sbetrace.H" #include "sberegaccess.H" #include "sbestates.H" #include "fapi2.H" // For target init //////////////////////////////////////////////////////////////// // @brief Global semaphores //////////////////////////////////////////////////////////////// PkSemaphore g_sbeSemCmdRecv; PkSemaphore g_sbeSemCmdProcess; //////////////////////////////////////////////////////////////// // @brief Stacks for Non-critical Interrupts and Threads //////////////////////////////////////////////////////////////// uint8_t g_sbe_Kernel_NCInt_stack[SBE_NONCRITICAL_STACK_SIZE]; uint8_t g_sbeCommandReceiver_stack[SBE_THREAD_CMD_RECV_STACK_SIZE]; uint8_t g_sbeSyncCommandProcessor_stack[SBE_THREAD_SYNC_CMD_PROC_STACK_SIZE]; uint8_t g_sbeAsyncCommandProcessor_stack[SBE_THREAD_ASYNC_CMD_PROC_STACK_SIZE]; //////////////////////////////////////////////////////////////// // @brief PkThread structure for SBE Command Receiver thread //////////////////////////////////////////////////////////////// PkThread g_sbeCommandReceiver_thread; //////////////////////////////////////////////////////////////// // @brief PkThread structure for SBE Synchronous ChipOps // processing thread //////////////////////////////////////////////////////////////// PkThread g_sbeSyncCommandProcessor_thread; //////////////////////////////////////////////////////////////// //// @brief PkThread structure for SBE Asynchronous ChipOps //// processing thread //////////////////////////////////////////////////////////////// PkThread g_sbeAsyncCommandProcessor_thread; extern "C" { // These variables are declared in linker script to keep track of // global constructor pointer functions and sbss section. extern void (*ctor_start_address)() __attribute__ ((section (".rodata"))); extern void (*ctor_end_address)() __attribute__ ((section (".rodata"))); extern uint64_t _sbss_start __attribute__ ((section (".sbss"))); extern uint64_t _sbss_end __attribute__ ((section (".sbss"))); // This function will be used to do any C++ handling required before doing // any main job. Call to this function should get generated by // compiler. // TODO via RTC 152070 // We are also initialising sbss section to zero this function. // Though it does not do any harm as of now, it is better if we use loader // or linker script to zero init sbss section. This way we will be future // garded if pk boot uses some static/global data initialised to // false in future. void __eabi() { // Initialise sbss section uint64_t *startAddr = &_sbss_start; while ( startAddr != &_sbss_end ) { *startAddr = 0; startAddr++; } // Call global constructors void(**ctors)() = &ctor_start_address; while( ctors != &ctor_end_address) { (*ctors)(); ctors++; } } } // end extern "C" //////////////////////////////////////////////////////////////// // @brief sbeInitSems - Create the necessary semaphores // // @return PK_OK - Success // PK_INVALID_SEMAPHORE_AT_CREATE - Invalid PkSemaphore // PK_INVALID_ARGUMENT_SEMAPHORE - max_count is non-zero // and less than the initial_count //////////////////////////////////////////////////////////////// uint32_t sbeInitSems(void) { SBE_ENTER("sbeInitSems"); int l_rc = PK_OK; do { l_rc = pk_semaphore_create(&g_sbeSemCmdRecv, 0, 1); if (l_rc) { break; } l_rc = pk_semaphore_create(&g_sbeSemCmdProcess, 0, 1); if (l_rc) { break; } } while (false); if (l_rc) { SBE_ERROR ("pk_semaphore_create, rc=[%d]", l_rc); } return l_rc; } //////////////////////////////////////////////////////////////// // @brief createAndResumeThreadHelper // - Create and resume the given thread // // @param[in/out] io_thread A pointer to an PkThread structure to initialize // @param[in] i_thread_routine The subroutine that implements the thread // @param[in/out] io_arg Private data to be passed as the argument to the // thread routine when it begins execution // @param[in] i_stack The stack space of the thread // @param[in] i_stack_size The size of the stack in bytes // @param[in] i_priority The initial priority of the thread // // @return PK_OK Successfully created and resumed the thread // // @return PK_INVALID_THREAD_AT_CREATE io_thread is null // @return PK_INVALID_ARGUMENT_THREAD1 i_thread_routine is null // @return PK_INVALID_ARGUMENT_THREAD2 i_priority is invalid // @return PK_INVALID_ARGUMENT_THREAD3 the stack area wraps around // the end of memory. // @return PK_STACK_OVERFLOW The stack area at thread creation // is smaller than the min safe size // @return PK_INVALID_THREAD_AT_RESUME1 io_thread is null (unlikely) // @return PK_INVALID_THREAD_AT_RESUME2 The thread is not active, // i.e. has completed or been deleted, // @return PK_PRIORITY_IN_USE_AT_RESUME Another thread is already // mapped at the priority of the thread //////////////////////////////////////////////////////////////// uint32_t createAndResumeThreadHelper(PkThread *io_pThread, PkThreadRoutine i_thread_routine, void *io_pArg, PkAddress i_stack, size_t i_stack_size, sbeThreadPriorities i_priority) { int l_rc = PK_OK; // Thread creation l_rc = pk_thread_create(io_pThread, i_thread_routine, io_pArg, i_stack, i_stack_size, (PkThreadPriority)i_priority); if(l_rc == PK_OK) { // resume the thread once created l_rc = pk_thread_resume(io_pThread); } // Check for errors creating or resuming the thread if(l_rc != PK_OK) { SBE_ERROR ("Failure creating/resuming thread, rc=[%d]", l_rc); } return l_rc; } //////////////////////////////////////////////////////////////// // @brief sbeInitThreads // Create the resume all the firmware threads // // @return See createAndResumeThreadHelper for more details //////////////////////////////////////////////////////////////// int sbeInitThreads(void) { // Locals uint32_t l_rc = PK_OK; do { // Initialize Command receiver thread l_rc = createAndResumeThreadHelper(&g_sbeCommandReceiver_thread, sbeCommandReceiver_routine, (void *)0, (PkAddress)g_sbeCommandReceiver_stack, SBE_THREAD_CMD_RECV_STACK_SIZE, THREAD_PRIORITY_5); if (l_rc) { break; } // Initialize Synchronous Command Processor thread l_rc = createAndResumeThreadHelper(&g_sbeSyncCommandProcessor_thread, sbeSyncCommandProcessor_routine, (void *)0, (PkAddress)g_sbeSyncCommandProcessor_stack, SBE_THREAD_SYNC_CMD_PROC_STACK_SIZE, THREAD_PRIORITY_7); if (l_rc) { break; } // Initialize Asynchronous Command Processor thread l_rc = createAndResumeThreadHelper(&g_sbeAsyncCommandProcessor_thread, sbeAsyncCommandProcessor_routine, (void *)0, (PkAddress)g_sbeAsyncCommandProcessor_stack, SBE_THREAD_ASYNC_CMD_PROC_STACK_SIZE, THREAD_PRIORITY_6); if (l_rc) { break; } } while (false); // If there are any errors initializing the threads if( l_rc ) { SBE_ERROR ("Error Initializing a thread, rc=[%d]", l_rc); } return l_rc; } //////////////////////////////////////////////////////////////// // @brief - main : SBE Application main //////////////////////////////////////////////////////////////// uint32_t main(int argc, char **argv) { #define SBE_FUNC "main " SBE_ENTER(SBE_FUNC); int l_rc = 0; // @TODO via RTC : 128818 // Explore on reclaiming the stack // used by this Initialization code do { // initializes kernel data - // stack, threads, timebase, timers, etc. l_rc = pk_initialize((PkAddress)g_sbe_Kernel_NCInt_stack, SBE_NONCRITICAL_STACK_SIZE, 0, 500000000); // @TODO via RTC : 128819 // Need to obtain at Runtime, a new attribute? if (l_rc) { break; } SBE_DEBUG("Completed PK init"); // Initialize the semaphores l_rc = sbeInitSems(); if (l_rc) { break; } // Initialize SBE control loop threads l_rc = sbeInitThreads(); if (l_rc) { break; } // Setup SBE PPE IRQs l_rc = sbeIRQSetup(); if (l_rc) { break; } // TODO via RTC 126146. // Check if we should call plat_TargetsInit in some other thread. // We may want to keep only PK init in main and can move // plat init to some other thread. Only if this is required by more // than one thread and there can be some race condition, we will // keep it here before starting other threads. fapi2::ReturnCode fapiRc = fapi2::plat_TargetsInit(); if( fapiRc != fapi2::FAPI2_RC_SUCCESS ) { SBE_ERROR(SBE_FUNC"plat_TargetsInit failed"); // TODO via RTC 126146. // Set the state to Failure and remove break statement. It will // enable FSP to get FFDC for this failure. break; } if(SbeRegAccess::theSbeRegAccess().init()) { SBE_ERROR(SBE_FUNC"Failed to initialize SbeRegAccess"); // init failure could mean the below will fail too, but attempt it // anyway (void)SbeRegAccess::theSbeRegAccess().updateSbeState(SBE_STATE_DUMP); // TODO: via RTC 126146 : Decide if we should really break here or // continue in the failed state. break; } // Start running the highest priority thread. // This function never returns pk_start_threads(); } while (false); return l_rc; }