| [294] | 1 | ////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [258] | 2 | // File     : ctx_handler.c | 
|---|
|  | 3 | // Date     : 01/04/2012 | 
|---|
|  | 4 | // Authors  : alain greiner & joel porquet | 
|---|
|  | 5 | // Copyright (c) UPMC-LIP6 | 
|---|
| [294] | 6 | ////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [258] | 7 |  | 
|---|
|  | 8 | #include <giet_config.h> | 
|---|
|  | 9 | #include <tim_driver.h> | 
|---|
|  | 10 | #include <xcu_driver.h> | 
|---|
|  | 11 | #include <tty_driver.h> | 
|---|
|  | 12 | #include <utils.h> | 
|---|
|  | 13 | #include <ctx_handler.h> | 
|---|
|  | 14 | #include <mapping_info.h> | 
|---|
|  | 15 | #include <sys_handler.h> | 
|---|
|  | 16 |  | 
|---|
|  | 17 | extern void _task_switch(unsigned int *, unsigned int *); | 
|---|
|  | 18 |  | 
|---|
|  | 19 | ///////////////////////////////////////////////////////////////////////////////// | 
|---|
|  | 20 | // This function performs a context switch between the running task | 
|---|
|  | 21 | // and  another task, using a round-robin sheduling policy between all | 
|---|
|  | 22 | // tasks allocated to a given processor (static allocation). | 
|---|
|  | 23 | // It selects the next runable task to resume execution. | 
|---|
|  | 24 | // If the only runable task is the current task, return without context switch. | 
|---|
|  | 25 | // If there is no runable task, the scheduler switch to the default "idle" task. | 
|---|
| [294] | 26 | ///////////////////////////////////////////////////////////////////////////////// | 
|---|
| [258] | 27 | // Implementation note | 
|---|
|  | 28 | // The return address contained in $31 is saved in the current task context | 
|---|
|  | 29 | // (in the ctx[31] slot), and the function actually returns to the address | 
|---|
|  | 30 | // contained in the ctx[31] slot of the next task context. | 
|---|
|  | 31 | ///////////////////////////////////////////////////////////////////////////////// | 
|---|
|  | 32 | void _ctx_switch() | 
|---|
|  | 33 | { | 
|---|
| [294] | 34 | unsigned int gpid       = _get_procid(); | 
|---|
|  | 35 | unsigned int cluster_xy = gpid / NB_PROCS_MAX; | 
|---|
|  | 36 | unsigned int lpid       = gpid % NB_PROCS_MAX; | 
|---|
|  | 37 |  | 
|---|
| [258] | 38 | // get scheduler address | 
|---|
|  | 39 | static_scheduler_t* psched = (static_scheduler_t*)_get_sched(); | 
|---|
|  | 40 |  | 
|---|
|  | 41 | // get number of tasks allocated to scheduler | 
|---|
|  | 42 | unsigned int tasks = psched->tasks; | 
|---|
|  | 43 |  | 
|---|
|  | 44 | // get current task index | 
|---|
|  | 45 | unsigned int curr_task_id = psched->current; | 
|---|
|  | 46 |  | 
|---|
|  | 47 | // select the next task using a round-robin policy | 
|---|
|  | 48 | unsigned int next_task_id; | 
|---|
|  | 49 | unsigned int tid; | 
|---|
|  | 50 | unsigned int found = 0; | 
|---|
|  | 51 |  | 
|---|
|  | 52 | for (tid = curr_task_id + 1; tid < curr_task_id + 1 + tasks; tid++) | 
|---|
|  | 53 | { | 
|---|
|  | 54 | next_task_id = tid % tasks; | 
|---|
|  | 55 | // test if the task is runable | 
|---|
|  | 56 | if ( psched->context[next_task_id][CTX_RUN_ID] ) | 
|---|
|  | 57 | { | 
|---|
|  | 58 | found = 1; | 
|---|
|  | 59 | break; | 
|---|
|  | 60 | } | 
|---|
|  | 61 | } | 
|---|
|  | 62 |  | 
|---|
|  | 63 | // launch "idle" task if no runable task | 
|---|
|  | 64 | if (found == 0) | 
|---|
|  | 65 | { | 
|---|
|  | 66 | next_task_id = IDLE_TASK_INDEX; | 
|---|
|  | 67 | } | 
|---|
|  | 68 |  | 
|---|
|  | 69 | #if GIET_DEBUG_SWITCH | 
|---|
| [294] | 70 | unsigned int x = cluster_xy >> Y_WIDTH; | 
|---|
|  | 71 | unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1); | 
|---|
|  | 72 |  | 
|---|
|  | 73 | _printf("\n[TASK SWITCH] (%d) -> (%d) on processor[%d,%d,%d] at cycle %d\n", | 
|---|
|  | 74 | curr_task_id, next_task_id, x, y , lpid, _get_proctime() ); | 
|---|
| [258] | 75 | #endif | 
|---|
|  | 76 |  | 
|---|
| [294] | 77 | if (curr_task_id != next_task_id)  // actual task switch required | 
|---|
|  | 78 | { | 
|---|
| [275] | 79 | unsigned int* curr_ctx_vaddr = &(psched->context[curr_task_id][0]); | 
|---|
|  | 80 | unsigned int* next_ctx_vaddr = &(psched->context[next_task_id][0]); | 
|---|
|  | 81 |  | 
|---|
| [330] | 82 | // reset timer counter. | 
|---|
|  | 83 | // In all clusters, the first NB_PROCS_MAX | 
|---|
|  | 84 | // timers are system timers (TICK) | 
|---|
| [294] | 85 |  | 
|---|
| [322] | 86 | #if USE_XCU | 
|---|
| [294] | 87 | _xcu_timer_reset_cpt( cluster_xy, lpid ); | 
|---|
| [275] | 88 | #else | 
|---|
| [294] | 89 | _timer_reset_cpt( cluster_xy, lpid); | 
|---|
| [275] | 90 | #endif | 
|---|
|  | 91 |  | 
|---|
|  | 92 | // set current task index | 
|---|
|  | 93 | psched->current = next_task_id; | 
|---|
|  | 94 |  | 
|---|
|  | 95 | // makes context switch | 
|---|
|  | 96 | _task_switch(curr_ctx_vaddr, next_ctx_vaddr); | 
|---|
| [258] | 97 | } | 
|---|
|  | 98 | } //end _ctx_switch() | 
|---|
|  | 99 |  | 
|---|
|  | 100 | ///////////////////////////////////////////////////////////////////////////////////// | 
|---|
|  | 101 | // This function is executed as the"idle" task when no other task can be executed | 
|---|
|  | 102 | ///////////////////////////////////////////////////////////////////////////////////// | 
|---|
|  | 103 | void _idle_task() | 
|---|
|  | 104 | { | 
|---|
|  | 105 | while(1) | 
|---|
|  | 106 | { | 
|---|
| [294] | 107 | unsigned int count = GIET_IDLE_TASK_PERIOD; | 
|---|
| [275] | 108 |  | 
|---|
| [294] | 109 | // decounting loop | 
|---|
| [258] | 110 | asm volatile( | 
|---|
|  | 111 | "move   $3,   %0              \n" | 
|---|
|  | 112 | "_idle_task_loop:             \n" | 
|---|
|  | 113 | "addi   $3,   $3,   -1        \n" | 
|---|
|  | 114 | "bnez   $3,   _idle_task_loop \n" | 
|---|
|  | 115 | "nop                          \n" | 
|---|
|  | 116 | : | 
|---|
|  | 117 | : "r"(count) | 
|---|
|  | 118 | : "$3" ); | 
|---|
|  | 119 |  | 
|---|
| [294] | 120 | // warning message | 
|---|
|  | 121 | unsigned int gpid       = _get_procid(); | 
|---|
|  | 122 | unsigned int cluster_xy = gpid / NB_PROCS_MAX; | 
|---|
|  | 123 | unsigned int lpid       = gpid % NB_PROCS_MAX; | 
|---|
|  | 124 | unsigned int x          = cluster_xy >> Y_WIDTH; | 
|---|
|  | 125 | unsigned int y          = cluster_xy & ((1<<Y_WIDTH)-1); | 
|---|
|  | 126 |  | 
|---|
|  | 127 | _printf("\n[GIET WARNING] Processor[%d,%d,%d] still idle at cycle %d\n", | 
|---|
|  | 128 | x, y, lpid, _get_proctime() ); | 
|---|
|  | 129 |  | 
|---|
| [258] | 130 | } | 
|---|
|  | 131 | } // end ctx_idle() | 
|---|
|  | 132 |  | 
|---|
|  | 133 |  | 
|---|
|  | 134 | ///////////////////////////////////////////////////////////////////////////////// | 
|---|
| [294] | 135 | // The address of this function is used to initialise the return address | 
|---|
| [258] | 136 | // in the "idle" task context. | 
|---|
|  | 137 | ///////////////////////////////////////////////////////////////////////////////// | 
|---|
|  | 138 | void _ctx_eret() | 
|---|
|  | 139 | { | 
|---|
|  | 140 | asm volatile("eret"); | 
|---|
|  | 141 | } | 
|---|
|  | 142 |  | 
|---|
|  | 143 |  | 
|---|
|  | 144 | // Local Variables: | 
|---|
|  | 145 | // tab-width: 4 | 
|---|
|  | 146 | // c-basic-offset: 4 | 
|---|
|  | 147 | // c-file-offsets:((innamespace . 0)(inline-open . 0)) | 
|---|
|  | 148 | // indent-tabs-mode: nil | 
|---|
|  | 149 | // End: | 
|---|
|  | 150 | // vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4 | 
|---|
|  | 151 |  | 
|---|