Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:41

0001 /*
0002  *  This file contains the implementation of the function described in irq.h
0003  */
0004 
0005 /*
0006  *  Copyright (c) 2009 embedded brains GmbH & Co. KG
0007  *  Copyright (C) 1998 valette@crf.canon.fr
0008  *
0009  *  The license and distribution terms for this file may be
0010  *  found in the file LICENSE in this distribution or at
0011  *  http://www.rtems.org/license/LICENSE.
0012  */
0013 
0014 #include <bsp.h>
0015 #include <bsp/irq.h>
0016 #include <bsp/irq-generic.h>
0017 #include <rtems/score/cpu.h>
0018 #include <rtems/score/processormaskimpl.h>
0019 
0020 #include <stdlib.h>
0021 #include <stdio.h>
0022 #include <inttypes.h>
0023 
0024 
0025 #include "elcr.h"
0026 
0027 RTEMS_INTERRUPT_LOCK_DEFINE( static, rtems_i8259_access_lock, "rtems_i8259_access_lock" );
0028 
0029 /*
0030  * pointer to the mask representing the additionnal irq vectors
0031  * that must be disabled when a particular entry is activated.
0032  * They will be dynamically computed from teh prioruty table given
0033  * in BSP_rtems_irq_mngt_set();
0034  * CAUTION : this table is accessed directly by interrupt routine
0035  *       prologue.
0036  */
0037 static rtems_i8259_masks irq_mask_or_tbl[BSP_IRQ_LINES_NUMBER];
0038 
0039 /*
0040  * Stats of interrupts dispatched.
0041  */
0042 static uint32_t irq_count[BSP_IRQ_VECTOR_NUMBER] = {0};
0043 static uint32_t spurious_count;
0044 
0045 /*
0046  * Edge or level trigger interrupts.
0047  */
0048 static enum intr_trigger irq_trigger[BSP_IRQ_LINES_NUMBER];
0049 
0050 /*-------------------------------------------------------------------------+
0051 | Cache for 1st and 2nd PIC IRQ line's mssk (enabled or disabled) register.
0052 +--------------------------------------------------------------------------*/
0053 /*
0054  * lower byte is interrupt mask on the master PIC.
0055  * while upper bits are interrupt on the slave PIC.
0056  * This cache is initialized in ldseg.s
0057  */
0058 static rtems_i8259_masks i8259a_imr_cache = 0xFFFB;
0059 static rtems_i8259_masks i8259a_in_progress = 0;
0060 
0061 static inline
0062 void BSP_i8259a_irq_update_master_imr( void )
0063 {
0064   rtems_i8259_masks mask = i8259a_in_progress | i8259a_imr_cache;
0065   outport_byte( PIC_MASTER_IMR_IO_PORT, mask & 0xff );
0066 }
0067 
0068 static inline
0069 void BSP_i8259a_irq_update_slave_imr( void )
0070 {
0071   rtems_i8259_masks mask = i8259a_in_progress | i8259a_imr_cache;
0072   outport_byte( PIC_SLAVE_IMR_IO_PORT, ( mask >> 8 ) & 0xff );
0073 }
0074 
0075 /*
0076  * Print the stats.
0077  */
0078 uint32_t BSP_irq_count_dump(FILE *f)
0079 {
0080   uint32_t tot = 0;
0081   int      i;
0082  if ( !f )
0083    f = stdout;
0084  fprintf(f,"SPURIOUS: %9"PRIu32"\n", spurious_count);
0085  for ( i = 0; i < BSP_IRQ_VECTOR_NUMBER; i++ ) {
0086    char type = '-';
0087    if (i < BSP_IRQ_LINES_NUMBER)
0088      type = irq_trigger[i] == INTR_TRIGGER_EDGE ? 'E' : 'L';
0089    tot += irq_count[i];
0090    fprintf(f,"IRQ %2u: %c %9"PRIu32"\n", i, type, irq_count[i]);
0091  }
0092  return tot;
0093 }
0094 
0095 /*
0096  * Is the IRQ valid?
0097  */
0098 static inline bool BSP_i8259a_irq_valid(const rtems_irq_number irqLine)
0099 {
0100   return ((int)irqLine >= BSP_IRQ_VECTOR_LOWEST_OFFSET) &&
0101     ((int)irqLine <= BSP_IRQ_MAX_ON_i8259A);
0102 }
0103 
0104 /*
0105  * Read the IRR register. The default.
0106  */
0107 static inline uint8_t BSP_i8259a_irq_int_request_reg(uint32_t ioport)
0108 {
0109   uint8_t isr;
0110   inport_byte(ioport, isr);
0111   return isr;
0112 }
0113 
0114 /*
0115  * Read the ISR register. Keep the default of the IRR.
0116  */
0117 static inline uint8_t BSP_i8259a_irq_in_service_reg(uint32_t ioport)
0118 {
0119   uint8_t isr;
0120   outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR | PIC_OCW3_RIS);
0121   inport_byte(ioport, isr);
0122   outport_byte(ioport, PIC_OCW3_SEL | PIC_OCW3_RR);
0123   return isr;
0124 }
0125 
0126 /*-------------------------------------------------------------------------+
0127 |         Function:  BSP_irq_disable_at_i8259a
0128 |      Description: Mask IRQ line in appropriate PIC chip.
0129 | Global Variables: i8259a_imr_cache, i8259a_in_progress
0130 |        Arguments: vector_offset - number of IRQ line to mask.
0131 |          Returns: 0 is OK.
0132 +--------------------------------------------------------------------------*/
0133 static int BSP_irq_disable_at_i8259a(const rtems_irq_number irqLine)
0134 {
0135   unsigned short        mask;
0136   rtems_interrupt_lock_context lock_context;
0137 
0138   rtems_interrupt_lock_acquire(&rtems_i8259_access_lock, &lock_context);
0139 
0140   mask = 1 << irqLine;
0141   i8259a_imr_cache |= mask;
0142 
0143   if (irqLine < 8)
0144   {
0145     BSP_i8259a_irq_update_master_imr();
0146   }
0147   else
0148   {
0149     BSP_i8259a_irq_update_slave_imr();
0150   }
0151 
0152   rtems_interrupt_lock_release(&rtems_i8259_access_lock, &lock_context);
0153 
0154   return 0;
0155 }
0156 
0157 /*-------------------------------------------------------------------------+
0158 |         Function:  BSP_irq_enable_at_i8259a
0159 |      Description: Unmask IRQ line in appropriate PIC chip.
0160 | Global Variables: i8259a_imr_cache, i8259a_in_progress
0161 |        Arguments: irqLine - number of IRQ line to mask.
0162 |          Returns: Nothing.
0163 +--------------------------------------------------------------------------*/
0164 static int BSP_irq_enable_at_i8259a(const rtems_irq_number irqLine)
0165 {
0166   unsigned short        mask;
0167   rtems_interrupt_lock_context lock_context;
0168   uint8_t               isr;
0169   uint8_t               irr;
0170 
0171   rtems_interrupt_lock_acquire(&rtems_i8259_access_lock, &lock_context);
0172 
0173   mask = 1 << irqLine;
0174   i8259a_imr_cache &= ~mask;
0175 
0176   if (irqLine < 8)
0177   {
0178     isr = BSP_i8259a_irq_in_service_reg(PIC_MASTER_COMMAND_IO_PORT);
0179     irr = BSP_i8259a_irq_int_request_reg(PIC_MASTER_COMMAND_IO_PORT);
0180     BSP_i8259a_irq_update_master_imr();
0181   }
0182   else
0183   {
0184     isr = BSP_i8259a_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
0185     irr = BSP_i8259a_irq_int_request_reg(PIC_SLAVE_COMMAND_IO_PORT);
0186     BSP_i8259a_irq_update_slave_imr();
0187   }
0188 
0189   if (((isr ^ irr) & mask) != 0)
0190     printk("i386: isr=%x irr=%x\n", isr, irr);
0191 
0192   rtems_interrupt_lock_release(&rtems_i8259_access_lock, &lock_context);
0193 
0194   return 0;
0195 } /* mask_irq */
0196 
0197 /*-------------------------------------------------------------------------+
0198 |         Function: BSP_irq_ack_at_i8259a
0199 |      Description: Signal generic End Of Interrupt (EOI) to appropriate PIC.
0200 | Global Variables: None.
0201 |        Arguments: irqLine - number of IRQ line to acknowledge.
0202 |          Returns: Nothing.
0203 +--------------------------------------------------------------------------*/
0204 static int BSP_irq_ack_at_i8259a(const rtems_irq_number irqLine)
0205 {
0206   uint8_t slave_isr = 0;
0207 
0208   if (irqLine >= 8) {
0209    outport_byte(PIC_SLAVE_COMMAND_IO_PORT, PIC_EOI);
0210    slave_isr = BSP_i8259a_irq_in_service_reg(PIC_SLAVE_COMMAND_IO_PORT);
0211   }
0212 
0213   /*
0214    * Only issue the EOI to the master if there are no more interrupts in
0215    * service for the slave. i8259a data sheet page 18, The Special Fully Nested
0216    * Mode, b.
0217    */
0218   if (slave_isr == 0)
0219     outport_byte(PIC_MASTER_COMMAND_IO_PORT, PIC_EOI);
0220 
0221   return 0;
0222 
0223 } /* ackIRQ */
0224 
0225 /*
0226  * ------------------------ RTEMS Irq helper functions ----------------
0227  */
0228 
0229 static rtems_irq_prio irqPrioTable[BSP_IRQ_LINES_NUMBER]={
0230   /*
0231    * actual priorities for each interrupt source:
0232    *    0   means that only current interrupt is masked
0233    *    255 means all other interrupts are masked
0234    * The second entry has a priority of 255 because
0235    * it is the slave pic entry and is should always remain
0236    * unmasked.
0237    */
0238   0,0,
0239   255,
0240   0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0
0241 };
0242 
0243 static void compute_i8259_masks_from_prio (void)
0244 {
0245   rtems_interrupt_lock_context lock_context;
0246   unsigned int i;
0247   unsigned int j;
0248 
0249   rtems_interrupt_lock_acquire(&rtems_i8259_access_lock, &lock_context);
0250 
0251   /*
0252    * Always mask at least current interrupt to prevent re-entrance
0253    */
0254   for (i=0; i < BSP_IRQ_LINES_NUMBER; i++) {
0255     * ((unsigned short*) &irq_mask_or_tbl[i]) = (1 << i);
0256     for (j = 0; j < BSP_IRQ_LINES_NUMBER; j++) {
0257       /*
0258        * Mask interrupts at i8259 level that have a lower priority
0259        */
0260       if (irqPrioTable [i] > irqPrioTable [j]) {
0261     * ((unsigned short*) &irq_mask_or_tbl[i]) |= (1 << j);
0262       }
0263     }
0264   }
0265 
0266   rtems_interrupt_lock_release(&rtems_i8259_access_lock, &lock_context);
0267 }
0268 
0269 static inline bool bsp_interrupt_vector_is_valid(rtems_vector_number vector)
0270 {
0271   return BSP_i8259a_irq_valid((const rtems_irq_number) vector);
0272 }
0273 
0274 rtems_status_code bsp_interrupt_get_attributes(
0275   rtems_vector_number         vector,
0276   rtems_interrupt_attributes *attributes
0277 )
0278 {
0279   return RTEMS_SUCCESSFUL;
0280 }
0281 
0282 rtems_status_code bsp_interrupt_is_pending(
0283   rtems_vector_number vector,
0284   bool               *pending
0285 )
0286 {
0287   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0288   bsp_interrupt_assert(pending != NULL);
0289   *pending = false;
0290   return RTEMS_UNSATISFIED;
0291 }
0292 
0293 rtems_status_code bsp_interrupt_raise(rtems_vector_number vector)
0294 {
0295   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0296   return RTEMS_UNSATISFIED;
0297 }
0298 
0299 #if defined(RTEMS_SMP)
0300 rtems_status_code bsp_interrupt_raise_on(
0301   rtems_vector_number vector,
0302   uint32_t            cpu_index
0303 )
0304 {
0305   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0306   return RTEMS_UNSATISFIED;
0307 }
0308 #endif
0309 
0310 rtems_status_code bsp_interrupt_clear(rtems_vector_number vector)
0311 {
0312   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0313   return RTEMS_UNSATISFIED;
0314 }
0315 
0316 rtems_status_code bsp_interrupt_vector_is_enabled(
0317   rtems_vector_number vector,
0318   bool               *enabled
0319 )
0320 {
0321   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0322   bsp_interrupt_assert(enabled != NULL);
0323   *enabled = false;
0324   return RTEMS_UNSATISFIED;
0325 }
0326 
0327 rtems_status_code bsp_interrupt_vector_enable(rtems_vector_number vector)
0328 {
0329   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0330   BSP_irq_enable_at_i8259a(vector);
0331   return RTEMS_SUCCESSFUL;
0332 }
0333 
0334 rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector)
0335 {
0336   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0337   BSP_irq_disable_at_i8259a(vector);
0338   return RTEMS_SUCCESSFUL;
0339 }
0340 
0341 rtems_status_code bsp_interrupt_set_priority(
0342   rtems_vector_number vector,
0343   uint32_t priority
0344 )
0345 {
0346   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0347   return RTEMS_UNSATISFIED;
0348 }
0349 
0350 rtems_status_code bsp_interrupt_get_priority(
0351   rtems_vector_number vector,
0352   uint32_t *priority
0353 )
0354 {
0355   bsp_interrupt_assert(bsp_interrupt_is_valid_vector(vector));
0356   bsp_interrupt_assert(priority != NULL);
0357   return RTEMS_UNSATISFIED;
0358 }
0359 
0360 #if defined(RTEMS_SMP)
0361 rtems_status_code bsp_interrupt_get_affinity(
0362   rtems_vector_number  vector,
0363   Processor_mask      *affinity
0364 )
0365 {
0366   (void) vector;
0367   _Processor_mask_From_index( affinity, 0 );
0368   return RTEMS_UNSATISFIED;
0369 }
0370 
0371 rtems_status_code bsp_interrupt_set_affinity(
0372   rtems_vector_number   vector,
0373   const Processor_mask *affinity
0374 )
0375 {
0376   (void) vector;
0377   (void) affinity;
0378   return RTEMS_UNSATISFIED;
0379 }
0380 #endif
0381 
0382 void bsp_interrupt_facility_initialize(void)
0383 {
0384   int i;
0385 
0386   /*
0387    * set up internal tables used by rtems interrupt prologue
0388    */
0389   compute_i8259_masks_from_prio();
0390 
0391   /*
0392    * must enable slave pic anyway
0393    */
0394   BSP_irq_enable_at_i8259a(2);
0395 
0396   /*
0397    * Probe the ELCR.
0398    */
0399   elcr_probe();
0400 
0401   for (i = 0; i < BSP_IRQ_LINES_NUMBER; i++)
0402     irq_trigger[i] = elcr_read_trigger(i);
0403 }
0404 
0405 static bool bsp_interrupt_handler_is_empty(rtems_vector_number vector)
0406 {
0407   return bsp_interrupt_entry_load_first(vector) == NULL;
0408 }
0409 
0410 /*
0411  * Global so the asm handler can call it.
0412  */
0413 void BSP_dispatch_isr(int vector);
0414 
0415 void BSP_dispatch_isr(int vector)
0416 {
0417   rtems_interrupt_lock_context lock_context;
0418   rtems_i8259_masks in_progress_save = 0;
0419 
0420   if (vector < BSP_IRQ_VECTOR_NUMBER) {
0421     /*
0422      * Hardware?
0423      */
0424     if (vector <= BSP_IRQ_MAX_ON_i8259A) {
0425 
0426       rtems_interrupt_lock_acquire_isr(&rtems_i8259_access_lock, &lock_context);
0427 
0428       /*
0429        * See if this is a spurious interrupt.
0430        */
0431       if ((vector == 7 || vector == 15)) {
0432         /*
0433          * Only check it there no handler for 7 or 15.
0434          */
0435         if (bsp_interrupt_handler_is_empty(vector)) {
0436           /*
0437            * Read the ISR register to see if IRQ 7/15 is really pending.
0438            */
0439           uint8_t isr = BSP_i8259a_irq_in_service_reg(PIC_MASTER_COMMAND_IO_PORT);
0440           if ((isr & (1 << 7)) == 0) {
0441             ++spurious_count;
0442             rtems_interrupt_lock_release_isr(&rtems_i8259_access_lock, &lock_context);
0443             return;
0444           }
0445         }
0446       }
0447 
0448       /*
0449        * Save the current cached value for the IMR. It will have the bit for this
0450        * vector clear.
0451        */
0452       if (vector <= BSP_IRQ_MAX_ON_i8259A) {
0453         in_progress_save = i8259a_in_progress;
0454         i8259a_in_progress |= irq_mask_or_tbl[vector];
0455         BSP_i8259a_irq_update_master_imr();
0456         BSP_i8259a_irq_update_slave_imr();
0457       }
0458 
0459       /*
0460        * Do not use auto-EOI as some slave PIC do not work correctly.
0461        */
0462       BSP_irq_ack_at_i8259a(vector);
0463 
0464       rtems_interrupt_lock_release_isr(&rtems_i8259_access_lock, &lock_context);
0465     }
0466 
0467     /*
0468      * Count the interrupt.
0469      */
0470     irq_count[vector]++;
0471 
0472     RTEMS_COMPILER_MEMORY_BARRIER();
0473     /*
0474      * Allow nesting.
0475      */
0476     __asm__ __volatile__("sti");
0477 
0478     bsp_interrupt_handler_dispatch(vector);
0479 
0480     /*
0481      * Disallow nesting.
0482      */
0483     __asm__ __volatile__("cli");
0484 
0485     RTEMS_COMPILER_MEMORY_BARRIER();
0486 
0487     if (vector <= BSP_IRQ_MAX_ON_i8259A) {
0488 
0489       rtems_interrupt_lock_acquire_isr(&rtems_i8259_access_lock, &lock_context);
0490 
0491       /*
0492        * Put the mask back but keep this vector masked if the trigger type is
0493        * level. The driver or a thread level interrupt server needs to enable it
0494        * again.
0495        */
0496       if (vector <= BSP_IRQ_MAX_ON_i8259A) {
0497         i8259a_in_progress = in_progress_save;
0498         BSP_i8259a_irq_update_master_imr();
0499         BSP_i8259a_irq_update_slave_imr();
0500       }
0501 
0502       rtems_interrupt_lock_release_isr(&rtems_i8259_access_lock, &lock_context);
0503     }
0504   }
0505 }