message signaled interrupts что это

Message Signaled Interrupts

1. Об этом руководстве

В этом руководстве описаны основы Message Signaled Interrupts (MSIs), преимущества использования MSI, по сравнению с традиционным механизмом прерываний, как изменить Ваш драйвер, что бы он использовал MSI или MSI-X и некоторые методы диагностики, для определения причины, почему устройство не поддерживает MSI.

Возможности MSI впервые были определены в стандарте PCI 2.2 и, позднее, были доработаны в PCI 3.0 для того, что бы можно было индивидуально маскировать каждое MSI прерывание. Возможности MSI-X так же были добавлены в версии 3.0. Каждое устройство теперь может иметь большее число прерываний по сравнению с PCI и позволяет независимо настраивать каждое прерывание.

Устройство может поддерживать как MSI, так и MSI-X, но в любой момент времени может быть доступен только один из этих режимов.

Использование MSI может дать три преимущества, по сравнению с использованием традиционной технологии линий прерывания.

Линии прерывания зачастую разделяются между несколькими устройствами. Для того, что бы обеспечить обработку разделяемых прерываний, ядро вынуждено вызывать поочерёдно все обработчики прерываний, связанный с этим прерыванием, что приводит к снижению производительности системы в целом. MSI никогда не разделяются, так что эта проблема не возникает.

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

Во время аппаратной инициализации, PCI устройства настраиваются на использование классических прерываний. Переключить устройство на использование MSI или MSI-X должен драйвер устройства. Не все архитектуры поддерживают MSI и на таких машинах, вызов API функций, описанных ниже, завершится ошибкой и устройство продолжит работать в классическом режиме линий прерывания.

4.1 Включаем поддержку ядра для MSI

Для того, что бы ядро Linux поддерживало MSI, необходимо собрать его с включённой опцией CONFIG_PCI_MSI. Эта опция доступна не на всех архитектурах и она может зависеть от некоторых других опций, которые тоже должны быть установлены. Например, для х86 необходимо включить опцию X86_UP_APIC или SMP для того, что бы сделать доступной опцию CONFIG_PCI_MSI.

4.2 Используем MSI

Самая тяжёлая часть работы для драйвера делается PCI-уровнем ядра. Он должен просто запросить PCI-уровень ядра установить поддержку возможностей MSI для данного устройства.

4.2.1 pci_enable_msi

Успешный вызов этой функции выделит ОДНО прерывание устройству, независимо от того, как много MSI способно обслуживать устройство. Устройство при этом будет переключено в режим MSI. Поле dev->irq, хранящее номер прерывания, будет изменено на новый номер, который будет предоставлен MSI. Эта функция должна быт вызвана до того, как драйвер вызовет request_irq() так как включение MSI запрещает линии IRQ и драйвер не получит прерываний от старых прерываний.

4.2.2 pci_enable_msi_block

Этот вариант вызова, описанного выше, позволяет драйверу устройства запросить множество MSI. Спецификация MSI позволяет выделять прерывания в количестве, равном степени двойки, до 2^5 = 32.

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

Драйвер устройства должен решить, что делать, в случае, если pci_enable_msi_block() вернула значение, меньшее, чем запрошенный count. Некоторые устройства могут использовать меньше прерываний, чем тот максимум, который они запросили; в этом случае драйвер должен вновь вызвать pci_enable_msi_block(). Следует отметить, что успех не гарантируется, даже если значение count уменьшено до значения. которое вернул предыдущий вызов pci_enable_msi_block(). Это возможно потому, что существует множество ограничений на количество векторов прерываний, которое может выделить система; pci_enable_msi_block() будет возвращать такое значение до тех пор, пока некоторые ограничения не позволяют успешно завершить вызов.

4.2.3 pci_disable_msi

Эта функция используется для отмены действия pci_enable_msi() или pci_enable_msi_block(). Её вызов восстанавливает значение dev->irq записывая туда номер IRQ и освобождает ранее выделенные MSI. В дальнейшем эти прерывания могут быть назначены другому устройству, поэтому драйвер не должен запоминать это эти значения.

Драйвер устройства обязательно должен вызывать free_irq() для тех прерываний, для которых он вызывал request_irq() ДО вызова этой функции. При неудаче устройство останется в режиме MSI и его вектора будут потеряны. Будет выполнен отладочный вызов BUG_ON().

4.3 Использование MSI-X

MCI-X предоставляет намного более гибкие возможности, чем MSI. Она поддерживает до 2048 прерываний, каждое из которых может управляться независимо от других. Для поддержания такой гибкости, драйвер должен использовать массив структур struct msix_entry :

