00001 00019 /* 00020 * INCLUDE FILES 00021 **************************************************************************************** 00022 */ 00023 // standard includes 00024 #include "co_int.h" 00025 #include "co_bool.h" 00026 00027 #include "mm_timer.h" 00028 #include "ke_event.h" 00029 #include "hal_machw.h" 00030 #include "reg_mac_core.h" 00031 #include "ke_timer.h" 00032 00033 #if NX_MM_TIMER 00034 /* 00035 * DEFINES 00036 **************************************************************************************** 00037 */ 00038 00039 00040 /* 00041 * GLOBAL VARIABLES 00042 **************************************************************************************** 00043 */ 00045 struct mm_timer_env_tag mm_timer_env; 00046 00047 /* 00048 * FUNCTION PROTOTYPES 00049 **************************************************************************************** 00050 */ 00051 void mm_timer_init(void) 00052 { 00053 // Initialize the list of programmed timers 00054 co_list_init(&mm_timer_env.prog); 00055 } 00056 00057 00065 static void mm_timer_hw_set(struct mm_timer_tag *timer) 00066 { 00067 GLOBAL_INT_DISABLE(); 00068 if (timer) 00069 { 00070 uint32_t timer_msk; 00071 00072 // set the abs timeout in HW 00073 nxmac_abs_timer_set(HAL_MM_TIMER, timer->time); 00074 00075 // enable timer irq 00076 timer_msk = nxmac_timers_int_un_mask_get(); 00077 if (!(timer_msk & HAL_MM_TIMER_BIT)) 00078 { 00079 // if timer is not enabled, it is possible that the irq is raised 00080 // due to a spurious value, so ack it before 00081 nxmac_timers_int_event_clear(HAL_MM_TIMER_BIT); 00082 nxmac_timers_int_un_mask_set(timer_msk | HAL_MM_TIMER_BIT); 00083 } 00084 } 00085 else 00086 { 00087 // disable timer irq 00088 nxmac_timers_int_un_mask_set(nxmac_timers_int_un_mask_get() & ~HAL_MM_TIMER_BIT); 00089 } 00090 GLOBAL_INT_RESTORE(); 00091 } 00092 00103 static bool cmp_abs_time(struct co_list_hdr const * timerA, struct co_list_hdr const * timerB) 00104 { 00105 uint32_t timeA = ((struct mm_timer_tag*)timerA)->time; 00106 uint32_t timeB = ((struct mm_timer_tag*)timerB)->time; 00107 00108 return (hal_machw_time_cmp(timeA, timeB)); 00109 } 00110 00111 void mm_timer_set(struct mm_timer_tag *timer, uint32_t value) 00112 { 00113 bool hw_prog = false; 00114 00115 // Sanity check - Timeout value should not be in the past 00116 ASSERT_ERR(!hal_machw_time_past(value)); 00117 00118 // check if timer is already present in the list 00119 if (co_list_pick(&mm_timer_env.prog) == (struct co_list_hdr*) timer) 00120 { 00121 // pop the timer from the list 00122 co_list_pop_front(&mm_timer_env.prog); 00123 // force the HW timer to be reprogrammed 00124 hw_prog = true; 00125 } 00126 else 00127 { 00128 // extract the timer from the list 00129 co_list_extract(&mm_timer_env.prog, &timer->list_hdr); 00130 } 00131 00132 // update characteristics 00133 timer->time = value; 00134 00135 // insert in sorted timer list 00136 co_list_insert(&mm_timer_env.prog, 00137 (struct co_list_hdr*) timer, 00138 cmp_abs_time); 00139 00140 // check if HW timer set needed 00141 if (hw_prog || (co_list_pick(&mm_timer_env.prog) == (struct co_list_hdr*) timer)) 00142 { 00143 mm_timer_hw_set((struct mm_timer_tag *)co_list_pick(&mm_timer_env.prog)); 00144 } 00145 00146 // Check that the timer did not expire before HW prog 00147 if (hal_machw_time_past(value)) 00148 { 00149 // Timer already expired, so schedule the timer event immediately 00150 ke_evt_set(KE_EVT_MM_TIMER_BIT); 00151 } 00152 } 00153 00154 00155 void mm_timer_clear(struct mm_timer_tag *timer) 00156 { 00157 // Check if timer is first of the list 00158 if (co_list_pick(&mm_timer_env.prog) == (struct co_list_hdr*) timer) 00159 { 00160 // Pop it 00161 co_list_pop_front(&mm_timer_env.prog); 00162 00163 // And reprogram the HW timer 00164 mm_timer_hw_set((struct mm_timer_tag *)co_list_pick(&mm_timer_env.prog)); 00165 } 00166 else 00167 // Extract the timer from the list 00168 co_list_extract(&mm_timer_env.prog, &timer->list_hdr); 00169 } 00170 00183 void mm_timer_schedule(int dummy) 00184 { 00185 struct mm_timer_tag *timer; 00186 00187 for(;;) 00188 { 00189 ke_evt_clear(KE_EVT_MM_TIMER_BIT); 00190 00191 // check the next timer 00192 timer = (struct mm_timer_tag *)co_list_pick(&mm_timer_env.prog); 00193 if (!timer) 00194 { 00195 // no more timers, disable HW irq and leave 00196 mm_timer_hw_set(NULL); 00197 break; 00198 } 00199 00200 if (!hal_machw_time_past(timer->time - 50)) 00201 { 00202 // timer will expire in more than 32us, configure the HW 00203 mm_timer_hw_set(timer); 00204 00205 // in most case, we will break here. However, if the timer expiration 00206 // time has just passed, may be the HW was set too late (due to an IRQ) 00207 // so we do not exit the loop to process it. 00208 if (!hal_machw_time_past(timer->time)) 00209 { 00210 break; 00211 } 00212 } 00213 00214 // at this point, the next timer in the queue has expired or is about to -> pop it 00215 co_list_pop_front(&mm_timer_env.prog); 00216 00217 // Sanity check 00218 ASSERT_ERR(timer->cb); 00219 00220 // notify the caller - It has to be done after popping the timer from the queue 00221 // as the callback may set it again 00222 timer->cb(timer->env); 00223 } 00224 } 00225 00226 #endif 00227 00229
1.6.1