web-dev-qa-db-fra.com

Comment la poignée du noyau Linux est-elle partagée IRQS?

Selon ce que j'ai lu jusqu'à présent, "lorsque le noyau reçoit une interruption, tous les gestionnaires enregistrés sont invoqués."

Je comprends que les gestionnaires enregistrés pour chaque IRQ peuvent être visionnés via /proc/interrupts, et je comprends aussi que les gestionnaires enregistrés proviennent des pilotes qui ont été invoqués request_irq passer dans un rappel brutalement de la forme:

irqreturn_t (*handler)(int, void *)

Sur la base de ce que je sais, chacun de ces raclages de gestionnaire d'interrupteurs associés à l'IRQ concerné doit être invoqué, et il appartient au gestionnaire de déterminer si l'interruption devrait en effet être traitée par elle. Si le gestionnaire ne doit pas gérer l'interruption particulière, il doit renvoyer la macro du noyau IRQ_NONE.

Ce dont j'ai du mal à comprendre, comment chaque pilote devrait déterminer s'il devrait gérer l'interruption ou non. Je suppose qu'ils puissent garder la suivi en interne s'il est censé attendre une interruption. Si tel est le cas, je ne sais pas comment ils seraient en mesure de traiter la situation dans laquelle plusieurs pilotes derrière le même IRQ s'attendent à une interruption.

La raison pour laquelle j'essaie de comprendre ces détails est parce que je suis en train de jouer avec le mécanisme kexec pour réexécuter le noyau au milieu du fonctionnement du système tout en jouant avec les goupilles de réinitialisation et divers registres sur un pont PCIE. ainsi qu'un périphérique PCI en aval. Et ce faisant, après un redémarrage, je reçois de la panique de noyau, ou d'autres conducteurs se plaignent de recevoir des interruptions, même si aucune opération n'avait eu lieu.

Comment le gestionnaire a décidé que l'interruption doit être traitée par elle est le mystère.

Edit: Au cas où il est pertinent, l'architecture de la CPU en question est x86.

14
bsirang

Lorsqu'un pilote demande un IRQ partagé, il passe un pointeur au noyau à une référence à une structure spécifique à un périphérique dans l'espace mémoire du conducteur.

Selon LDD3:

Chaque fois que deux pilotes ou plus partagent une ligne d'interruption et que le matériel interrompt le processeur sur cette ligne, le noyau invoque chaque gestionnaire enregistré pour cette interruption, en passant chacun son propre dev_id.

Lors de la vérification de plusieurs gestionnaires IRQ des pilotes, il apparaît qu'ils sondent le matériel lui-même afin de déterminer si elle devrait ou non gérer l'interruption ou le retour IRQ_NONE.

Exemples

  status = inw(uhci->io_addr + USBSTS);
  if (!(status & ~USBSTS_HCH))  /* shared interrupt, not mine */
    return IRQ_NONE;

Dans le code ci-dessus, le conducteur lit le registre USBSTS enregistre pour déterminer s'il y a une interruption au service.

  intmask = sdhci_readl(Host, SDHCI_INT_STATUS);

  if (!intmask || intmask == 0xffffffff) {
    result = IRQ_NONE;
    goto out;
  }

Tout comme dans l'exemple précédent, le conducteur vérifie un registre d'état, SDHCI_INT_STATUS Pour déterminer s'il doit servir une interruption.

  struct ath5k_softc *sc = dev_id;
  struct ath5k_hw *ah = sc->ah;
  enum ath5k_int status;
  unsigned int counter = 1000;

  if (unlikely(test_bit(ATH_STAT_INVALID, sc->status) ||
        !ath5k_hw_is_intr_pending(ah)))
    return IRQ_NONE;

Juste un autre exemple.

4
bsirang