Linux 커널은 공유 IRQ를 어떻게 처리합니까?

Linux 커널은 공유 IRQ를 어떻게 처리합니까?

지금까지 읽은 내용에 따르면 "커널이 인터럽트를 받으면 등록된 모든 핸들러가 호출됩니다."

내가 아는 한, 각 IRQ에 대해 등록된 핸들러를 볼 수 있으며 , 등록된 핸들러는 대략 다음과 같은 형식의 콜백을 전달하는 드라이버 /proc/interrupts에서 온다는 것도 알고 있습니다 .request_irq

irqreturn_t (*handler)(int, void *)

내가 아는 한, 특정 IRQ와 관련된 각 인터럽트 핸들러 콜백은 호출되어야 하며, 인터럽트가 실제로 처리되어야 하는지 여부를 결정하는 것은 핸들러의 몫입니다. 핸들러가 특정 인터럽트를 처리하지 않아야 하는 경우 커널 매크로를 반환해야 합니다 IRQ_NONE.

내가 이해할 수 없는 것은 각 드라이버가 인터럽트를 처리해야 하는지 여부를 어떻게 결정하는지입니다. 인터럽트를 기다려야 한다면 내부적으로 추적할 수 있을 것 같아요. 그렇다면 동일한 IRQ 뒤에서 인터럽트를 기다리는 여러 드라이버의 상황을 어떻게 처리할 수 있는지 모르겠습니다.

제가 이러한 세부 사항을 이해하려고 노력하는 이유는 kexecPCIe 브리지 및 다운스트림 PCI의 재설정 핀과 다양한 레지스터를 다루면서 시스템 작동 중에 커널을 다시 실행하는 메커니즘을 엉망으로 만들고 있기 때문입니다. 장비. 이렇게 하면 재부팅한 후 커널 패닉이 발생하거나 아무 조치도 취하지 않았는데도 인터럽트를 받았다고 불평하는 다른 드라이버가 발생합니다.

핸들러가 어떤 인터럽트를 처리해야 하는지 결정하는 방법은 미스터리입니다.

편집: 관련이 있는 경우 문제의 CPU 아키텍처는 x86.

답변1

이 내용은 다음과 같습니다제10장~의리눅스 장치 드라이버, 3판, Corbet et al. 무료로온라인, 또는 할 수 있습니다O'Reilly 방식으로 셰켈을 투자하세요.죽은 나무 또는 전자책 형식의 경우. 귀하의 질문과 관련된 섹션은 첫 번째 링크의 278페이지에서 시작됩니다.

그만한 가치가 있는 것에 대해 Google에서 찾은 다른 내용과 함께 다음 세 페이지에 대한 나의 시도는 다음과 같습니다.

  • 공유 IRQ 핸들러를 등록하면 커널은 다음을 확인합니다.

    ㅏ. 이 인터럽트에 대한 다른 핸들러가 존재하지 않습니다.

    b. 이전에 등록된 모든 것반품공유 중단 요청

dev_id두 경우 모두 적용되는 경우 커널이 예를 들어 핸들러 제거 중에 여러 핸들러를 구별할 수 있도록 매개변수가 고유한지 확인합니다 .

  • PCI1 하드웨어 장치가 IRQ 라인을 발행하면 커널의 저수준 인터럽트 핸들러가 호출되고 차례로모두등록된 인터럽트 핸들러는 각 반환을 dev_id등록된 핸들러에 전달합니다 request_irq().

dev_id은 시스템마다 고유해야 합니다. 일반적인 접근 방식은 struct드라이버가 장치를 관리하는 데 사용하는 각 장치에 포인터를 전달하는 것입니다. 이 포인터는 드라이버에 유용하려면 드라이버의 메모리 공간 내에 있어야 하므로그 자체이 드라이버에 고유합니다. ²

특정 인터럽트에 대해 여러 드라이버가 등록된 경우모두전화했을 때어느장치는 공유 인터럽트 라인을 발생시킵니다. 드라이버가 아닌 다른 장치가 이 작업을 수행하는 경우 드라이버의 인터럽트 핸들러는 이를 감지하고 IRQ_NONE즉시 반환해야 합니다.

또 다른 상황은 드라이버가 여러 장치를 관리하고 있다는 것입니다. 드라이버의 인터럽트 처리기를 사용하여 dev_id폴링할 장치를 결정해야 합니다.

코벳의 예외.주어진 PC 병렬 포트의 포트입니다. 인터럽트 라인을 지정하면 첫 번째 장치 레지스터에서 가장 높은 비트도 설정됩니다. (즉 inb(0x378) & 0x80 == true, 표준 I/O 포트 번호를 가정합니다.) 핸들러가 이를 감지하면 해당 작업을 수행한 다음 I/O 포트에서 읽은 값을 다시 최상위 포트에 기록하여 IRQ를 지워야 합니다. 조금 클리어됨.

