////////////////////////////////////////////////////////////////////////////////////// // File : timer_driver.c // Date : 23/05/2013 // Author : alain greiner // Copyright (c) UPMC-LIP6 ////////////////////////////////////////////////////////////////////////////////////// // The timer_driver.c and timer_driver.h files are part ot the GIET-VM nano-kernel. // This driver supports the SoCLib vci_multi_timer component. // // It can exist several multi_timers in the architecture (at most one per cluster), // and each one can contain several timers (called channels). // // There is two types of timers: // - "system" timers : one per processor, used for context switch. // local_id in [0, NB_PROCS_MAX-1], // - "user" timers : requested by the task in the mapping_info data structure. // For each user timer, the timer_id is stored in the context of the task. // The global index is cluster_id * (NB_PROCS_MAX + NB_TIM_CHANNELS) + local_id // // The NB_PROCS_MAX and NB_TIM_CHANNELS values must be defined in the // hard_config.h file. // // The register offsets must be defined in the hwr_mapping.h file. ///////////////////////////////////////////////////////////////////////////////////// // The virtual base address of the segment associated to a channel is: // // seg_tim_base + cluster_id * vseg_cluster_increment + TIMER_SPAN * timer_id // // The seg_tim_base and vseg_cluster_increment values must be defined // in the giet_vsegs.ld file. ///////////////////////////////////////////////////////////////////////////////////// #include #include #include #if !defined(NB_CLUSTERS) # error: You must define NB_CLUSTERS in the hard_config.h file #endif #if (NB_CLUSTERS > 256) # error: NB_CLUSTERS cannot be larger than 256! #endif #if !defined(NB_PROCS_MAX) # error: You must define NB_PROCS_MAX in the hard_config.h file #endif #if (NB_PROCS_MAX > 8) # error: NB_PROCS_MAX cannot be larger than 8! #endif #if !defined(NB_TIM_CHANNELS) #define NB_TIM_CHANNELS 0 #endif #if ( (NB_TIM_CHANNELS + NB_PROC_MAX) > 32 ) # error: NB_TIM_CHANNELS + NB_PROCS_MAX cannot be larger than 32 #endif #if !defined( USE_XICU ) # error: You must define USE_XICU in the hard_config.h file #endif /////////////////// Timer global variables //////////////////////////////////////// #define in_unckdata __attribute__((section (".unckdata"))) #if (NB_TIM_CHANNELS > 0) in_unckdata volatile unsigned char _user_timer_event[NB_CLUSTERS * NB_TIM_CHANNELS] = { [0 ... ((NB_CLUSTERS * NB_TIM_CHANNELS) - 1)] = 0 }; #endif //////////////////////////////////////////////////////////////////////////////////// // _timer_start() // This function activates a timer in the vci_timer component // by writing in the proper register the period value. // It can be used by both the kernel to initialise a "system" timer, // or by a task (through a system call) to configure an "user" timer. // Returns 0 if success, > 0 if error. ////////////////////////////////////////////////////////////////////////////// unsigned int _timer_start( unsigned int cluster_id, unsigned int local_id, unsigned int period) { // parameters checking if (cluster_id >= NB_CLUSTERS) return 1; if (local_id >= NB_TIM_CHANNELS) return 1; unsigned int* timer_address = (unsigned int *) ((unsigned int)&seg_tim_base + (cluster_id * (unsigned int)&vseg_cluster_increment)); timer_address[local_id * TIMER_SPAN + TIMER_PERIOD] = period; timer_address[local_id * TIMER_SPAN + TIMER_MODE] = 0x3; return 0; } ////////////////////////////////////////////////////////////////////////////// // _timer_stop() // This function desactivates a timer in the vci_timer component // by writing in the proper register. // Returns 0 if success, > 0 if error. ////////////////////////////////////////////////////////////////////////////// unsigned int _timer_stop( unsigned int cluster_id, unsigned int local_id) { // parameters checking if (cluster_id >= NB_CLUSTERS) return 1; if (local_id >= NB_TIM_CHANNELS) return 1; unsigned int* timer_address = (unsigned int *) ((unsigned int)&seg_tim_base + (cluster_id * (unsigned int)&vseg_cluster_increment)); timer_address[local_id * TIMER_SPAN + TIMER_MODE] = 0; return 0; } ////////////////////////////////////////////////////////////////////////////// // _timer_reset_irq() // This function acknowlegge a timer interrupt in the vci_timer // component by writing in the proper register. // It can be used by both the isr_switch() for a "system" timer, // or by the _isr_timer() for an "user" timer. // Returns 0 if success, > 0 if error. ////////////////////////////////////////////////////////////////////////////// unsigned int _timer_reset_irq( unsigned int cluster_id, unsigned int local_id ) { // parameters checking if (cluster_id >= NB_CLUSTERS) return 1; if (local_id >= NB_TIM_CHANNELS) return 1; unsigned int * timer_address = (unsigned int *) ((unsigned int)&seg_tim_base + (cluster_id * (unsigned int)&vseg_cluster_increment)); timer_address[local_id * TIMER_SPAN + TIMER_RESETIRQ] = 0; return 0; } ///////////////////////////////////////////////////////////////////////////// // _timer_reset_cpt() // This function resets the timer counter. To do so, we re-write the period // in the proper register, what causes the count to restart. // The period value is read from the same (TIMER_PERIOD) register, // this is why in appearance we do nothing useful (read a value // from a register and write this value in the same register) // This function is called during a context switch (user or preemptive) //////////////////////////////////////////////////////////////////////i////// unsigned int _timer_reset_cpt( unsigned int cluster_id, unsigned int local_id) { // parameters checking if (cluster_id >= NB_CLUSTERS) return 1; if (local_id >= NB_TIM_CHANNELS) return 1; // We suppose that the TIMER_MODE register value is 0x3 unsigned int * timer_address = (unsigned int *) ((unsigned int)&seg_tim_base + (cluster_id * (unsigned int)&vseg_cluster_increment)); unsigned int period = timer_address[local_id * TIMER_SPAN + TIMER_PERIOD]; timer_address[local_id * TIMER_SPAN + TIMER_PERIOD] = period; return 0; } // Local Variables: // tab-width: 4 // c-basic-offset: 4 // c-file-offsets:((innamespace . 0)(inline-open . 0)) // indent-tabs-mode: nil // End: // vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4