Gestion des interruptions
Traitement des interruptions sous Linux
La figure ci-dessous montre schématiquement le traitement des interruptions par le noyau Linux pour les processeurs ARM
Installation des routines de traitement des interruptions
L’interface <linux/interrupt.h>
propose deux fonctions pour
l’enregistrement et l’effacement des routines de traitement
d’interruptions (interrupt handlers)
int request_irq (
unsigned int irq,
irq_handler_t handler,
unsigned long flags,
const char *dev_name,
void *dev_id);
void free_irq (unsigned int irq, void *dev_id);
irq
→ vecteur d’interruption (numéro)handler
→ routine de traitement des interruptionsflags
→ fanions de gestion des interruptionsIRQF_DISABLED
→ garde irqs déclenché lors de l’appel de la routine de traitementIRQF_SAMPLE_RANDOM
→ irq est utilisée pour la génération de nombres aléatoiresIRQF_SHARED
→ permet de partager l’irq avec plusieurs périphériquesIRQF_TIMER
→ fanion pour marquer cette interruption comme timerIRQF_TRIGGER_<xx>
→ fanion pour sélectionner le trigger (xx
:FALLING
,RISING
, …)
dev_name
→ nom du périphérique d’interruptiondev_id
→ paramètre spécifique à l’application(doit impérativement être non nul si l’interruption est partagéeIRQF_SHARED
)
Routine de traitement des interruptions (interrupt handler)
La routine de traitement des interruptions prend la forme suivante
irqreturn_t short_interrupt(int irq, void *dev_id)
{
/* do something...*/
return IRQ_HANDLED;
}
irq
→ vecteur ayant levé l’interruptiondev_id
→ paramètre spécifique à l’application fournie lors de l’enregistrement de la routine de traitement
Si la routine a été en mesure de traiter l’interruption, IRQ_HANDLED
sera retourné, dans le cas contraire, la valeur de retour devra être
IRQ_NONE
La valeur de retour est utilisée par le noyau pour éliminer les interruptions parasites (spurious interrupts)
Etat des Interruptions
La commande cat /proc/interrupts
fournit des informations très intéressantes sur l’état des interruptions avec le nom associé au vecteur d’interruption.
cat /proc/interrupts
CPU0 CPU1 CPU2 CPU3
1: 0 0 0 0 GICv2 25 Level vgic
3: 359 386 482 457 GICv2 30 Level arch_timer
4: 0 0 0 0 GICv2 27 Level kvm guest timer
8: 38452 0 0 0 GICv2 92 Level sunxi-mmc
9: 461 0 0 0 GICv2 93 Level sunxi-mmc
10: 43 0 0 0 GICv2 94 Level sunxi-mmc
11: 0 0 0 0 GICv2 103 Level musb-hdrc.1.auto
12: 0 0 0 0 GICv2 104 Level ehci_hcd:usb1
13: 0 0 0 0 GICv2 105 Level ohci_hcd:usb3
14: 0 0 0 0 GICv2 110 Level ehci_hcd:usb2
15: 0 0 0 0 GICv2 111 Level ohci_hcd:usb4
19: 21 0 0 0 GICv2 63 Level 1c25000.ths
22: 0 0 0 0 GICv2 114 Level eth0
25: 84 0 0 0 GICv2 32 Level ttyS0
26: 0 0 0 0 GICv2 72 Level 1f00000.rtc
29: 0 0 0 0 GICv2 152 Level arm-pmu
30: 0 0 0 0 GICv2 153 Level arm-pmu
31: 0 0 0 0 GICv2 154 Level arm-pmu
32: 0 0 0 0 GICv2 155 Level arm-pmu
103: 0 0 0 0 sunxi_pio_edge 38 Edge 1c0f000.mmc cd
IPI0: 713 1050 35946 629 Rescheduling interrupts
IPI1: 15 492 484 484 Function call interrupts
IPI2: 0 0 0 0 CPU stop interrupts
IPI3: 0 0 0 0 CPU stop (for crash dump) interrupts
IPI4: 0 0 0 0 Timer broadcast interrupts
IPI5: 0 0 0 0 IRQ work interrupts
IPI6: 0 0 0 0 CPU wake-up interrupts
Err: 0
Tâches usuelles d’une routine de traitement d’interruptions
Les tâches typiques d’une routine de traitement
- Quittancer la notification de l’événement sur le périphérique ayant
levé l’interruption, afin d’éviter que les interruptions ne soient
plus générées ou que l’interruption soit levée continuellement
(
deadlock
) - Lire ou écrire les données du ou vers le périphérique
- Réveiller l’éventuel thread en attente de l’évènement, afin qu’il
puisse terminer le traitement de l’information et son opération,
typiquement avec une waitqueue
wake_up_interruptible (&queue);
Contraintes et limitations
La programmation des routines de traitement des interruptions doit toujours être réalisée avec beaucoup de soin. Il en va de même dans le noyau Linux.
- Le temps de traitement dans une interruption doit être limité au minimum. Si le traitement est lourd et complexe, il peut être délégué à une softirq, une workqueue ou depuis la version 2.6.30 à un thread
- Il n’est pas possible de transférer des données avec des applications de l’espace utilisateur
- Il n’est pas possible d’effectuer des opérations nécessitant des mises en sommeil
L’utilisation de fonctions pour autoriser et/ou bloquer les
interruptions (disable_irq
/enable_irq
) doit être évitée au maximum
Traitement des interruptions par thread
Linux propose depuis la version 2.6.30 un mécanisme permettant de traiter les interruptions dans une routine appelée par un thread. Ce mécanisme permet d’avoir des traitements longs non bloquants.
int request_threaded_irq (
unsigned int irq,
irq_handler_t handler,
irq_handler_t thread_fn,
unsigned long flags,
const char * dev_name,
void * dev_id);
irq
→ vecteur d’interruption (numéro).handler
→ routine appelée lorsque l’interruption est levée. Pour passer la main au thread, cette routine retournera la valeurIRQ_WAKE_THREAD
.thread_fn
→ routine de traitement appelée par un thread.flags
→ fanions de gestion des interruptions.dev_name
→ nom du périphérique d’interruption.dev_id
→ paramètre spécifique à l’application (doit impérativement être non nul).
Interface gérée
Il existe également une interface gérée :
devm_request_irq()
devm_free_irq()
devm_request_threaded_irq()