PowerPC exceptions and interrupts

Till Straumann strauman at slac.stanford.edu
Fri May 23 17:55:26 UTC 2008


>> The next algorithm is required to handle correctly shared edge
>> triggered sources
>>
>>    rtems_interrupt_handled_state again;
>>    rtems_interrupt_handled_state res;
>>    do {
>>      again = 0;
>>      for_each(vector->rtems_irq_connect_data_list, connect) {
>>        res=connect->hndl(connect->handle);
>>        if(res == RTEMS_INTERRUPT_HANDLED)
>>          again = 1;
>>      }
>>    } while(again);
>>
>>     
>
> If understand the above scheme correctly, the intention is to handle 
> shared interrupt sources onan edge triggered interrupt input.
>   
>  From my perspective as a (sometimes) hardware developer, I assume such 
> a structure as a severe bug. I consider it at least questionable, 
> whether it makes sense to cure such a design fault in a general way, 
> which will greatly increase the interrupt response time for other 
> interrupt sources (Note, that normally each chain of interrupt handlers 
> will be called at least twice instead of once).
>
> If such a hardware must be serviced correctly, a better, "realtime" way 
> would be that the interrupt dispatcher code will check the state of the 
> interrupt line AFTER the handlers have been called ONCE and, if the 
> (GPIO?) line is still active, will call the handlers again. But this 
> must be controlled by specific code in the dispatcher area of the BSP.
>   
Not sure I understand this all but IMO in order to
properly support shared, edge-triggered interrupts
you must clear the interrupt at the IRQ controller
*before* dispatching them (so that a possible IRQ
raised by device 'X' just after the handler for 'X' returns
but before the interrupt is cleared in the IRQ controller
is not lost):

   active_irqs = get_active_irqs();

   if ( edge_triggered ) {
         /* disable irqs so that new IRQ occurring just
          * after clearing does not interrupt us again
          * further down when we enable IRQS
          */
         clear_irqs_at_irq_controller(active_irqs);
          /* temporarily mask interrupts we're working on */
          disable_irqs_at_irq_controller(active_irqs);
   }

   enable_interrupts(); /* enable other irqs during dipatch of the 
handlers */

   dispatch_all_handlers(active_irqs)

   disable_interrupts(); /* turn off again */

   if ( edge_triggered ) {
   /* re-enable 'active_irqs' here. There could be an IRQ
    * latched which has already be handled (occurred between
    * clear_irqs_at_irq_controller() and the handler being
    * called) but that would only result in an extra (unnecessary)
    * execution of the irq dispatcher.
    */
      enable_irqs_at_irq_controller(active_irqs);
   } else {
        /* clear active irqs. If a new level-triggered IRQ occurred
         * after the corresponding handler was executed then
         * the irq will be asserted again after clearing and
         * the irq dispatcher will execute immediately.
         */
       clear_irqs_at_irq_controller(active_irqs);
   }

FWIW
-- Till
> wkr,
> Thomas.
>
>   




More information about the users mailing list