Freeing an interrupt line

The function shown in Figure 12.26, from arch/i386/kernel/irq.c, deallocates an interrupt line. The handler is removed and the interrupt line is not available for use by any driver; it is disabled and shutdown. If the irq was shared, then the caller must ensure that the interrupt is disabled on the card that issues this irq before calling this function. This function may be called from interrupt context, but note that attempting to free an irq in a handler for the same irq hangs the machine.

740 void free_irq(unsigned int irq, void *dev_id)

742 irq_desc_t*desc;

743 struct irqaction**p;

744 unsigned long flags; 74 5

746 74 7


spin_lock_irqsave(&desc->lock,flags); p = &desc->action; for (;;) {

struct irqaction **pp = p; p = &action->next; if(action->dev_id ! = dev_id) continue;



768 #ifdef CONFIG_SMP

while (desc->status & IRQ_INPROGRESS) { barrier(); cpu_relax();

774 #endif



printk("Trying to free free IRQ%d\n",irq); spin_unlock_irqrestore(&desc->lock,flags); return;


752-781 753


756 757-758

761 -776

Figure 12.26 Freeing an irq line the function is passed the number of the interrupt line to free and a pointer to the structure representing the device that generates this interrupt. Note that it is declared as void; it gives no indication of whether it was successful or not.

if trying to free an impossibly numbered irq, we simply return immediately.

this constructs a pointer to the entry corresponding to this irq in irq_desc[] (see Section 12.2.4).

mutual exclusion is needed while working on the descriptor, to protect from any other interrupts while doing so. The interrupt safe spinlock functions are described in Section 12.8.1.

this takes a local pointer p to the action field of the descriptor, which is itself a pointer to a struct irqaction (see the definition of p on line 743).

this loop is working its way along the chain of handlers for this irq.

the first time around this loop, the local action variable has the same value as action in the descriptor - that is, it points to the first struct irqaction in the list. On each subsequent iteration of the loop, it will point to the next entry. On any iteration, action points directly to the one we are considering, p points indirectly to the same entry.

this block of code is executed if there is a valid struct irqaction (i.e. if there is at least one more to try). Otherwise, we skip on to line 778.

this takes a local indirect pointer pp to the struct irqaction being considered. this advances p to point to the next entry in the list.

if the dev_id field in the current entry does not match the dev_id passed as parameter, then we do not want to deallocate this one. We go around the loop again (with an updated value for p).

we have found the one we were looking for - now we remove it from the list of entries.

761 from line 755, pp is an indirect pointer to the entry we are considering, through the link field of the previous one. So *pp is the link field in the previous entry. By copying the next field of the entry we are considering into that we ensure that this entry is being removed from the list.

762-765 after the previous line, if there are no entries at all on the list, then this irq is no longer in use by any device.

763 this sets the disabled bit in the status field of the descriptor.

764 this runs the controller shutdown() function for that irq.

766 we are finished with the descriptor, so we give back the lock (see Section 12.8).

768-774 there is one extra complication for a multiprocessing kernel. We have to wait to make sure that the interrupt is not being processed, or that the descriptor is in use by another CPU.

770-773 if the IRQ_INPROGRESS bit is set in the status field of the descriptor, we synchronise memory to make sure that other CPUs see the disabled bit and that we know as soon as possible that the other CPU is finished. So this function will not return until any executing interrupts for this IRQ have completed.

772 this function inserts a pause in a busy waiting loop (see Section

775-776 in any case, we give back the memory occupied by the struct irqaction, and return.

778 control only comes here if action was found to be NULL at line 754 (i.e. we got to the end of the list and found no entry corresponding to the interrupt we are trying to deallocate). The message is not the most helpful.

12.6.3 Disabling an irq

After an irq line has been set up, a driver may wish temporarily to disable it and reenable it later without the extra overhead of shutting it down and then setting it up again. So functions are provided for this. However, calls to disable_irq() and enable_irq() must be paired, and the depth field in the irq_desc_t is provided for this.

There are two functions provided for disabling an irq line. One just goes ahead and disables it; the other is a synchronous version; it waits until any instances of this irq that might be running on any other CPU are finished before returning to the caller. Disabling an irq line without waiting

The function shown in Figure 12.27, from arch/i386/kernel/irq.c, does not ensure existing instances of the irq handler have completed before returning.

482 inline void disable_irq_nosync(unsigned int irq)

484 irq_desc_t *desc = irq_desc + irq; 48 5 unsigned long flags;

487 spin_lock_irqsave(&desc->lock,flags);

489 desc->status | = IRQ_DISABLED;

490 desc->handler->disable(irq);

492 spin_unlock_irqrestore(&desc->lock,flags);

Figure 12.27 Disabling an irq line without waiting

484 this uses the irq number supplied as a parameter to get a pointer to the entry in the irq_desc [] table (Section 12.2.4) corresponding to this irq.

487-492 this code takes out an interrupt-safe spinlock on that element of the table. The macros to manipulate the spinlock are in Section 12.8; the lock itself is part of the descriptor in the table.

488-491 only if the depth field in the descriptor was 0 before the increment will this block of code be executed.

489 this sets the IRQ_DISABLED flag in the descriptor, so that all other handlers know this. However, the controller still thinks it is enabled and many send interrupts until the next line.

490 this calls the disable() function appropriate to the hardware controller from which the interrupt originated. Disabling an irq line and waiting

The disable_irq() function, from arch/i386/kernel/irq.c, is shown in Figure 12.28. It disables the selected interrupt line. This function waits for any pending irq handlers for this interrupt to complete before returning.

508 void disable_irq(unsigned int irq)

510 disable_irq_nosync(irq);

512 if(!local_irq_count(smp_processor_id())){

514 barrier();

516 } while (irq_desc[irq].status &IRQ_INPROGRESS);

Figure 12.28 Disabling an irq line and wait

510 this function, described in Section, does most of the work. It is the nonwaiting version.

512-517 this code is executed only if there are no irqs currently being handled by the local CPU.

512 the smp_processor_id() macro is from Section; the local_irq_count() macro is from Section If there are other irqs in progress, then this function must have been called from a higher priority and so preempted one of them. We do not want to go into a busy waiting loop in that situation.

513-516 the loop delays until any occurrence of this irq being handled on any other CPU has finished.

514 the barrier () macro guarantees that the current process is seeing a coherent view of memory.

515 the cpu_relax() macro, from Section, introduces a delay into this busy waiting loop.

516 we loop until some other CPU clears the IRQ_INPROGRESS flag for this irq.

Was this article helpful?

0 0

Post a comment