Как ядро Linux обрабатывает совместно использованный IRQs?

Обычно термин 'консольный терминал' или 'компьютерный терминал' относится только к физическому интерфейсу, части аппаратных средств. Современные операционные системы имеют (часто несколько) виртуальные консоли, которые эмулируют поведение старых стеклянных терминалов (который в свою очередь эмулирует Телетайп http://en.wikipedia.org/wiki/Teleprinter). Существуют части консоли VGA на современном ПК, которые являются программным обеспечением части и аппаратными средствами части (так как OSs как Linux и BSD использует в своих интересах аппаратные средства VGA для отображения вместо того, чтобы представить сами шрифты), но они не то же как старые стеклянные терминалы, которые использовались для чеканки термина 'Терминал'. (см. http://en.wikipedia.org/wiki/VT100, например.)

Каждый виртуальный терминал имеет tty (помните телетайп выше?), и tty то, что используется для текстовой консоли.

Когда дело доходит до вещей как 'графический терминал', если Вы не говорите о псевдотерминалах, используемых в X программах как 'xterm', это - совершенно другая вещь, и 'терминальный' термин становится немного более туманным. У Вас могут быть виртуальные консоли, которые эмулируют виртуальный дисплей VGA, когда Вы выполняете что-то как VirtualBox.

14
26.11.2018, 22:37
3 ответа

Это охвачено в главе 10 Драйверов устройств Linux, 3-го выпуска, Corbet и др. Это доступно бесплатно онлайн, или можно бросить некоторого O'Reilly шекелей путь к мертвому дереву или формам электронной книги. Часть, относящаяся к Вашему вопросу, начинается на странице 278 в первой ссылке.

Если это имеет значение вот моя попытка перефразировать те три страницы плюс другие биты, которые я Погуглил:

  • При регистрации общего обработчика IRQ ядро проверяет что также:

    a. никакой другой обработчик не существует для того прерывания, или

    b. все ранее зарегистрированные также требуемое совместное использование прерывания

    Если любой случай применяется, он затем проверяет что Ваш dev_id параметр уникален, так, чтобы ядро могло дифференцировать несколько обработчиков, например, во время демонтажа обработчика.

  • Когда PCI ¹ устройство повышает линию IRQ, обработчика прерываний ядра низкого уровня называют, и это в свою очередь называет всех зарегистрированных обработчиков прерываний, пасуя назад каждого dev_id Вы раньше регистрировали обработчик через request_irq().

    dev_id оцените должно быть уникальным для машины. Распространенный способ сделать, который должен передать указатель на для каждого устройства struct Ваше использование драйвера для управления тем устройством. Так как этот указатель должен быть в пространстве памяти Вашего драйвера для него, чтобы быть полезным для драйвера, это в силу самого факта уникально для того драйвера. ²

    Если будет несколько драйверов, зарегистрированных для данного прерывания, то их все назовут, когда любое из повышений устройств, которые совместно использовали линию прерывания. Если это не было устройство Вашего драйвера, которое сделало это, обработчик прерываний Вашего драйвера будет передан a dev_id значение, которое не принадлежит ему. Обработчик прерываний Вашего драйвера должен сразу возвратиться, когда это происходит.

    Другой случай - то, что Ваш драйвер управляет несколькими устройствами. Обработчик прерываний драйвера получит один из dev_id значения известны драйверу. Ваш код, как предполагается, опрашивает каждое устройство для обнаружения, какой повысил прерывание.

    Примером, который и др. дают Corbet, является пример параллельного порта ПК. Когда это утверждает линию прерывания, это также устанавливает главный бит в своем первом регистре устройства. (Таким образом, inb(0x378) & 0x80 == true, принятие стандартной нумерации порта I/O.), Когда Ваш обработчик обнаруживает это, он, как предполагается, делает свою работу, затем очищает IRQ путем записи значения, считанного из порта I/O назад к порту с главным очищенным битом.

    Я не вижу оснований, что конкретный механизм является особенным. Другое устройство могло выбрать другой механизм. Единственная важная вещь состоит в том, что, чтобы устройство позволило совместно использованные прерывания, оно должно иметь некоторый путь к драйверу для чтения состояния прерывания устройства и некоторого способа очистить прерывание. Необходимо будет прочитать таблицу данных устройства или руководство по программированию для обнаружения, какой механизм конкретное устройство использует.

  • Когда Ваш обработчик прерываний говорит ядру, что это обработало прерывание, которое не мешает ядру продолжить называть любые другие обработчики зарегистрированными для того же самого прерывания. Это неизбежно, если необходимо совместно использовать линию прерывания при использовании инициированных уровнем прерываний.

    Предположите, что два устройства утверждают ту же линию прерывания одновременно. (Или по крайней мере, так закройтесь вовремя, что ядро не имеет времени для вызова обработчика прерываний, чтобы очистить строку и таким образом рассматривать второе утверждение как отдельное.) Ядро должно назвать все обработчики для той линии прерывания, чтобы дать каждому шанс запросить его связанные аппаратные средства, чтобы видеть, необходимо уделять внимание ли этому. Для двух различных драйверов довольно возможно успешно обработать прерывание в том же, проходят через список обработчика для данного прерывания.

    Из-за этого обязательно, чтобы Ваш драйвер сказал устройству, что этому удается очистить его утверждение прерывания когда-то перед возвратами обработчика прерываний. Мне не ясно, что происходит иначе. Непрерывно утверждаемая линия прерывания будет или приводить к ядру, непрерывно называя общих обработчиков прерываний, или это замаскирует способность ядра видеть новые прерывания, таким образом, обработчики никогда не будут называть. Так или иначе, авария.


Сноски:

  1. Я указал PCI выше, потому что все вышеупомянутое принимает инициированные уровнем прерывания, как используется в исходной спецификации PCI. ISA использовал инициированные фронтом сигнала прерывания, которые сделали совместное использование хитрого в лучшем случае и возможного даже затем только при поддержке аппаратными средствами. PCIe использует сообщенные сообщению прерывания; сообщение прерывания содержит уникальное значение, которое ядро может использовать для предотвращения циклической игры предположения, требуемой с совместным использованием прерывания PCI. PCIe может избавить от самой необходимости совместное использование прерывания. (Я не знаю, делает ли это на самом деле, просто что это имеет потенциал к.)

  2. Драйверы ядра Linux вся доля то же пространство памяти, но несвязанный драйвер, как предполагается, не слоняется без дела в чьем-либо пространстве памяти. Если Вы не раздаете тот указатель, можно быть вполне уверены, другой драйвер не собирается придумывать то же самое значение случайно самостоятельно.

14
27.01.2020, 19:51
  • 1
    Как Вы упомянутый, обработчик прерываний может быть передан a dev_id то, что это не владеет. Мне кажется, что существует ненулевой шанс, что драйвер, который не владеет dev_id структура может все еще перепутать его как свое собственное на основе того, как это интерпретирует содержание. Если бы дело обстоит не так затем, какой механизм предотвратил бы это? –  bsirang 07.09.2012, 00:07
  • 2
    Вы предотвращаете его путем создания dev_id указатель на что-то в пространстве памяти Вашего драйвера. Другой драйвер мог составить a dev_id значение, которое, оказалось, было с трудом различимым с указателем на память Ваш драйвер, владеет, но это не собирается происходить, потому что все играют по правилам. Это - пространство ядра, помните: самодисциплина принята как само собой разумеющееся, в отличие от этого, с кодом пространства пользователя, который может беспечно предположить, что что-либо не запрещенное позволяется. –  Warren Young 07.09.2012, 00:24
  • 3
    Согласно главе десять из LDD3: "Каждый раз, когда два или больше драйвера совместно используют линию прерывания и аппаратные прерывания процессор на той строке, ядро вызывает каждый обработчик, зарегистрированный для того прерывания, передавая каждый его собственный dev_id", кажется, что предыдущее понимание было неправильным относительно того, может ли обработчик прерываний быть передан в a dev_id то, что это не владеет. –  bsirang 07.09.2012, 02:34
  • 4
    Это было неправильно читавшим с моей стороны. Когда я записал, что, объединял два понятия. Я отредактировал свой ответ. Условие, которое требует, чтобы Ваш обработчик прерываний возвратился быстро, состоит в том, что это называет из-за утверждения прерывания устройство, которым это не управляет. Значение dev_id не помогает Вам определить, произошло ли это. Необходимо ли спросить аппаратные средства, "Вы звонили?" –  Warren Young 07.09.2012, 02:50
  • 5
    Да, теперь я должен выяснить, как то, что я переделываю, на самом деле заставляет другие драйверы полагать, что их устройства "звонили" после перезапуска ядра через kexec. –  bsirang 07.09.2012, 03:20

Когда драйвер запрашивает общий 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;

Просто еще один пример.

4
27.01.2020, 19:51

Пожалуйста, посетите эту ссылку:

Обычная практика состоит в том, чтобы запускать нижние шлемы или любую другую логику в обработчике IRQ только после проверки статуса IRQ из регистра, отображенного в памяти. Следовательно, проблема по умолчанию решается хорошим программистом.

0
27.01.2020, 19:51

Теги

Похожие вопросы