Это позволяет драйверу использовать разряженные номера прерываний. Например, он может использовать номера 3 и 1027 и выделить место всего под двухэлементный массив. Предполагается, что драйвер заполнит поля entry каждого элемента массива, значениями указывающими, какие номера прерываний он желает что бы ядро выделило для устройства. Ошибкой будет указание двух одинаковых значений поля entry в разных элементах массива.

4.3.1 pci_enable_msix

Вызов этой функции запрашивает у PCI-подсистемы ядра выделить nvec MSI прерываний. Аргумент entries указывает на массив структур типа msix_entry который должен имет размер не менее nvec. При успешном завершении функция вернет 0 и устройство будет переключено в режим MSI-X прерываний. В каждом элементе массива структур, поле vector получит соответствующий номер прерывания. После этого драйвер должен вызвать request_irq() для каждого значения vector, которое он собирается использовать.

Читайте также:  lemlem что за бренд

Если эта функция вернула отрицательное значение, то это указывает на ошибку и драйвер не должен больше пытаться выделять MSI-X прерывания для данного устройства. Если он вернул положительное число, то оно указывает на максимальный номер вектора прерывания, который был выделен системой. См. пример ниже.

В противоположность pci_enable_msi() эта функция НЕ настраивает dev->irq. Устройство перестанет генерировать прерывания по этому номеру прерывания, при включении режима MSI-X. Драйвер устройства отвечает за отслеживание прерываний, назначенных MSI-X векторам для того, что бы он мог, в последствии, освободить их позднее.

Во время фазы инициализации, драйвер устройства должен вызвать эту функцию однократно для каждого устройства.

Идеально будет, если драйвер способен работать с разными номерами MSI-X прерываний, так есть много причин, по которым разные платформы окажутся не в состоянии выделить именно те номера, которые запросил драйвер.

Цикл запроса прерываний, решающий эту задачу, может выглядеть следующим образом:

4.3.2 pci_disable_msix

Эта функция API должна использоваться для отмены результатов действия pci_enable_msix(). Она осовбождает ранее выделенные MSI прерывания. В последствии, эти прерывания могут быть назначены другому устройству, поэтому драйвер не должен хранить и использовать значения поля vector после вызова pci_disable_msix().

Драйвер устройства обязательно должен вызывать free_irq() для всех прерываний, для которых он делал вызов request_irq(), перед вызовом этой функции. Иначе возникнет ошибка, результатом которой будет отладочная печать в BUG_ON(), устройство выйдет из режима MSI и вектор будет потерян.

4.3.3 Таблица MSI-X

В элементе MSI-X capability указывается BAR и смещение для указания на таблицу MSI-X. Этот адрес устанавливается PCI подсистемой ядра и не должен использоваться напрямую драйвером устройства. Если драйвер намеревается маскировать / размаскировать некотрое прерывание, то он должен делать это вызывая disable_irq() / enable_irq().

4.4 Управление устройствами, в которых реализовано как MSI так и MSI-X

4.5.1 Выбор между MSI-X и MSI

Если Ваше устройство поддерживает и MSI и MSI-X, предпочтительно, что бы Вы использовали возможности MSI-X. Как упоминалось выше, MSI-X поддерживает любое количество номеров прерываний от 1 до 2048. В то время, как MSI ограничен 32 прерываниями. Кроме того, так как вектора прерываний MSI должны быть расположены последовательно, система, возможно, окажется не в состоянии выделить так много векторов MSI, как для MSI-X. На некоторых платформах, все MSI прерывания передаются на один набор процессоров, тогда как все прерывания MSI-X могут быть нацелены на различные ЦП.

4.5.2 Spinlocks

Большинство драйверов устройств имеют спинлоки, связанные с каждым устройством, которые захватываются обработчиком прерываний. При работе с линиями прерывания или единственным прерыванием MSI, нет необходимости запрещать прерывания (ядро Linux гарантирует, что одно и тоже прерывание не будет повторно входимым). Если же устройство работает с множеством прерываний, то драйвер должен запретить прерывания пока сохраняется блокировка. Если устройство пошлет другое прерывание, драйвер войдет в клинч, пытаясь рекурсивно получить спинлок.

Есть два решения. Первое заключается в использовании вызовов функций API spin_lock_irqsave() или spin_lock_irq() (Смотри Documentation/DocBook/kernel-locking). Второе заключается в использовании флага IRQF_DISABLED при вызове request_irq(), так что ядро будет запускать обработчик прерываний при запрещённых прерываниях.

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

