1 /* 2 * File : trap.c 3 * This file is part of RT-Thread RTOS 4 * COPYRIGHT (C) 2006, RT-Thread Development Team 5 * 6 * The license and distribution terms for this file may be 7 * found in the file LICENSE in this distribution or at 8 * http://openlab.rt-thread.com/license/LICENSE 9 * 10 * Change Logs: 11 * Date Author Notes 12 * 2006-08-23 Bernard first version 13 * 2011-12-17 nl1031 for MicroBlaze 14 * 15 */ 16 17 #include <rtthread.h> 18 #include "xparameters.h" 19 #include "xintc.h" 20 #include "xintc_i.h" 21 #include "xintc_l.h" 22 23 24 #define MAX_HANDLERS XPAR_INTC_MAX_NUM_INTR_INPUTS 25 extern XIntc int_ctl; /* The instance of the Interrupt Controller */ 26 27 28 extern rt_uint32_t rt_interrupt_nest; 29 30 rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread; 31 rt_uint32_t rt_thread_switch_interrupt_flag; 32 33 34 void rt_hw_interrupt_handler(int vector) 35 { 36 rt_kprintf("Unhandled interrupt %d occured!!!\n", vector); 37 } 38 39 /** 40 * This function will initialize hardware interrupt 41 */ 42 void rt_hw_interrupt_init() 43 { 44 rt_base_t index; 45 46 XIntc_Config *CfgPtr; 47 48 49 CfgPtr = &XIntc_ConfigTable[0]; 50 51 52 for (index = 0; index < MAX_HANDLERS; index ++) 53 { 54 CfgPtr->HandlerTable[index].Handler = (XInterruptHandler)rt_hw_interrupt_handler; 55 } 56 57 /* init interrupt nest, and context in thread sp */ 58 rt_interrupt_nest = 0; 59 rt_interrupt_from_thread = 0; 60 rt_interrupt_to_thread = 0; 61 rt_thread_switch_interrupt_flag = 0; 62 } 63 64 /** 65 * This function will mask a interrupt. 66 * @param vector the interrupt number 67 */ 68 void rt_hw_interrupt_mask(int vector) 69 { 70 /* disable interrupt */ 71 XIntc_Disable(&int_ctl,vector); 72 } 73 74 /** 75 * This function will un-mask a interrupt. 76 * @param vector the interrupt number 77 */ 78 void rt_hw_interrupt_umask(int vector) 79 { 80 XIntc_Enable(&int_ctl,vector); 81 } 82 83 /** 84 * This function will install a interrupt service routine to a interrupt. 85 * @param vector the interrupt number 86 * @param new_handler the interrupt service routine to be installed 87 * @param old_handler the old interrupt service routine 88 */ 89 void rt_hw_interrupt_install(int vector, rt_isr_handler_t new_handler, rt_isr_handler_t *old_handler) 90 { 91 XIntc_Config *CfgPtr; 92 93 CfgPtr = &XIntc_ConfigTable[0]; 94 95 if(vector >= 0 && vector < MAX_HANDLERS) 96 { 97 if (*old_handler != RT_NULL) *old_handler = (rt_isr_handler_t)CfgPtr->HandlerTable[vector].Handler; 98 if (new_handler != RT_NULL) CfgPtr->HandlerTable[vector].Handler = (XInterruptHandler)new_handler; 99 } 100 } 101 102 /*****************************************************************************/ 103 /** copy from XIntc_DeviceInterruptHandler in xintc_l.c nl1031 104 * 105 * This function is the primary interrupt handler for the driver. It must be 106 * connected to the interrupt source such that is called when an interrupt of 107 * the interrupt controller is active. It will resolve which interrupts are 108 * active and enabled and call the appropriate interrupt handler. It uses 109 * the AckBeforeService flag in the configuration data to determine when to 110 * acknowledge the interrupt. Highest priority interrupts are serviced first. 111 * The driver can be configured to service only the highest priority interrupt 112 * or all pending interrupts using the {XIntc_SetOptions()} function or 113 * the {XIntc_SetIntrSrvOption()} function. 114 * 115 * This function assumes that an interrupt vector table has been previously 116 * initialized. It does not verify that entries in the table are valid before 117 * calling an interrupt handler. 118 * 119 * 120 * @return None. 121 * 122 * @note 123 * 124 * The constant XPAR_INTC_MAX_NUM_INTR_INPUTS must be setup for this to compile. 125 * Interrupt IDs range from 0 - 31 and correspond to the interrupt input signals 126 * for the interrupt controller. XPAR_INTC_MAX_NUM_INTR_INPUTS specifies the 127 * highest numbered interrupt input signal that is used. 128 * 129 ******************************************************************************/ 130 131 132 void rt_hw_trap_irq(void ) 133 { 134 u32 intr_status; 135 u32 intr_mask = 1; 136 int intr_number; 137 volatile u32 reg; /* used as bit bucket */ 138 XIntc_Config *cfg_ptr; 139 140 141 /* Get the configuration data using the device ID */ 142 cfg_ptr = &XIntc_ConfigTable[0]; 143 144 /* Get the interrupts that are waiting to be serviced */ 145 intr_status = XIntc_GetIntrStatus(XPAR_INTC_0_BASEADDR); 146 147 /* Service each interrupt that is active and enabled by checking each 148 * bit in the register from LSB to MSB which corresponds to an interrupt 149 * intput signal 150 */ 151 for (intr_number = 0; intr_number < XPAR_INTC_MAX_NUM_INTR_INPUTS; intr_number++) 152 { 153 if (intr_status & 1) 154 { 155 XIntc_VectorTableEntry *table_ptr; 156 157 /* If the interrupt has been setup to acknowledge it 158 * before servicing the interrupt, then ack it 159 */ 160 if (cfg_ptr->AckBeforeService & intr_mask) 161 { 162 XIntc_AckIntr(cfg_ptr->BaseAddress, intr_mask); 163 } 164 165 /* The interrupt is active and enabled, call the 166 * interrupt handler that was setup with the specified 167 * parameter 168 */ 169 table_ptr = &(cfg_ptr->HandlerTable[intr_number]); 170 table_ptr->Handler(table_ptr->CallBackRef); 171 172 /* If the interrupt has been setup to acknowledge it 173 * after it has been serviced then ack it 174 */ 175 if ((cfg_ptr->AckBeforeService & intr_mask) == 0) 176 { 177 XIntc_AckIntr(cfg_ptr->BaseAddress, intr_mask); 178 } 179 180 /* 181 * Read the ISR again to handle architectures with posted write 182 * bus access issues. 183 */ 184 reg = XIntc_GetIntrStatus(cfg_ptr->BaseAddress); 185 186 /* 187 * If only the highest priority interrupt is to be 188 * serviced, exit loop and return after servicing 189 * the interrupt 190 */ 191 if (cfg_ptr->Options == XIN_SVC_SGL_ISR_OPTION) 192 { 193 return; 194 } 195 } 196 197 /* Move to the next interrupt to check */ 198 intr_mask <<= 1; 199 intr_status >>= 1; 200 201 /* If there are no other bits set indicating that all interrupts 202 * have been serviced, then exit the loop 203 */ 204 if (intr_status == 0) 205 { 206 break; 207 } 208 } 209 } 210 211 212