Maison > Tutoriel système > Linux > Veille du système Linux (System Suspend) et gestion des interruptions de périphérique

Veille du système Linux (System Suspend) et gestion des interruptions de périphérique

WBOY
Libérer: 2024-02-11 19:00:30
avant
1281 Les gens l'ont consulté

Cette section résout principalement un problème : comment suspendre les interruptions de périphérique (IRQ) lorsque le système entre en état de veille ? Comment restaurer l'IRQ de l'appareil lors du réveil du système ?

Normalement, une fois que le système entre en état de veille, l'IRQ (Interrupt Request Line) de tous les appareils sera désactivée. Le moment précis se situe après la phase de suspension tardive de l’appareil. Vous trouverez ci-dessous le code pertinent (code non pertinent omis).

«

static int suspend_enter(suspend_state_t state, bool *wakeup)

{……

error = dpm_suspend_late(PMSG_SUSPEND);----phase de suspension tardive

error = platform_suspend_prepare_late(state);

Le code suivant désactivera l'irq de chaque appareil

error = dpm_suspend_noirq(PMSG_SUSPEND);——Entrer dans l'étape noirq

error = platform_suspend_prepare_noirq(state);

……

}

Dans la fonction dpm_suspend_noirq, device_suspend_noirq sera appelé à tour de rôle pour chaque périphérique du système afin d'exécuter la fonction de rappel de suspension dans le cas de noirq de l'appareil. Bien entendu, la fonction suspend_device_irqs sera appelée avant cela pour désactiver les irqs de tous. dispositifs.

L'idée derrière cela est la suivante : une fois que chaque pilote de périphérique a terminé une suspension tardive, il va de soi que ces périphériques suspendus ne devraient plus déclencher d'interruptions. Si certains périphériques n'ont toujours pas été suspendus correctement, notre meilleure stratégie consiste à masquer l'irq du périphérique pour empêcher la soumission de l'interruption. De plus, dans le code précédent (en référence au gestionnaire d'interruption), nous n'avons pas très bien géré la situation des périphériques partageant l'IRQ. Il existe un tel problème : une fois la suspension complète des périphériques partageant l'IRQ, si une interruption est déclenchée, le périphérique. le pilote le fera. Le gestionnaire d'interruption n'est pas prêt. Dans certains scénarios, le gestionnaire d'interruption accèdera à l'espace d'adressage IO du périphérique suspendu, provoquant des problèmes imprévisibles. Ces problèmes sont difficiles à déboguer, nous avons donc introduit suspend_device_irqs() et la fonction de rappel dans l'étape périphérique noirq.

Pendant le processus de reprise du système, avant le processus de reprise anticipée de chaque appareil, l'IRQ de chaque appareil sera rouverte. Le code spécifique est le suivant (certains codes non pertinents ont été supprimés) :

«

static int suspend_enter(suspend_state_t state, bool *wakeup)

{……

platform_resume_noirq(state);---Exécutez d'abord le CV dans la phase noirq

dpm_resume_noirq(PMSG_RESUME);-----L'irq sera restauré ici, puis entrera dans la phase de reprise anticipée

platform_resume_early(state);

dpm_resume_early(PMSG_RESUME);

……}

Dans la fonction dpm_resume_noirq, le rappel noirq de chaque pilote de périphérique sera appelé. Après cela, la fonction summary_device_irqs est appelée pour terminer l'activation de chaque irq de périphérique.

2. À propos du drapeau IRQF_NO_SUSPEND

Bien sûr, certaines interruptions doivent rester déclenchables pendant le processus de suspension-reprise de l'ensemble du système (y compris pendant la phase noirq, y compris la phase dans laquelle le processeur non amorçable est poussé vers l'état hors ligne et le système est réinitialisé en ligne après le le système reprend). Un exemple simple est l'interruption de minuterie, en plus de l'IPI et de certaines interruptions de périphériques à usage spécial.

Lors d'une demande d'interruption, l'indicateur IRQF_NO_SUSPEND peut être utilisé pour informer le sous-système IRQ. Cette interruption est le type d'interruption décrit dans le paragraphe précédent : elle doit rester activée pendant le processus de suspension-reprise du système. Avec cet indicateur, suspend_device_irqs ne désactivera pas l'IRQ, permettant à l'interruption de rester activée lors des processus de suspension et de reprise ultérieurs. Bien entendu, cela ne garantit pas que l’interruption puisse réveiller le système. Si vous souhaitez atteindre l'objectif de vous réveiller, veuillez appeler activate_irq_wake.