5.Проблемы MSI

Некоторые чипсеты PCI или устройства, как известно, не поддерживают MSI. Стек PCI предоставляет три метода для запрета MSI :

5.1. Глобальный запрет MSI

Некоторые чипсеты не поддерживают совсем или поддерживают MSI неправильно. Если Вам повезет, то производитель, знающий об этом, отметит это в таблице ACPI FADT. В этом случае, ядро Linux автоматически запретит MSI. Некоторые платы не включают эту информацию в таблицу и тогда мы должны определять это самостоятельно. Наиболее полный список таких плат можно найти рядом с функцией quirk_disable_all_msi() в файле drivers/pci/quirks.c.

5.2. Запрет MSI ниже моста

Некоторые мосты не способны правильно направлять MSI между ветвями. В этом случае необходимо запретить MSI для всех устройств за этим мостом.

Для запрета MSI выдайте команду echo 0 вместо 1. Выполнять такие действия необходимо с осторожностью, так как они могут нарушить обработку прерываний у всех устройств, расположенных ниже моста.

Повторяю, пожалуйста, сообщите о всех мостах, которым требуется специальное управление, по адресу linux-pci@vger.kernel.org.

5.3. Запрет MSI на одном устройстве

Известно, что на некоторых устройствах MSI реализован с ошибками. Обычно, такие устройства управляются индивидуальными драйверами, но иногда необходимо управлять ими с помощью различных уловок. Некоторые драйверы имеют опцию для запрета MSI. Хотя это является простейшим выходом для разработчика драйвера, нельзя признать это хорошей идеей и не следует подражать такому решению.

5.4. Определение причины запрета MSI на устройстве

Из трёх предыдущих разделов Вы могли увидеть, что есть множество причин, по которым MSI отключен на данном устройстве. Вашим первым шагом должна быть внимательная проверка файла dmesg для выяснения того, включены ли MSI на Вашей машине. Кроме того, Вам необходимо проверить файл .config и убедится, что опция CONFIG_PCI_MSI включена.

Полезно так же проверить сам драйвер, что бы выяснить, поддерживает ли он MSI. Такой драйвер должен содержать вызовы функций pci_enable_msi(), pci_enable_msix() or pci_enable_msi_block().

Источник

Читайте также:  jasmin tv что за канал

Message Signaled Interrupts

1. Об этом руководстве

В этом руководстве описаны основы Message Signaled Interrupts (MSIs), преимущества использования MSI, по сравнению с традиционным механизмом прерываний, как изменить Ваш драйвер, что бы он использовал MSI или MSI-X и некоторые методы диагностики, для определения причины, почему устройство не поддерживает MSI.

Возможности MSI впервые были определены в стандарте PCI 2.2 и, позднее, были доработаны в PCI 3.0 для того, что бы можно было индивидуально маскировать каждое MSI прерывание. Возможности MSI-X так же были добавлены в версии 3.0. Каждое устройство теперь может иметь большее число прерываний по сравнению с PCI и позволяет независимо настраивать каждое прерывание.

Устройство может поддерживать как MSI, так и MSI-X, но в любой момент времени может быть доступен только один из этих режимов.

Использование MSI может дать три преимущества, по сравнению с использованием традиционной технологии линий прерывания.

Линии прерывания зачастую разделяются между несколькими устройствами. Для того, что бы обеспечить обработку разделяемых прерываний, ядро вынуждено вызывать поочерёдно все обработчики прерываний, связанный с этим прерыванием, что приводит к снижению производительности системы в целом. MSI никогда не разделяются, так что эта проблема не возникает.

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

Во время аппаратной инициализации, PCI устройства настраиваются на использование классических прерываний. Переключить устройство на использование MSI или MSI-X должен драйвер устройства. Не все архитектуры поддерживают MSI и на таких машинах, вызов API функций, описанных ниже, завершится ошибкой и устройство продолжит работать в классическом режиме линий прерывания.

4.1 Включаем поддержку ядра для MSI

Для того, что бы ядро Linux поддерживало MSI, необходимо собрать его с включённой опцией CONFIG_PCI_MSI. Эта опция доступна не на всех архитектурах и она может зависеть от некоторых других опций, которые тоже должны быть установлены. Например, для х86 необходимо включить опцию X86_UP_APIC или SMP для того, что бы сделать доступной опцию CONFIG_PCI_MSI.

4.2 Используем MSI

Самая тяжёлая часть работы для драйвера делается PCI-уровнем ядра. Он должен просто запросить PCI-уровень ядра установить поддержку возможностей MSI для данного устройства.

