Changeset 437 for soft/giet_vm/giet_drivers/tim_driver.c
- Timestamp:
- Nov 3, 2014, 10:53:00 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
soft/giet_vm/giet_drivers/tim_driver.c
r426 r437 1 1 ////////////////////////////////////////////////////////////////////////////////////// 2 // File : tim er_driver.c2 // File : tim_driver.c 3 3 // Date : 23/05/2013 4 4 // Author : alain greiner 5 5 // Copyright (c) UPMC-LIP6 6 6 ////////////////////////////////////////////////////////////////////////////////////// 7 // The timer_driver.c and timer_driver.h files are part ot the GIET-VM nano-kernel.8 // This driver supports the SoCLib vci_multi_timer component.9 //10 // It can exist several multi_timers in the architecture (at most one per cluster),11 // and each one can contain several timers (called channels).12 //13 // There is two types of timers:14 // - "system" timers : one per processor, used for context switch.15 // local_id in [0, NB_PROCS_MAX-1],16 // - "user" timers : requested by the task in the mapping_info data structure.17 // For each user timer, the timer_id is stored in the context of the task.18 // The global index is cluster_xy * (NB_PROCS_MAX + NB_TIM_CHANNELS) + local_id19 //20 // The NB_PROCS_MAX and NB_TIM_CHANNELS values must be defined in hard_config.h file.21 //22 // The virtual base address of the segment associated to a channel is:23 // SEG_TIM_BASE + cluster_xy * PERI_CLUSTER_INCREMENT + TIMER_SPAN * timer_id24 //25 // The SEG_TIM_BASE and PERI_CLUSTER_INCREMENT must be defined in hard_config.h.26 /////////////////////////////////////////////////////////////////////////////////////27 7 28 8 #include <giet_config.h> 9 #include <hard_config.h> 29 10 #include <tim_driver.h> 30 #include <xcu_driver.h>31 #include <tty_driver.h>32 11 #include <utils.h> 33 12 … … 68 47 #endif 69 48 70 /////////////////// Timer global variables //////////////////////////////////////// 49 ///////////////////////////////////////////////////////////////////////////////// 50 // global variables 51 ///////////////////////////////////////////////////////////////////////////////// 71 52 72 53 #define in_unckdata __attribute__((section (".unckdata"))) 73 54 74 55 #if (NB_TIM_CHANNELS > 0) 75 in_unckdata volatile unsigned char _user_timer_event[ (1<<X_WIDTH)*(1<<Y_WIDTH)*NB_TIM_CHANNELS]76 = { [0 ... (( (1<<X_WIDTH)*(1<<Y_WIDTH)*NB_TIM_CHANNELS) - 1)] = 0 };56 in_unckdata volatile unsigned char _user_timer_event[NB_TIM_CHANNELS] 57 = { [0 ... ((1<<NB_TIM_CHANNELS) - 1)] = 0 }; 77 58 #endif 78 59 79 //////////////////////////////////////////////////////////////////////////////////// 80 // This function activates a timer in the vci_timer component 81 // by writing in the proper register the period value. 82 // It can be used by both the kernel to initialise a "system" timer, 83 // or by a task (through a system call) to configure an "user" timer. 84 /////////////////////////////////////////////////////////////////////////////////// 85 void _timer_start( unsigned int cluster_xy, 86 unsigned int local_id, 87 unsigned int period) 60 ///////////////////////////////////////////////////////////////////////////////// 61 // access functions 62 ///////////////////////////////////////////////////////////////////////////////// 63 64 ////////////////////////////////////////////////////////////// 65 unsigned int _timer_get_register( unsigned int channel, 66 unsigned int index ) 67 { 68 unsigned int* vaddr = (unsigned int*)SEG_TIM_BASE + channel*TIMER_SPAN + index; 69 return _io_extended_read( vaddr ); 70 } 71 72 ////////////////////////////////////////////////////// 73 void _timer_set_register( unsigned int channel, 74 unsigned int index, 75 unsigned int value ) 76 { 77 unsigned int* vaddr = (unsigned int*)SEG_TIM_BASE + channel*TIMER_SPAN + index; 78 _io_extended_write( vaddr, value ); 79 } 80 81 /////////////////////////////////////// 82 int _timer_start( unsigned int channel, 83 unsigned int period ) 88 84 { 89 85 #if NB_TIM_CHANNELS 90 86 91 // parameters checking 92 unsigned int x = cluster_xy >> Y_WIDTH; 93 unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1); 94 if ( (x >= X_SIZE) || (y >= Y_SIZE) || (local_id >= NB_TIM_CHANNELS) ) 87 if ( channel >= NB_TIM_CHANNELS ) 95 88 { 96 _p rintf("[GIET ERROR] in _timer_start()\n");97 _exit();89 _puts("[GIET ERROR] in _timer_start()\n"); 90 return -1; 98 91 } 99 92 100 unsigned int* timer_address = (unsigned int *) ( SEG_TIM_BASE + 101 (cluster_xy * PERI_CLUSTER_INCREMENT) ); 102 103 timer_address[local_id * TIMER_SPAN + TIMER_PERIOD] = period; 104 timer_address[local_id * TIMER_SPAN + TIMER_MODE] = 0x3; 93 _timer_set_register( channel, TIMER_PERIOD, period ); 94 _timer_set_register( channel, TIMER_MODE , 0x3 ); 95 96 return 0; 105 97 106 98 #else 107 _printf("[GIET ERROR] _timer_start() should not be called when NB_TIM_CHANNELS is 0\n"); 108 _exit(); 99 100 _puts("[GIET ERROR] _timer_start() should not be called when NB_TIM_CHANNELS is 0\n"); 101 return -1; 102 109 103 #endif 110 104 } 111 105 112 ////////////////////////////////////////////////////////////////////////////// 113 // This function desactivates a timer in the vci_timer component 114 // by writing in the proper register. 115 // Returns 0 if success, > 0 if error. 116 ////////////////////////////////////////////////////////////////////////////// 117 void _timer_stop( unsigned int cluster_xy, 118 unsigned int local_id) 106 /////////////////////////////////////// 107 int _timer_stop( unsigned int channel ) 119 108 { 120 109 #if NB_TIM_CHANNELS 121 110 122 // parameters checking 123 unsigned int x = cluster_xy >> Y_WIDTH; 124 unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1); 125 if ( (x >= X_SIZE) || (y >= Y_SIZE) || (local_id >= NB_TIM_CHANNELS) ) 111 if ( channel >= NB_TIM_CHANNELS ) 126 112 { 127 _p rintf("[GIET ERROR] in _timer_stop()\n");128 _exit();113 _puts("[GIET ERROR] in _timer_stop()\n"); 114 return -1; 129 115 } 130 116 131 unsigned int* timer_address = (unsigned int *) ( SEG_TIM_BASE + 132 (cluster_xy * PERI_CLUSTER_INCREMENT) ); 117 _timer_set_register( channel, TIMER_MODE , 0 ); 133 118 134 timer_address[local_id * TIMER_SPAN + TIMER_MODE] =0;119 return 0; 135 120 136 121 #else 137 _printf("[GIET ERROR] _timer_stop() should not be called when NB_TIM_CHANNELS is 0\n"); 138 _exit(); 122 123 _puts("[GIET ERROR] _timer_stop() should not be called when NB_TIM_CHANNELS is 0\n"); 124 return -1; 125 139 126 #endif 140 127 } 141 128 142 ////////////////////////////////////////////////////////////////////////////// 143 // This function acknowlegge a timer interrupt in the vci_timer 144 // component by writing in the proper register. 145 // It can be used by both the isr_switch() for a "system" timer, 146 // or by the _isr_timer() for an "user" timer. 147 // Returns 0 if success, > 0 if error. 148 ////////////////////////////////////////////////////////////////////////////// 149 void _timer_reset_irq( unsigned int cluster_xy, 150 unsigned int local_id ) 129 //////////////////////////////////////////// 130 int _timer_reset_cpt( unsigned int channel ) 151 131 { 152 132 #if NB_TIM_CHANNELS 153 133 154 // parameters checking 155 unsigned int x = cluster_xy >> Y_WIDTH; 156 unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1); 157 if ( (x >= X_SIZE) || (y >= Y_SIZE) || (local_id >= NB_TIM_CHANNELS) ) 134 if ( channel >= NB_TIM_CHANNELS ) 158 135 { 159 _p rintf("[GIET ERROR] in _timer_reset_irq()\n");160 _exit();136 _puts("[GIET ERROR in _timer_reset_cpt()\n"); 137 return -1; 161 138 } 162 139 163 unsigned int * timer_address = (unsigned int *) ( SEG_TIM_BASE +164 (cluster_xy * PERI_CLUSTER_INCREMENT));140 unsigned int period = _timer_get_register( channel, TIMER_PERIOD ); 141 _timer_set_register( channel, TIMER_PERIOD, period ); 165 142 166 timer_address[local_id * TIMER_SPAN + TIMER_RESETIRQ] =0;143 return 0; 167 144 168 145 #else 169 _printf("[GIET ERROR] _timer_reset_irq() should not be called when NB_TIM_CHANNELS is 0\n"); 170 _exit(); 146 147 _puts("[GIET ERROR] _timer_reset_cpt should not be called when NB_TIM_CHANNELS is 0\n"); 148 return -1; 149 171 150 #endif 172 151 } 173 152 174 ///////////////////////////////////////////////////////////////////////////// 175 // This function resets the timer counter. To do so, we re-write the period 176 // in the proper register, what causes the count to restart. 177 // The period value is read from the same (TIMER_PERIOD) register, 178 // this is why in appearance we do nothing useful (read a value 179 // from a register and write this value in the same register) 180 // This function is called during a context switch (user or preemptive) 181 //////////////////////////////////////////////////////////////////////i////// 182 void _timer_reset_cpt( unsigned int cluster_xy, 183 unsigned int local_id) 184 { 185 #if NB_TIM_CHANNELS 186 187 // parameters checking 188 unsigned int x = cluster_xy >> Y_WIDTH; 189 unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1); 190 if ( (x >= X_SIZE) || (y >= Y_SIZE) || (local_id >= NB_TIM_CHANNELS) ) 191 { 192 _printf("[GIET ERROR in _timer_reset_cpt()\n"); 193 _exit(); 194 } 195 196 // We suppose that the TIMER_MODE register value is 0x3 197 unsigned int* timer_address = (unsigned int *) ( SEG_TIM_BASE + 198 (cluster_xy * PERI_CLUSTER_INCREMENT) ); 199 200 unsigned int period = timer_address[local_id * TIMER_SPAN + TIMER_PERIOD]; 201 timer_address[local_id * TIMER_SPAN + TIMER_PERIOD] = period; 202 203 #else 204 _printf("[GIET ERROR] _timer_reset_cpt should not be called when NB_TIM_CHANNELS is 0\n"); 205 _exit(); 206 #endif 207 } 208 209 /////////////////////////////////////////////////////////////////////////////////// 210 // This ISR handles the IRQs generated by the "user" timers that are 211 // replicated in all clusters. 212 // The IRQs generated by the "system" timers should be handled by _isr_switch(). 213 // It can be a HWI or a PTI. 214 // The channel argument is the user timer local index. 215 // timer_global_id = cluster_id*(NB_TIM_CHANNELS) + channel 216 // The ISR acknowledges the IRQ and registers the event in the proper entry 217 // of the _user_timer_event[] array, and a log message is displayed on TTY0. 218 /////////////////////////////////////////////////////////////////////////////////// 153 /////////////////////////////////////// 219 154 void _timer_isr( unsigned int irq_type, // HWI / PTI 220 155 unsigned int irq_id, // index returned by XCU … … 223 158 #if NB_TIM_CHANNELS 224 159 225 unsigned int cluster_xy = _get_procid() >> P_WIDTH; 226 227 // acknowledge IRQ depending on type 228 if ( irq_type == IRQ_TYPE_HWI ) _timer_reset_irq( cluster_xy, channel ); 229 else _xcu_timer_reset_irq( cluster_xy, irq_id ); 160 // acknowledge IRQ 161 _timer_set_register( channel, TIMER_RESETIRQ, 0 ); 230 162 231 163 // register the event 232 _user_timer_event[c luster_xy * NB_TIM_CHANNELS + channel] = 1;164 _user_timer_event[channel] = 1; 233 165 234 166 // display a message on TTY 0 235 _p rintf("\n[GIET WARNING] User Timer IRQ at cycle %d / cluster = %x /channel = %d\n",236 _get_proctime(), c luster_xy, channel );167 _puts("\n[GIET WARNING] User Timer IRQ at cycle %d for channel = %d\n", 168 _get_proctime(), channel ); 237 169 238 170 #else 239 _printf("[GIET ERROR] _timer_isr() should not be called when NB_TIM_CHANNELS == 0\n"); 171 172 _puts("[GIET ERROR] _timer_isr() should not be called when NB_TIM_CHANNELS == 0\n"); 240 173 _exit(); 174 241 175 #endif 242 176 }
Note: See TracChangeset
for help on using the changeset viewer.