[67a2288] | 1 | /* irq.c |
---|
| 2 | * |
---|
| 3 | * This file contains the implementation of the function described in irq.h |
---|
| 4 | * |
---|
| 5 | * CopyRight (C) 1998 valette@crf.canon.fr |
---|
| 6 | * |
---|
| 7 | * The license and distribution terms for this file may be |
---|
| 8 | * found in found in the file LICENSE in this distribution or at |
---|
[a3c7123] | 9 | * http://www.rtems.com/license/LICENSE. |
---|
[67a2288] | 10 | * |
---|
| 11 | * $Id$ |
---|
| 12 | */ |
---|
| 13 | |
---|
| 14 | #include <bsp.h> |
---|
[529cebf0] | 15 | #include <bsp/irq.h> |
---|
[eb562f2] | 16 | #include <rtems/score/thread.h> |
---|
| 17 | #include <rtems/score/apiext.h> |
---|
| 18 | |
---|
[67a2288] | 19 | /* |
---|
| 20 | * pointer to the mask representing the additionnal irq vectors |
---|
| 21 | * that must be disabled when a particular entry is activated. |
---|
| 22 | * They will be dynamically computed from teh prioruty table given |
---|
[0ebbf66] | 23 | * in BSP_rtems_irq_mngt_set(); |
---|
[67a2288] | 24 | * CAUTION : this table is accessed directly by interrupt routine |
---|
| 25 | * prologue. |
---|
| 26 | */ |
---|
[0ebbf66] | 27 | rtems_i8259_masks irq_mask_or_tbl[BSP_IRQ_LINES_NUMBER]; |
---|
[67a2288] | 28 | |
---|
| 29 | /* |
---|
| 30 | * default handler connected on each irq after bsp initialization |
---|
| 31 | */ |
---|
| 32 | static rtems_irq_connect_data default_rtems_entry; |
---|
| 33 | |
---|
| 34 | /* |
---|
| 35 | * location used to store initial tables used for interrupt |
---|
| 36 | * management. |
---|
| 37 | */ |
---|
| 38 | static rtems_irq_global_settings* internal_config; |
---|
[f0a2528] | 39 | rtems_irq_connect_data* rtems_hdl_tbl; |
---|
[67a2288] | 40 | /*-------------------------------------------------------------------------+ |
---|
| 41 | | Cache for 1st and 2nd PIC IRQ line's status (enabled or disabled) register. |
---|
| 42 | +--------------------------------------------------------------------------*/ |
---|
| 43 | /* |
---|
| 44 | * lower byte is interrupt mask on the master PIC. |
---|
| 45 | * while upper bits are interrupt on the slave PIC. |
---|
| 46 | * This cache is initialized in ldseg.s |
---|
| 47 | */ |
---|
[a1c70a2] | 48 | rtems_i8259_masks i8259s_cache = 0xFFFB; |
---|
[67a2288] | 49 | |
---|
| 50 | /*-------------------------------------------------------------------------+ |
---|
[0ebbf66] | 51 | | Function: BSP_irq_disable_at_i8259s |
---|
[67a2288] | 52 | | Description: Mask IRQ line in appropriate PIC chip. |
---|
| 53 | | Global Variables: i8259s_cache |
---|
| 54 | | Arguments: vector_offset - number of IRQ line to mask. |
---|
[6128a4a] | 55 | | Returns: Nothing. |
---|
[67a2288] | 56 | +--------------------------------------------------------------------------*/ |
---|
[838c82b] | 57 | int BSP_irq_disable_at_i8259s (const rtems_irq_number irqLine) |
---|
[67a2288] | 58 | { |
---|
[c83c325] | 59 | unsigned short mask; |
---|
| 60 | rtems_interrupt_level level; |
---|
[67a2288] | 61 | |
---|
[0ebbf66] | 62 | if ( ((int)irqLine < BSP_LOWEST_OFFSET) || |
---|
| 63 | ((int)irqLine > BSP_MAX_OFFSET ) |
---|
[67a2288] | 64 | ) |
---|
| 65 | return 1; |
---|
[6128a4a] | 66 | |
---|
[c83c325] | 67 | rtems_interrupt_disable(level); |
---|
[6128a4a] | 68 | |
---|
[67a2288] | 69 | mask = 1 << irqLine; |
---|
| 70 | i8259s_cache |= mask; |
---|
[6128a4a] | 71 | |
---|
[67a2288] | 72 | if (irqLine < 8) |
---|
| 73 | { |
---|
| 74 | outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff); |
---|
| 75 | } |
---|
| 76 | else |
---|
| 77 | { |
---|
[783e8322] | 78 | outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8)); |
---|
[67a2288] | 79 | } |
---|
[c83c325] | 80 | rtems_interrupt_enable(level); |
---|
[67a2288] | 81 | |
---|
| 82 | return 0; |
---|
[6128a4a] | 83 | } |
---|
[67a2288] | 84 | |
---|
| 85 | /*-------------------------------------------------------------------------+ |
---|
[0ebbf66] | 86 | | Function: BSP_irq_enable_at_i8259s |
---|
[67a2288] | 87 | | Description: Unmask IRQ line in appropriate PIC chip. |
---|
| 88 | | Global Variables: i8259s_cache |
---|
| 89 | | Arguments: irqLine - number of IRQ line to mask. |
---|
[6128a4a] | 90 | | Returns: Nothing. |
---|
[67a2288] | 91 | +--------------------------------------------------------------------------*/ |
---|
[838c82b] | 92 | int BSP_irq_enable_at_i8259s (const rtems_irq_number irqLine) |
---|
[67a2288] | 93 | { |
---|
[c83c325] | 94 | unsigned short mask; |
---|
| 95 | rtems_interrupt_level level; |
---|
[67a2288] | 96 | |
---|
[0ebbf66] | 97 | if ( ((int)irqLine < BSP_LOWEST_OFFSET) || |
---|
| 98 | ((int)irqLine > BSP_MAX_OFFSET ) |
---|
[67a2288] | 99 | ) |
---|
| 100 | return 1; |
---|
| 101 | |
---|
[c83c325] | 102 | rtems_interrupt_disable(level); |
---|
[6128a4a] | 103 | |
---|
[67a2288] | 104 | mask = ~(1 << irqLine); |
---|
| 105 | i8259s_cache &= mask; |
---|
[6128a4a] | 106 | |
---|
[67a2288] | 107 | if (irqLine < 8) |
---|
| 108 | { |
---|
| 109 | outport_byte(PIC_MASTER_IMR_IO_PORT, i8259s_cache & 0xff); |
---|
| 110 | } |
---|
| 111 | else |
---|
| 112 | { |
---|
[783e8322] | 113 | outport_byte(PIC_SLAVE_IMR_IO_PORT, ((i8259s_cache & 0xff00) >> 8)); |
---|
[67a2288] | 114 | } |
---|
[c83c325] | 115 | rtems_interrupt_enable(level); |
---|
[67a2288] | 116 | |
---|
| 117 | return 0; |
---|
| 118 | } /* mask_irq */ |
---|
| 119 | |
---|
[838c82b] | 120 | int BSP_irq_enabled_at_i8259s (const rtems_irq_number irqLine) |
---|
[67a2288] | 121 | { |
---|
| 122 | unsigned short mask; |
---|
| 123 | |
---|
[0ebbf66] | 124 | if ( ((int)irqLine < BSP_LOWEST_OFFSET) || |
---|
| 125 | ((int)irqLine > BSP_MAX_OFFSET ) |
---|
[67a2288] | 126 | ) |
---|
| 127 | return 1; |
---|
| 128 | |
---|
| 129 | mask = (1 << irqLine); |
---|
| 130 | return (~(i8259s_cache & mask)); |
---|
| 131 | } |
---|
[6128a4a] | 132 | |
---|
[67a2288] | 133 | /*-------------------------------------------------------------------------+ |
---|
[0ebbf66] | 134 | | Function: BSP_irq_ack_at_i8259s |
---|
[67a2288] | 135 | | Description: Signal generic End Of Interrupt (EOI) to appropriate PIC. |
---|
| 136 | | Global Variables: None. |
---|
| 137 | | Arguments: irqLine - number of IRQ line to acknowledge. |
---|
[6128a4a] | 138 | | Returns: Nothing. |
---|
[67a2288] | 139 | +--------------------------------------------------------------------------*/ |
---|
[838c82b] | 140 | int BSP_irq_ack_at_i8259s (const rtems_irq_number irqLine) |
---|
[67a2288] | 141 | { |
---|
[0ebbf66] | 142 | if ( ((int)irqLine < BSP_LOWEST_OFFSET) || |
---|
| 143 | ((int)irqLine > BSP_MAX_OFFSET ) |
---|
[67a2288] | 144 | ) |
---|
| 145 | return 1; |
---|
| 146 | |
---|
| 147 | if (irqLine >= 8) { |
---|
| 148 | outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI); |
---|
| 149 | } |
---|
| 150 | outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI); |
---|
| 151 | |
---|
| 152 | return 0; |
---|
| 153 | |
---|
| 154 | } /* ackIRQ */ |
---|
| 155 | |
---|
| 156 | /* |
---|
| 157 | * ------------------------ RTEMS Irq helper functions ---------------- |
---|
| 158 | */ |
---|
[6128a4a] | 159 | |
---|
[67a2288] | 160 | /* |
---|
| 161 | * Caution : this function assumes the variable "internal_config" |
---|
| 162 | * is already set and that the tables it contains are still valid |
---|
| 163 | * and accessible. |
---|
| 164 | */ |
---|
| 165 | static void compute_i8259_masks_from_prio () |
---|
| 166 | { |
---|
| 167 | unsigned int i; |
---|
| 168 | unsigned int j; |
---|
| 169 | /* |
---|
| 170 | * Always mask at least current interrupt to prevent re-entrance |
---|
| 171 | */ |
---|
| 172 | for (i=0; i < internal_config->irqNb; i++) { |
---|
| 173 | * ((unsigned short*) &irq_mask_or_tbl[i]) = (1 << i); |
---|
| 174 | for (j = 0; j < internal_config->irqNb; j++) { |
---|
| 175 | /* |
---|
| 176 | * Mask interrupts at i8259 level that have a lower priority |
---|
| 177 | */ |
---|
| 178 | if (internal_config->irqPrioTbl [i] > internal_config->irqPrioTbl [j]) { |
---|
| 179 | * ((unsigned short*) &irq_mask_or_tbl[i]) |= (1 << j); |
---|
| 180 | } |
---|
| 181 | } |
---|
| 182 | } |
---|
| 183 | } |
---|
| 184 | |
---|
| 185 | /* |
---|
| 186 | * This function check that the value given for the irq line |
---|
| 187 | * is valid. |
---|
| 188 | */ |
---|
| 189 | |
---|
| 190 | static int isValidInterrupt(int irq) |
---|
| 191 | { |
---|
[0ebbf66] | 192 | if ( (irq < BSP_LOWEST_OFFSET) || (irq > BSP_MAX_OFFSET)) |
---|
[67a2288] | 193 | return 0; |
---|
| 194 | return 1; |
---|
| 195 | } |
---|
| 196 | |
---|
| 197 | /* |
---|
| 198 | * ------------------------ RTEMS Single Irq Handler Mngt Routines ---------------- |
---|
| 199 | */ |
---|
| 200 | |
---|
[0ebbf66] | 201 | int BSP_install_rtems_irq_handler (const rtems_irq_connect_data* irq) |
---|
[67a2288] | 202 | { |
---|
[c83c325] | 203 | rtems_interrupt_level level; |
---|
[6128a4a] | 204 | |
---|
[67a2288] | 205 | if (!isValidInterrupt(irq->name)) { |
---|
| 206 | return 0; |
---|
| 207 | } |
---|
| 208 | /* |
---|
| 209 | * Check if default handler is actually connected. If not issue an error. |
---|
| 210 | * You must first get the current handler via i386_get_current_idt_entry |
---|
| 211 | * and then disconnect it using i386_delete_idt_entry. |
---|
| 212 | * RATIONALE : to always have the same transition by forcing the user |
---|
| 213 | * to get the previous handler before accepting to disconnect. |
---|
| 214 | */ |
---|
[c83c325] | 215 | rtems_interrupt_disable(level); |
---|
[67a2288] | 216 | if (rtems_hdl_tbl[irq->name].hdl != default_rtems_entry.hdl) { |
---|
[c83c325] | 217 | rtems_interrupt_enable(level); |
---|
[67a2288] | 218 | return 0; |
---|
| 219 | } |
---|
| 220 | |
---|
| 221 | /* |
---|
| 222 | * store the data provided by user |
---|
| 223 | */ |
---|
| 224 | rtems_hdl_tbl[irq->name] = *irq; |
---|
| 225 | /* |
---|
| 226 | * Enable interrupt at PIC level |
---|
| 227 | */ |
---|
[0ebbf66] | 228 | BSP_irq_enable_at_i8259s (irq->name); |
---|
[67a2288] | 229 | /* |
---|
| 230 | * Enable interrupt on device |
---|
| 231 | */ |
---|
| 232 | irq->on(irq); |
---|
[6128a4a] | 233 | |
---|
[c83c325] | 234 | rtems_interrupt_enable(level); |
---|
[67a2288] | 235 | |
---|
| 236 | return 1; |
---|
| 237 | } |
---|
| 238 | |
---|
[0ebbf66] | 239 | int BSP_get_current_rtems_irq_handler (rtems_irq_connect_data* irq) |
---|
[67a2288] | 240 | { |
---|
[c83c325] | 241 | rtems_interrupt_level level; |
---|
[fe235a1e] | 242 | |
---|
[c83c325] | 243 | if (!isValidInterrupt(irq->name)) { |
---|
[67a2288] | 244 | return 0; |
---|
[c83c325] | 245 | } |
---|
| 246 | rtems_interrupt_disable(level); |
---|
| 247 | *irq = rtems_hdl_tbl[irq->name]; |
---|
| 248 | rtems_interrupt_enable(level); |
---|
| 249 | return 1; |
---|
[67a2288] | 250 | } |
---|
| 251 | |
---|
[0ebbf66] | 252 | int BSP_remove_rtems_irq_handler (const rtems_irq_connect_data* irq) |
---|
[67a2288] | 253 | { |
---|
[c83c325] | 254 | rtems_interrupt_level level; |
---|
[6128a4a] | 255 | |
---|
[67a2288] | 256 | if (!isValidInterrupt(irq->name)) { |
---|
| 257 | return 0; |
---|
| 258 | } |
---|
| 259 | /* |
---|
| 260 | * Check if default handler is actually connected. If not issue an error. |
---|
| 261 | * You must first get the current handler via i386_get_current_idt_entry |
---|
| 262 | * and then disconnect it using i386_delete_idt_entry. |
---|
| 263 | * RATIONALE : to always have the same transition by forcing the user |
---|
| 264 | * to get the previous handler before accepting to disconnect. |
---|
| 265 | */ |
---|
[c83c325] | 266 | rtems_interrupt_disable(level); |
---|
[67a2288] | 267 | if (rtems_hdl_tbl[irq->name].hdl != irq->hdl) { |
---|
[c83c325] | 268 | rtems_interrupt_enable(level); |
---|
[67a2288] | 269 | return 0; |
---|
| 270 | } |
---|
| 271 | |
---|
| 272 | /* |
---|
| 273 | * disable interrupt at PIC level |
---|
| 274 | */ |
---|
[0ebbf66] | 275 | BSP_irq_disable_at_i8259s (irq->name); |
---|
[67a2288] | 276 | |
---|
| 277 | /* |
---|
| 278 | * Disable interrupt on device |
---|
| 279 | */ |
---|
| 280 | irq->off(irq); |
---|
| 281 | |
---|
| 282 | /* |
---|
| 283 | * restore the default irq value |
---|
| 284 | */ |
---|
| 285 | rtems_hdl_tbl[irq->name] = default_rtems_entry; |
---|
| 286 | |
---|
[c83c325] | 287 | rtems_interrupt_enable(level); |
---|
[67a2288] | 288 | |
---|
| 289 | return 1; |
---|
| 290 | } |
---|
| 291 | |
---|
| 292 | /* |
---|
| 293 | * ------------------------ RTEMS Global Irq Handler Mngt Routines ---------------- |
---|
| 294 | */ |
---|
| 295 | |
---|
[0ebbf66] | 296 | int BSP_rtems_irq_mngt_set(rtems_irq_global_settings* config) |
---|
[67a2288] | 297 | { |
---|
[c83c325] | 298 | int i; |
---|
| 299 | rtems_interrupt_level level; |
---|
| 300 | |
---|
| 301 | /* |
---|
| 302 | * Store various code accelerators |
---|
| 303 | */ |
---|
[67a2288] | 304 | internal_config = config; |
---|
| 305 | default_rtems_entry = config->defaultEntry; |
---|
| 306 | rtems_hdl_tbl = config->irqHdlTbl; |
---|
| 307 | |
---|
[c83c325] | 308 | rtems_interrupt_disable(level); |
---|
[67a2288] | 309 | /* |
---|
| 310 | * set up internal tables used by rtems interrupt prologue |
---|
| 311 | */ |
---|
| 312 | compute_i8259_masks_from_prio (); |
---|
| 313 | |
---|
| 314 | for (i=0; i < internal_config->irqNb; i++) { |
---|
| 315 | if (rtems_hdl_tbl[i].hdl != default_rtems_entry.hdl) { |
---|
[0ebbf66] | 316 | BSP_irq_enable_at_i8259s (i); |
---|
[67a2288] | 317 | rtems_hdl_tbl[i].on(&rtems_hdl_tbl[i]); |
---|
| 318 | } |
---|
| 319 | else { |
---|
| 320 | rtems_hdl_tbl[i].off(&rtems_hdl_tbl[i]); |
---|
[0ebbf66] | 321 | BSP_irq_disable_at_i8259s (i); |
---|
[67a2288] | 322 | } |
---|
| 323 | } |
---|
| 324 | /* |
---|
[ba46ffa6] | 325 | * must enable slave pic anyway |
---|
[67a2288] | 326 | */ |
---|
[0ebbf66] | 327 | BSP_irq_enable_at_i8259s (2); |
---|
[c83c325] | 328 | rtems_interrupt_enable(level); |
---|
[67a2288] | 329 | return 1; |
---|
| 330 | } |
---|
| 331 | |
---|
[0ebbf66] | 332 | int BSP_rtems_irq_mngt_get(rtems_irq_global_settings** config) |
---|
[67a2288] | 333 | { |
---|
| 334 | *config = internal_config; |
---|
| 335 | return 0; |
---|
[6128a4a] | 336 | } |
---|
[8b2ee37c] | 337 | |
---|
| 338 | void _ThreadProcessSignalsFromIrq (CPU_Exception_frame* ctx) |
---|
| 339 | { |
---|
| 340 | /* |
---|
[eb562f2] | 341 | * Process pending signals that have not already been |
---|
| 342 | * processed by _Thread_Displatch. This happens quite |
---|
| 343 | * unfrequently : the ISR must have posted an action |
---|
| 344 | * to the current running thread. |
---|
| 345 | */ |
---|
| 346 | if ( _Thread_Do_post_task_switch_extension || |
---|
| 347 | _Thread_Executing->do_post_task_switch_extension ) { |
---|
| 348 | _Thread_Executing->do_post_task_switch_extension = FALSE; |
---|
| 349 | _API_extensions_Run_postswitch(); |
---|
| 350 | } |
---|
| 351 | /* |
---|
| 352 | * I plan to process other thread related events here. |
---|
[ba46ffa6] | 353 | * This will include DEBUG session requested from keyboard... |
---|
[8b2ee37c] | 354 | */ |
---|
| 355 | } |
---|
[f0a2528] | 356 | |
---|
| 357 | void processIrq(unsigned index) |
---|
| 358 | { |
---|
| 359 | rtems_hdl_tbl[index].hdl(rtems_hdl_tbl[index].handle); |
---|
| 360 | } |
---|
| 361 | |
---|