4.2.1 pci_enable_msi

Успешный вызов этой функции выделит ОДНО прерывание устройству, независимо от того, как много MSI способно обслуживать устройство. Устройство при этом будет переключено в режим MSI. Поле dev->irq, хранящее номер прерывания, будет изменено на новый номер, который будет предоставлен MSI. Эта функция должна быт вызвана до того, как драйвер вызовет request_irq() так как включение MSI запрещает линии IRQ и драйвер не получит прерываний от старых прерываний.

4.2.2 pci_enable_msi_block

Этот вариант вызова, описанного выше, позволяет драйверу устройства запросить множество MSI. Спецификация MSI позволяет выделять прерывания в количестве, равном степени двойки, до 2^5 = 32.

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

Драйвер устройства должен решить, что делать, в случае, если pci_enable_msi_block() вернула значение, меньшее, чем запрошенный count. Некоторые устройства могут использовать меньше прерываний, чем тот максимум, который они запросили; в этом случае драйвер должен вновь вызвать pci_enable_msi_block(). Следует отметить, что успех не гарантируется, даже если значение count уменьшено до значения. которое вернул предыдущий вызов pci_enable_msi_block(). Это возможно потому, что существует множество ограничений на количество векторов прерываний, которое может выделить система; pci_enable_msi_block() будет возвращать такое значение до тех пор, пока некоторые ограничения не позволяют успешно завершить вызов.

4.2.3 pci_disable_msi

Эта функция используется для отмены действия pci_enable_msi() или pci_enable_msi_block(). Её вызов восстанавливает значение dev->irq записывая туда номер IRQ и освобождает ранее выделенные MSI. В дальнейшем эти прерывания могут быть назначены другому устройству, поэтому драйвер не должен запоминать это эти значения.

Драйвер устройства обязательно должен вызывать free_irq() для тех прерываний, для которых он вызывал request_irq() ДО вызова этой функции. При неудаче устройство останется в режиме MSI и его вектора будут потеряны. Будет выполнен отладочный вызов BUG_ON().

4.3 Использование MSI-X

MCI-X предоставляет намного более гибкие возможности, чем MSI. Она поддерживает до 2048 прерываний, каждое из которых может управляться независимо от других. Для поддержания такой гибкости, драйвер должен использовать массив структур struct msix_entry :

Это позволяет драйверу использовать разряженные номера прерываний. Например, он может использовать номера 3 и 1027 и выделить место всего под двухэлементный массив. Предполагается, что драйвер заполнит поля entry каждого элемента массива, значениями указывающими, какие номера прерываний он желает что бы ядро выделило для устройства. Ошибкой будет указание двух одинаковых значений поля entry в разных элементах массива.

4.3.1 pci_enable_msix

Вызов этой функции запрашивает у PCI-подсистемы ядра выделить nvec MSI прерываний. Аргумент entries указывает на массив структур типа msix_entry который должен имет размер не менее nvec. При успешном завершении функция вернет 0 и устройство будет переключено в режим MSI-X прерываний. В каждом элементе массива структур, поле vector получит соответствующий номер прерывания. После этого драйвер должен вызвать request_irq() для каждого значения vector, которое он собирается использовать.

Читайте также:  что делать если встретился с шаровой молнией

Если эта функция вернула отрицательное значение, то это указывает на ошибку и драйвер не должен больше пытаться выделять MSI-X прерывания для данного устройства. Если он вернул положительное число, то оно указывает на максимальный номер вектора прерывания, который был выделен системой. См. пример ниже.

В противоположность pci_enable_msi() эта функция НЕ настраивает dev->irq. Устройство перестанет генерировать прерывания по этому номеру прерывания, при включении режима MSI-X. Драйвер устройства отвечает за отслеживание прерываний, назначенных MSI-X векторам для того, что бы он мог, в последствии, освободить их позднее.

Во время фазы инициализации, драйвер устройства должен вызвать эту функцию однократно для каждого устройства.

Идеально будет, если драйвер способен работать с разными номерами MSI-X прерываний, так есть много причин, по которым разные платформы окажутся не в состоянии выделить именно те номера, которые запросил драйвер.

Цикл запроса прерываний, решающий эту задачу, может выглядеть следующим образом:

4.3.2 pci_disable_msix

Эта функция API должна использоваться для отмены результатов действия pci_enable_msix(). Она осовбождает ранее выделенные MSI прерывания. В последствии, эти прерывания могут быть назначены другому устройству, поэтому драйвер не должен хранить и использовать значения поля vector после вызова pci_disable_msix().

