/////////////////////////////////////////////////////////////////////////////////// // File : xcu_driver.c // Date : 23/05/2013 // Author : alain greiner // Copyright (c) UPMC-LIP6 /////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #if !defined(X_SIZE) # error: You must define X_SIZE in the hard_config.h file #endif #if !defined(Y_SIZE) # error: You must define X_SIZE in the hard_config.h file #endif #if !defined(X_WIDTH) # error: You must define X_WIDTH in the hard_config.h file #endif #if !defined(Y_WIDTH) # error: You must define X_WIDTH in the hard_config.h file #endif #if !defined(NB_PROCS_MAX) # error: You must define NB_PROCS_MAX in the hard_config.h file #endif #if !defined( USE_XICU ) # error: You must define USE_XICU in the hard_config.h file #endif //////////////////////////////////////////////////////////////////////////////// // This function set the mask register for the IRQ type defined by "irq_type", // and for the channel identified by the "cluster_xy" and "channel" arguments. // All '1' bits are set / all '0' bits are not modified. //////////////////////////////////////////////////////////////////////////////// void _xcu_set_mask( unsigned int cluster_xy, unsigned int channel, unsigned int value, unsigned int irq_type ) { #if USE_XICU // parameters checking unsigned int x = cluster_xy >> Y_WIDTH; unsigned int y = cluster_xy & ((1<= X_SIZE) _exit(); if (y >= Y_SIZE) _exit(); if (channel >= (NB_PROCS_MAX * IRQ_PER_PROCESSOR)) _exit(); volatile unsigned int* xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base + (cluster_xy * (unsigned int)&vseg_cluster_increment)); unsigned int func; if (irq_type == IRQ_TYPE_PTI) func = XICU_MSK_PTI_ENABLE; else if (irq_type == IRQ_TYPE_WTI) func = XICU_MSK_WTI_ENABLE; else if (irq_type == IRQ_TYPE_HWI) func = XICU_MSK_HWI_ENABLE; else { _printf("[GIET ERROR] _xcu_set_mask() receives illegal IRQ type\n"); _exit(); } xcu_address[XICU_REG(func,channel)] = value; #else _printf("[GIET ERROR] _xcu_set_mask() should not be used if USE_XICU not set\n"); _exit(); #endif } //////////////////////////////////////////////////////////////////////////////// // This function returns the index and the type of the highest priority // - active PTI (Timer Interrupt), then // - active HWI (Hardware Interrupt), then // - active WTI (Software Interrupt) // As the hardware can define more than one IRQ per processor, but the GIET // use only one, channel = lpid * IRQ_PER_PROCESSOR. //////////////////////////////////////////////////////////////////////////////// void _xcu_get_index( unsigned int cluster_xy, unsigned int channel, unsigned int * index, unsigned int * irq_type ) { #if USE_XICU // parameters checking unsigned int x = cluster_xy >> Y_WIDTH; unsigned int y = cluster_xy & ((1<= X_SIZE) _exit(); if (y >= Y_SIZE) _exit(); if (channel >= (NB_PROCS_MAX * IRQ_PER_PROCESSOR)) _exit(); volatile unsigned int* xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base + (cluster_xy * (unsigned int)&vseg_cluster_increment)); unsigned int prio = xcu_address[XICU_REG(XICU_PRIO,channel)]; unsigned int pti_ok = (prio & 0x00000001); unsigned int hwi_ok = (prio & 0x00000002); unsigned int wti_ok = (prio & 0x00000004); unsigned int pti_id = (prio & 0x00001F00) >> 8; unsigned int hwi_id = (prio & 0x001F0000) >> 16; unsigned int wti_id = (prio & 0x1F000000) >> 24; if (pti_ok) { *index = pti_id; *irq_type = IRQ_TYPE_PTI; } else if (hwi_ok) { *index = hwi_id; *irq_type = IRQ_TYPE_HWI; } else if (wti_ok) { *index = wti_id; *irq_type = IRQ_TYPE_WTI; } else { *index = 32; } #else _printf("[GIET ERROR] _xcu_get_index should not be used if USE_XICU is not set\n"); _exit(); #endif } //////////////////////////////////////////////////////////////////////////////// // This function writes the "wdata" value in the mailbox defined // by the "cluster_xy" and "wti_index" arguments. //////////////////////////////////////////////////////////////////////////////// void _xcu_send_wti( unsigned int cluster_xy, unsigned int wti_index, unsigned int wdata ) { #if USE_XICU // parameters checking unsigned int x = cluster_xy >> Y_WIDTH; unsigned int y = cluster_xy & ((1<= X_SIZE) _exit(); if (y >= Y_SIZE) _exit(); if (wti_index >= 32) _exit(); volatile unsigned int* xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base + (cluster_xy * (unsigned int)&vseg_cluster_increment)); xcu_address[XICU_REG(XICU_WTI_REG,wti_index)] = wdata; #else _printf("[GIET ERROR] _xcu_send_ipi should not be used if USE_XICU is not set\n"); _exit(); #endif } //////////////////////////////////////////////////////////////////////////////// // This function returns the value contained in a WTI mailbox defined by // the cluster_xy and "wti_index" arguments. This value is written in // the "value" argument, and the corresponding WTI is acknowledged. // returns 0 if success, > 0 if error. //////////////////////////////////////////////////////////////////////////////// void _xcu_get_wti_value( unsigned int cluster_xy, unsigned int wti_index, unsigned int * value ) { #if USE_XICU // parameters checking unsigned int x = cluster_xy >> Y_WIDTH; unsigned int y = cluster_xy & ((1<= X_SIZE) _exit(); if (y >= Y_SIZE) _exit(); if (wti_index >= 32) _exit(); volatile unsigned int* xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base + (cluster_xy * (unsigned int)&vseg_cluster_increment)); *value = xcu_address[XICU_REG(XICU_WTI_REG, wti_index)]; #else _printf("[GIET ERROR] in _xcu_get_wti_value() USE_XICU is not set\n"); _exit(); #endif } //////////////////////////////////////////////////////////////////////////////// // This function returns the address of a WTI mailbox defined by // the "wti_index" argument, in the unsigned int "address" argument. // It is used by the GIET to configurate the IOPIC component. // There is no access to a specific XCU component in a specific cluster. // returns 0 if success, > 0 if error. //////////////////////////////////////////////////////////////////////////////// void _xcu_get_wti_address( unsigned int wti_index, unsigned int * address ) { #if USE_XICU if (wti_index >= 32) _exit(); unsigned int xcu_address = (unsigned int)&seg_xcu_base; *address = xcu_address + (XICU_REG(XICU_WTI_REG, wti_index)<<2); #else _printf("[GIET ERROR] in _xcu_get_wti_address() USE_XICU is not set\n"); _exit(); #endif } //////////////////////////////////////////////////////////////////////////////// // This function activates a timer contained in XICU by writing in the // proper register the period value. //////////////////////////////////////////////////////////////////////////////// void _xcu_timer_start( unsigned int cluster_xy, unsigned int pti_index, unsigned int period ) { #if USE_XICU // parameters checking unsigned int x = cluster_xy >> Y_WIDTH; unsigned int y = cluster_xy & ((1<= X_SIZE) _exit(); if (y >= Y_SIZE) _exit(); volatile unsigned int* xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base + (cluster_xy * (unsigned int)&vseg_cluster_increment)); xcu_address[XICU_REG(XICU_PTI_PER, pti_index)] = period; #else _printf("[GIET ERROR] in _xcu_timer_start() USE_XICU is not set\n"); _exit(); #endif } ////////////////////////////////////////////////////////////////////////////// // This function desactivates a timer in XICU component // by writing in the proper register. ////////////////////////////////////////////////////////////////////////////// void _xcu_timer_stop( unsigned int cluster_xy, unsigned int pti_index) { #if USE_XICU // parameters checking unsigned int x = cluster_xy >> Y_WIDTH; unsigned int y = cluster_xy & ((1<= X_SIZE) _exit(); if (y >= Y_SIZE) _exit(); volatile unsigned int * xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base + (cluster_xy * (unsigned int)&vseg_cluster_increment)); xcu_address[XICU_REG(XICU_PTI_PER, pti_index)] = 0; #else _printf("[GIET ERROR] in _xcu_timer_stop() USE_XICU is not set\n"); _exit(); #endif } ////////////////////////////////////////////////////////////////////////////// // This function acknowlegge a timer interrupt in XICU // component by reading 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. ////////////////////////////////////////////////////////////////////////////// void _xcu_timer_reset_irq( unsigned int cluster_xy, unsigned int pti_index ) { #if USE_XICU // parameters checking unsigned int x = cluster_xy >> Y_WIDTH; unsigned int y = cluster_xy & ((1<= X_SIZE) _exit(); if (y >= Y_SIZE) _exit(); volatile unsigned int * xcu_address = (unsigned int *) ((unsigned int)&seg_xcu_base + (cluster_xy * (unsigned int)&vseg_cluster_increment)); xcu_address[XICU_REG(XICU_PTI_ACK, pti_index)]; #else _printf("[GIET ERROR] in _xcu_timer_reset_irq() USE_XICU is not set\n"); _exit(); #endif } ////////////////////////////////////////////////////////////////////////////// // This function resets a 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) ///////////////////////////////////////////////////////////////////////////// void _xcu_timer_reset_cpt( unsigned int cluster_xy, unsigned int pti_index ) { #if USE_XICU // parameters checking unsigned int x = cluster_xy >> Y_WIDTH; unsigned int y = cluster_xy & ((1<= X_SIZE) _exit(); if (y >= Y_SIZE) _exit(); volatile unsigned int * xcu_address = (unsigned int *) ((unsigned int) &seg_xcu_base + (cluster_xy * (unsigned int)&vseg_cluster_increment)); unsigned int period = xcu_address[XICU_REG(XICU_PTI_PER, pti_index)]; // we write 0 first because if the timer is currently running, // the corresponding timer counter is not reset xcu_address[XICU_REG(XICU_PTI_PER, pti_index)] = 0; xcu_address[XICU_REG(XICU_PTI_PER, pti_index)] = period; #else _printf("[GIET ERROR] in _xcu_timer_reset_cpt() USE_XICU is not set\n"); _exit(); #endif } // 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