Il est à noter que l'indicateur IRQF_NO_SUSPEND affecte tous les périphériques qui utilisent cette IRQ (une IRQ peut être partagée par plusieurs périphériques, mais cela n'est pas utilisé dans ARM). Si une IRQ est partagée par plusieurs périphériques et que chaque périphérique a enregistré un gestionnaire d'interruption correspondant, et si l'un d'eux utilise l'indicateur IRQF_NO_SUSPEND lors de la demande d'interruption, alors lorsque le système est suspendu (en référence à après suspend_device_irqs), il est raison pour laquelle chaque IRQ a été désactivée), les gestionnaires d'interruption de tous les périphériques sur l'IRQ peuvent être déclenchés et exécutés normalement, même si certains périphériques ne définissent pas l'indicateur IRQF_NO_SUSPEND lors de l'appel de request_irq (ou d'autres fonctions d'enregistrement d'interruption). Pour cette raison, nous devons éviter autant que possible d’utiliser les deux indicateurs IRQF_NO_SUSPEND et IRQF_SHARED en même temps.

3. Interface de réveil d'interruption du système : activate_irq_wake() et Disable_irq_wake()

Certaines interruptions peuvent sortir le système de l'état de veille, que nous appelons « interruptions pouvant réveiller le système ». Bien entendu, les « interruptions pouvant réveiller le système » doivent être configurées pour activer la fonction de réveil du système. De telles interruptions apparaissent généralement comme des interruptions d'E/S ordinaires pendant les conditions de travail. Ce n'est que lors de la préparation de l'activation de la fonction du système de réveil que certaines configurations et paramètres spéciaux seront lancés.

Ces configurations et paramètres peuvent être liés à la logique de traitement du signal sur le système matériel (tel que SOC). Nous pouvons considérer le schéma fonctionnel matériel suivant :

Linux系统休眠(System Suspend)和设备中断处理

Les signaux d'interruption périphériques sont envoyés au « module de traitement du signal d'interruption général » et au « module de réception de signal d'interruption spécifique ». Lorsque nous travaillons normalement, nous activerons la logique de traitement du « module de traitement du signal d'interruption général » et désactiverons la logique de traitement du « module de réception du signal d'interruption spécifique ». Cependant, lorsque le système entre en état de veille, il est possible que le « module de traitement du signal d'interruption général » ait été désactivé. À ce moment-là, nous devons démarrer le « module de réception du signal d'interruption spécifique » pour recevoir le signal d'interruption, de sorte que. le module de suspension-reprise du système (c'est souvent le seul bloc matériel qui peut fonctionner en état suspendu) et peut être réveillé normalement par le signal d'interruption. Une fois réveillé, il est préférable de désactiver le « module de réception du signal d'interruption spécifique » pour permettre au traitement des interruptions périphériques de revenir au mode de fonctionnement normal. En même temps, cela évite également les interférences inutiles avec le module de suspension-reprise du système.

Le sous-système IRQ fournit deux fonctions d'interface pour compléter cette fonction : la fonction activate_irq_wake() est utilisée pour ouvrir la ligne d'interruption périphérique menant au module de gestion de l'alimentation du système (c'est-à-dire le module de suspension-reprise ci-dessus), et une autre interface est Disable_irq_wake(), qui est utilisé pour fermer divers blocs matériels sur le chemin allant de la ligne d'interruption périphérique au module de gestion de l'alimentation du système.

L'appel de activate_irq_wake affectera le traitement suspend_device_irqs dans le processus de suspension du système. Le code est le suivant :

«

static bool suspend_device_irq(struct irq_desc *desc)

{

……

if (irqd_is_wakeup_set(&desc->irq_data)) {

irqd_set(&desc->irq_data, IRQD_WAKEUP_ARMED);

retour vrai ;

}

Omettez le code d'interruption de désactivation

}

En d'autres termes, une fois activate_irq_wake appelé pour définir l'interruption de l'appareil comme source de réveil de la suspension du système, l'interruption dans le périphérique ne sera pas désactivée, mais sera marquée d'un indicateur IRQD_WAKEUP_ARMED. Pour les interruptions qui ne sont pas des sources de réveil, IRQS_SUSPENDED sera marqué dans la fonction suspend_device_irq et l'irq du périphérique sera désactivé. Pendant le processus de réveil du système (resume_device_irqs), les interruptions désactivées seront réactivées.

Bien sûr, si certains événements se produisent pendant le processus de suspension (par exemple, la source de réveil génère un signal valide), entraînant cet abandon de suspension, alors cet événement d'abandon sera également notifié au module principal PM. L'événement n'a pas besoin d'être notifié immédiatement au module principal PM. De manière générale, le thread de suspension vérifiera l'événement de réveil en attente à un moment donné.