Драйвер устройства обязательно должен вызывать free_irq() для всех прерываний, для которых он делал вызов request_irq(), перед вызовом этой функции. Иначе возникнет ошибка, результатом которой будет отладочная печать в BUG_ON(), устройство выйдет из режима MSI и вектор будет потерян.

4.3.3 Таблица MSI-X

В элементе MSI-X capability указывается BAR и смещение для указания на таблицу MSI-X. Этот адрес устанавливается PCI подсистемой ядра и не должен использоваться напрямую драйвером устройства. Если драйвер намеревается маскировать / размаскировать некотрое прерывание, то он должен делать это вызывая disable_irq() / enable_irq().

4.4 Управление устройствами, в которых реализовано как MSI так и MSI-X

4.5.1 Выбор между MSI-X и MSI

Если Ваше устройство поддерживает и MSI и MSI-X, предпочтительно, что бы Вы использовали возможности MSI-X. Как упоминалось выше, MSI-X поддерживает любое количество номеров прерываний от 1 до 2048. В то время, как MSI ограничен 32 прерываниями. Кроме того, так как вектора прерываний MSI должны быть расположены последовательно, система, возможно, окажется не в состоянии выделить так много векторов MSI, как для MSI-X. На некоторых платформах, все MSI прерывания передаются на один набор процессоров, тогда как все прерывания MSI-X могут быть нацелены на различные ЦП.

4.5.2 Spinlocks

Большинство драйверов устройств имеют спинлоки, связанные с каждым устройством, которые захватываются обработчиком прерываний. При работе с линиями прерывания или единственным прерыванием MSI, нет необходимости запрещать прерывания (ядро Linux гарантирует, что одно и тоже прерывание не будет повторно входимым). Если же устройство работает с множеством прерываний, то драйвер должен запретить прерывания пока сохраняется блокировка. Если устройство пошлет другое прерывание, драйвер войдет в клинч, пытаясь рекурсивно получить спинлок.

Есть два решения. Первое заключается в использовании вызовов функций API spin_lock_irqsave() или spin_lock_irq() (Смотри Documentation/DocBook/kernel-locking). Второе заключается в использовании флага IRQF_DISABLED при вызове request_irq(), так что ядро будет запускать обработчик прерываний при запрещённых прерываниях.

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

5.Проблемы MSI

Некоторые чипсеты PCI или устройства, как известно, не поддерживают MSI. Стек PCI предоставляет три метода для запрета MSI :

5.1. Глобальный запрет MSI

Некоторые чипсеты не поддерживают совсем или поддерживают MSI неправильно. Если Вам повезет, то производитель, знающий об этом, отметит это в таблице ACPI FADT. В этом случае, ядро Linux автоматически запретит MSI. Некоторые платы не включают эту информацию в таблицу и тогда мы должны определять это самостоятельно. Наиболее полный список таких плат можно найти рядом с функцией quirk_disable_all_msi() в файле drivers/pci/quirks.c.

5.2. Запрет MSI ниже моста

Некоторые мосты не способны правильно направлять MSI между ветвями. В этом случае необходимо запретить MSI для всех устройств за этим мостом.

Для запрета MSI выдайте команду echo 0 вместо 1. Выполнять такие действия необходимо с осторожностью, так как они могут нарушить обработку прерываний у всех устройств, расположенных ниже моста.

Повторяю, пожалуйста, сообщите о всех мостах, которым требуется специальное управление, по адресу linux-pci@vger.kernel.org.

5.3. Запрет MSI на одном устройстве

Известно, что на некоторых устройствах MSI реализован с ошибками. Обычно, такие устройства управляются индивидуальными драйверами, но иногда необходимо управлять ими с помощью различных уловок. Некоторые драйверы имеют опцию для запрета MSI. Хотя это является простейшим выходом для разработчика драйвера, нельзя признать это хорошей идеей и не следует подражать такому решению.

5.4. Определение причины запрета MSI на устройстве

Из трёх предыдущих разделов Вы могли увидеть, что есть множество причин, по которым MSI отключен на данном устройстве. Вашим первым шагом должна быть внимательная проверка файла dmesg для выяснения того, включены ли MSI на Вашей машине. Кроме того, Вам необходимо проверить файл .config и убедится, что опция CONFIG_PCI_MSI включена.

Полезно так же проверить сам драйвер, что бы выяснить, поддерживает ли он MSI. Такой драйвер должен содержать вызовы функций pci_enable_msi(), pci_enable_msix() or pci_enable_msi_block().

Источник

Сказочный портал