특별한 특별한 메커니즘은 보이지 않습니다. 다양한 하드웨어 장치는 다양한 메커니즘을 선택할 수 있습니다. 유일한 중요한 점은 장치가 공유 인터럽트를 허용하려면 드라이버가 이를 수행할 수 있는 방법이 있어야 한다는 것입니다.읽다장치의 인터럽트 상태 및 일부 방법분명한방해하다. 특정 장치에서 사용되는 메커니즘을 이해하려면 장치의 데이터 시트나 프로그래밍 설명서를 읽어야 합니다.

  • 인터럽트 핸들러가 커널에 인터럽트를 처리했음을 알릴 때 커널이 동일한 인터럽트에 등록된 다른 핸들러를 계속 호출하는 것을 막지는 못합니다. 레벨 트리거 인터럽트를 사용할 때 인터럽트 라인을 공유하는 경우 이는 불가피합니다.

동시에 동일한 인터럽트 라인을 어설션하는 두 장치를 상상해 보십시오. (또는 적어도 시간이 너무 가까워서 커널이 라인을 지우기 위해 인터럽트 핸들러를 호출할 시간이 없으므로 두 번째 주장을 별도의 것으로 처리합니다.) 커널은 각 기회를 제공하기 위해 해당 인터럽트 라인에 대한 모든 핸들러를 호출해야 합니다. 관련 하드웨어를 쿼리하여 주의가 필요한지 확인합니다. 주어진 인터럽트에 대해 두 개의 서로 다른 드라이버가 동일한 핸들러 목록에서 인터럽트를 성공적으로 처리할 가능성이 매우 높습니다.

따라서 드라이버는 인터럽트 핸들러가 반환되기 전에 인터럽트 어설션을 지우려고 한다는 것을 장치에 알려야 합니다. 그렇지 않으면 무슨 일이 일어날지 모르겠습니다. 지속적으로 어설션된 인터럽트 라인은 커널이 공유 인터럽트 핸들러를 계속 호출하게 하거나 커널이 새로운 인터럽트를 볼 수 있는 기능을 차단하므로 핸들러가 호출되지 않습니다. 어느 쪽이든 그것은 재앙이다.


각주:

  1. 위의 모든 내용은 가정하기 때문에 위에서 PCI를 지정했습니다.레벨이 트리거됨원래 PCI 사양에 사용된 인터럽트입니다. ISA 사용엣지 트리거이는 기껏해야 공유를 까다롭게 만들고 심지어 하드웨어가 이를 지원하는 경우에만 가능합니다. PCIe 목적메시지 신호인터럽트: 인터럽트 메시지에는 PCI 인터럽트 공유에 필요한 루프 추측 게임을 피하기 위해 커널이 사용할 수 있는 고유한 값이 포함되어 있습니다. PCIe를 사용하면 인터럽트 공유가 필요하지 않을 수 있습니다. (실제로 그런지는 모르겠지만 잠재력이 있다는 것뿐입니다.)

  2. Linux 커널 드라이버는 모두 동일한 메모리 공간을 공유하지만, 관련되지 않은 드라이버는 다른 드라이버의 메모리 공간을 어지럽혀서는 안 됩니다. 해당 포인터를 전달하지 않는 한, 다른 드라이버가 실수로 자체적으로 동일한 값을 제시하지 않을 것이라고 확신할 수 있습니다.

답변2

드라이버가 공유 IRQ를 요청하면 드라이버는 커널에 대한 포인터와 드라이버 메모리 공간 내의 장치별 구조에 대한 참조를 전달합니다.

LDD3에 따르면:

둘 이상의 드라이버가 인터럽트 라인을 공유하고 하드웨어가 해당 라인의 프로세서를 인터럽트할 때마다 커널은 해당 인터럽트에 등록된 각 핸들러를 호출하여 각 핸들러에 자체 dev_id를 전달합니다.

여러 드라이버의 IRQ 처리기를 확인한 후 하드웨어 자체를 조사하여 인터럽트를 처리해야 하는지 아니면 반환해야 하는지 결정하는 것으로 보입니다 IRQ_NONE.

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

위의 코드에서 드라이버는 USBSTS서비스가 필요한 인터럽트가 있는지 확인하기 위해 레지스터를 읽고 있습니다.

SDHCI 드라이버
  intmask = sdhci_readl(host, SDHCI_INT_STATUS);

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

이전 예에서와 같이 드라이버는 SDHCI_INT_STATUS인터럽트를 처리해야 하는지 결정하기 위해 상태 레지스터를 확인합니다.

Ath5k 드라이버
  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;

또 다른 예를 들어보겠습니다.

답변3

이를 확인하시려면 방문해주세요협회:

메모리 매핑된 레지스터에서 IRQ 상태를 확인한 후에만 IRQ 처리기의 하위 절반 또는 다른 논리를 트리거하는 것이 일반적인 관행입니다. 따라서 이 문제는 기본적으로 좋은 프로그래머에 의해 해결됩니다.

관련 정보