Pendant le processus de suspension du système, chaque interruption de la source de réveil mettra fin au processus de suspension ou réveillera le système (si le système est entré dans l'état de suspension). Cependant, après l'exécution de suspend_device_irqs, les interruptions ordinaires sont bloquées. À ce stade, même si le matériel déclenche le signal d'interruption, il ne peut pas exécuter son gestionnaire d'interruption. Qu'arrive-t-il à l'IRQ en tant que source de réveil ? Bien que son interruption n'ait pas été masquée, son gestionnaire d'interruption ne sera pas exécuté (le signal matériel à ce moment n'est utilisé que pour réveiller le système). Les seuls gestionnaires d'interruptions qui ont une chance de s'exécuter sont les IRQ marquées avec l'indicateur IRQF_NO_SUSPEND, car leurs interruptions sont toujours activées. Bien entendu, ces interruptions ne doivent pas appeler activate_irq_wake pour définir la source de réveil.

4. Interruptions et mise en veille

Suspend-to-idle (également connu sous le nom d'état « gel ») est un état de gestion de l'alimentation du système relativement nouveau. Le code correspondant est le suivant :

«

static int suspend_enter(suspend_state_t state, bool *wakeup)

{

……

Étape de suspension tardive de chaque appareil

phase de suspension noirq de chaque appareil

si (état == PM_SUSPEND_FREEZE) {

freeze_enter();

aller à Platform_wake;

}

……

}

Les opérations précédentes de gel et de suspension sont fondamentalement les mêmes : gelez d'abord les processus du système, puis suspendez les différents périphériques du système. La différence est qu'une fois la suspension de noirq terminée, le gel ne désactivera pas ces processus non BSP. . phase de suspension du processeur et de syscore, mais appelle la fonction freeze_enter pour pousser tous les processeurs à l'état inactif. À ce moment-là, toute interruption activée peut réveiller le système. Et cela signifie que ces indicateurs IRQF_NO_SUSPEND (dont l'IRQ n'est pas masqué pendant le processus suspend_device_irqs) sont capables de sortir le processeur de l'état inactif (cependant, il convient de noter que ce signal ne déclenche pas de signal de réveil du système), et les interruptions ordinaires ne peuvent pas réveiller le processeur à l'état inactif car leur IRQ est désactivée.

Qu'en est-il des interruptions de réveil qui peuvent réveiller le système ? Puisque son interruption n'est pas masquée, le système peut également être réveillé de l'état de suspension à veille. L'ensemble du processus est le même que pour réveiller le système de l'état suspendu. La seule différence est : le chemin de traitement d'interruption pour sortir le système de l'état gelé et le chemin de traitement de réveil pour sortir le système de l'état suspendu, nécessitent une gestion spéciale de l’alimentation HW BLOCK. Participation à la logique de gestion des interruptions.

5. L'indicateur IRQF_NO_SUSPEND et la fonction activate_irq_wake ne peuvent pas être utilisés en même temps

Pour un appareil, il est déraisonnable d'utiliser l'indicateur IRQF_NO_SUSPEND lors d'une demande d'interruption et d'appeler Enable_irq_wake pour définir la source de réveil en même temps. Les principales raisons sont les suivantes :

1. Si l'IRQ n'est pas partagée, utilisez l'indicateur IRQF_NO_SUSPEND pour indiquer que vous souhaitez garder l'interruption ouverte pendant le processus de suspension-reprise de l'ensemble du système (y compris l'étape après suspend_device_irqs) afin que son gestionnaire d'interruption puisse être appelé normalement. . L'appel de la fonction activate_irq_wake indique que vous souhaitez définir le signal irq du périphérique comme source d'interruption, vous ne vous attendez donc pas à appeler son gestionnaire d'interruption. Ces deux exigences s’excluent évidemment mutuellement.

2. Ni l'indicateur IRQF_NO_SUSPEND ni la fonction activate_irq_wake ne sont destinés à un seul gestionnaire d'interruption, mais à tous les gestionnaires enregistrés sur l'IRQ. Il est ridicule de partager la source de réveil et la source d'interruption sans suspension sur la même IRQ.

Cependant, dans des circonstances très particulières, une IRQ peut être définie comme source de réveil et l'indicateur IRQF_NO_SUSPEND est également défini. Pour que la logique du code soit correcte, le code du pilote du périphérique doit répondre à certaines exigences particulières.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:lxlinux.net
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal