Перейти к содержимому

Sata interrupt selection что это msix msi legacy

  • автор:

Общие сведения о прерываниях Message-Signaled

Прерывания с сигналом сообщения (MSIs) были представлены в спецификации PCI 2.2 в качестве альтернативы прерываниям на основе строк. Вместо использования выделенного контакта для активации прерываний устройства, использующие MSIs, активируют прерывание, записывая значение в определенный адрес памяти. СТАНДАРТ PCI 3.0 определяет расширенную форму MSI-X, которая обеспечивает большую программируемость. Windows Vista и более поздние версии Windows поддерживают MSI и MSI-X. Одно устройство может поддерживать как MSI, так и MSI-X. Для такого устройства операционная система будет автоматически использовать MSI-X.

Сообщение прерывания — это определенное значение, которое устройство записывает на определенный адрес для активации прерывания. В отличие от прерываний на основе строк, прерывания, сигнальные сообщением, имеют граничную семантику. Устройство отправляет сообщение, но не получает аппаратного подтверждения того, что прерывание было получено.

Для PCI 2.2 сообщение состоит из адреса и частично непрозрачного 16-разрядного значения. Каждому устройству назначается один адрес. Для отправки нескольких сообщений устройство может использовать более низкие 4 бита значения сообщения для различения сообщений. Таким образом, для PCI 2.2 устройства могут поддерживать до 16 сообщений.

Для PCI 3.0 сообщение состоит из адреса и непрозрачного 32-разрядного значения. Каждое сообщение имеет свой уникальный адрес. В отличие от PCI 2.2, устройство не изменяет значение . Для PCI 3.0 устройство может поддерживать до 2048 различных сообщений. Устройства, поддерживающие PCI 3.0 MSI-X, имеют динамически программируемую аппаратную таблицу, содержащую записи для каждого из источников прерываний на устройстве. Каждая запись в этой таблице может быть запрограммирована с помощью одного из сообщений, выделенных устройству, и может быть замаскирована независимо друг от друга. Драйверы могут изменять программирование сообщения прерывания на запись таблицы и возможность маскирования записи. Дополнительные сведения см. в разделе Динамическая настройка MSI-X.

Драйверы могут зарегистрировать одну подпрограмму InterruptMessageService , которая обрабатывает все возможные сообщения или отдельные подпрограммы InterruptService для каждого сообщения.

Драйверы могут обрабатывать MSIs, отправляемые устройством, следующим образом:

  1. Во время установки драйвера включите MSIs в реестре. Вы также можете использовать реестр, чтобы указать количество сообщений, выделяемых для устройства. Дополнительные сведения см. в разделе Включение прерываний Message-Signaled в реестре.
  2. При необходимости увеличьте количество сообщений о прерываниях и сохраните некоторые параметры каждого сообщения, отвечая на запрос IRP_MN_FILTER_RESOURCE_REQUIREMENTS . Дополнительные сведения см. в разделе Использование дескрипторов ресурсов прерывания.
  3. В подпрограмме диспетчеризации драйвера для IRP_MN_START_DEVICE вызовите IoConnectInterruptEx , чтобы зарегистрировать подпрограмму InterruptService или InterruptMessageService для обслуживания прерываний устройства. Используйте CONNECT_FULLY_SPECIFIED версию IoConnectInterruptEx , чтобы зарегистрировать подпрограмму InterruptService для определенного сообщения, или CONNECT_MESSAGE_BASED версию IoConnectInterruptEx , чтобы зарегистрировать одну подпрограмму InterruptMessageService для всех сообщений. Дополнительные сведения см. в разделах Использование версии CONNECT_MESSAGE_BASED IoConnectInterruptEx и Использование CONNECT_FULLY_SPECIFIED версии IoConnectInterruptEx.
  4. После того как драйвер больше не будет обслуживать прерывания с устройства, вызовите IoDisconnectInterruptEx (после отключения прерываний устройства), чтобы удалить все зарегистрированные процедуры обслуживания прерываний.

Драйверы, предназначенные для использования нескольких сообщений, должны проверка, что выделяется ожидаемое количество сообщений. Если диспетчер Plug and Play (PnP) не может выделить запрошенное количество сообщений, он выделяет устройству ровно одно сообщение. Драйверы могут проверка количество фактически выделенных сообщений одним из следующих способов:

  • Диспетчер PnP сообщает количество выделенных сообщений в списке дескрипторов необработанных ресурсов. Дополнительные сведения см. в разделе Использование дескрипторов ресурсов прерывания.
  • Когда IoConnectInterruptEx возвращает значение , параметр Parameters-MessageBased.ConnectContext.InterruptMessageTable-MessageCount>> задает количество выделенных сообщений.

Совместная работа с нами на GitHub

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

Windows driver documentation

interrupt paradigms (MSI/MSI-X and legacy) in drivers

I’d like to support all three modes in my driver and pass an intr_type argument in module_param() macro. I’m wondering what is the general rule of thumb: if by default the command line parameter is empty, support MSI or MSI-X? Since MSI and MSI-X are logically close, which one should be preferable to use?

For instance: if the driver detects that the device supports MSI-X, is this sufficient to try enable MSI-X and use it in driver, and in case of failure revert to the legacy INTx ?

  • linux-kernel
  • linux-device-driver
  • interrupt
  • interrupt-handling

Прерывания от внешних устройств в системе x86. Часть 2. Опции загрузки ядра Linux

В предыдущей части мы рассмотрели эволюцию доставки прерываний от устройств в x86 системах (PIC → APIC → MSI), общую теорию и все необходимые термины.

В этой практической части мы рассмотрим как откатиться к использованию устаревших методов доставки прерываний в Linux, а именно рассмотрим опции загрузки ядра:

  • pci=nomsi
  • noapic
  • nolapic
  • pci=noacpi
  • acpi=noirq
  • acpi=off

Загрузка без дополнительных опций

Смотреть прерывания в данной статье мы будем на кастомной плате с Intel Haswell i7 с чипсетом lynxPoint-LP на которой запущен coreboot.

Информацию о прерываниях мы будем выводить через команду

cat /proc/interrupts

Вывод при загрузке без дополнительных опций:

 CPU0 CPU1 CPU2 CPU3 0: 15 0 0 0 IO-APIC-edge timer 1: 0 1 0 1 IO-APIC-edge i8042 8: 0 0 0 1 IO-APIC-edge rtc0 9: 0 0 0 0 IO-APIC-fasteoi acpi 12: 0 0 0 1 IO-APIC-edge 23: 16 247 7 10 IO-APIC-fasteoi ehci_hcd:usb1 56: 0 0 0 0 PCI-MSI-edge aerdrv,PCIe PME 57: 0 0 0 0 PCI-MSI-edge aerdrv,PCIe PME 58: 0 0 0 0 PCI-MSI-edge aerdrv,PCIe PME 59: 0 0 0 0 PCI-MSI-edge aerdrv,PCIe PME 60: 0 0 0 0 PCI-MSI-edge aerdrv,PCIe PME 61: 0 0 0 0 PCI-MSI-edge aerdrv,PCIe PME 62: 3118 1984 972 3454 PCI-MSI-edge ahci 63: 1 0 0 0 PCI-MSI-edge eth59 64: 2095 57 4 832 PCI-MSI-edge eth59-rx-0 65: 6 18 1 1309 PCI-MSI-edge eth59-rx-1 66: 13 512 2 1 PCI-MSI-edge eth59-rx-2 67: 10 61 232 2 PCI-MSI-edge eth59-rx-3 68: 169 0 0 0 PCI-MSI-edge eth59-tx-0 69: 14 14 4 205 PCI-MSI-edge eth59-tx-1 70: 11 491 3 0 PCI-MSI-edge eth59-tx-2 71: 20 19 134 50 PCI-MSI-edge eth59-tx-3 72: 0 0 0 0 PCI-MSI-edge eth58 73: 2 1 0 152 PCI-MSI-edge eth58-rx-0 74: 3 150 2 0 PCI-MSI-edge eth58-rx-1 75: 2 34 117 2 PCI-MSI-edge eth58-rx-2 76: 153 0 2 0 PCI-MSI-edge eth58-rx-3 77: 4 0 2 149 PCI-MSI-edge eth58-tx-0 78: 4 149 2 0 PCI-MSI-edge eth58-tx-1 79: 4 0 117 34 PCI-MSI-edge eth58-tx-2 80: 153 0 2 0 PCI-MSI-edge eth58-tx-3 81: 66 106 2 101 PCI-MSI-edge snd_hda_intel 82: 928 5657 262 224 PCI-MSI-edge i915 83: 545 56 32 15 PCI-MSI-edge snd_hda_intel NMI: 0 0 0 0 Non-maskable interrupts LOC: 4193 3644 3326 3499 Local timer interrupts SPU: 0 0 0 0 Spurious interrupts PMI: 0 0 0 0 Performance monitoring interrupts IWI: 290 233 590 111 IRQ work interrupts RTR: 3 0 0 0 APIC ICR read retries RES: 1339 2163 2404 1946 Rescheduling interrupts CAL: 607 537 475 559 Function call interrupts TLB: 163 202 164 251 TLB shootdowns TRM: 48 48 48 48 Thermal event interrupts THR: 0 0 0 0 Threshold APIC interrupts MCE: 0 0 0 0 Machine check exceptions MCP: 3 3 3 3 Machine check polls ERR: 0 MIS: 0 

Файл /proc/interrupts предоставляет таблицу о количестве прерываний на каждом из процессоров в следующем виде:

  • Первая колонка: номер прерывания
  • Колонки CPUx: счётчики прерываний на каждом из процессоров
  • Следующая колонка: вид прерывания:
    • IO-APIC-edge — прерывание по фронту на контроллер I/O APIC
    • IO-APIC-fasteoi — прерывание по уровню на контроллер I/O APIC
    • PCI-MSI-edge — MSI прерывание
    • XT-PIC-XT-PIC — прерывание на PIC контроллер (увидим позже)

    Упрощённо схему роутинга прерываний можно нарисовать так (красным помечены активные пути, чёрным неиспользуемые).

    Поддержка MSI/MSI-X устройством должна быть обозначена как соответствующая Capability в его конфигурационном пространстве PCI.

    В подтверждении приведём небольшой фрагмент вывода lspci для устройств, для которых обозначено, что они используют MSI/MSI-X. В нашем случае это SATA контроллер (прерывание ahci), 2 ethernet контроллера (прерывания eth58* и eth59*), графический контроллер (i915) и 2 контроллера HD Audio (snd_hda_intel).

    lspci -v
    00:02.0 VGA compatible controller: Intel Corporation Haswell-ULT Integrated Graphics Controller (rev 09) (prog-if 00 [VGA controller]) . Capabilities: [90] MSI: Enable+ Count=1/1 Maskable- 64bit- Capabilities: [d0] Power Management version 2 Capabilities: [a4] PCI Advanced Features Kernel driver in use: i915 00:03.0 Audio device: Intel Corporation Haswell-ULT HD Audio Controller (rev 09 . Capabilities: [60] MSI: Enable+ Count=1/1 Maskable- 64bit- Capabilities: [70] Express Root Complex Integrated Endpoint, MSI 00 Kernel driver in use: snd_hda_intel 00:1b.0 Audio device: Intel Corporation 8 Series HD Audio Controller (rev 04) . Capabilities: [60] MSI: Enable+ Count=1/1 Maskable- 64bit+ Capabilities: [70] Express Root Complex Integrated Endpoint, MSI 00 Capabilities: [100] Virtual Channel Kernel driver in use: snd_hda_intel 00:1f.2 SATA controller: Intel Corporation 8 Series SATA Controller 1 [AHCI mode] (rev 04) (prog-if 01 [AHCI 1.0]) . Capabilities: [80] MSI: Enable+ Count=1/1 Maskable- 64bit- Capabilities: [70] Power Management version 3 Capabilities: [a8] SATA HBA v1.0 Kernel driver in use: ahci 05:00.0 Ethernet controller: Intel Corporation I350 Gigabit Network Connection (rev 01) . Capabilities: [50] MSI: Enable- Count=1/1 Maskable+ 64bit+ Capabilities: [70] MSI-X: Enable+ Count=10 Masked- Capabilities: [a0] Express Endpoint, MSI 00 Kernel driver in use: igb 05:00.1 Ethernet controller: Intel Corporation I350 Gigabit Network Connection (rev 01) . Capabilities: [50] MSI: Enable- Count=1/1 Maskable+ 64bit+ Capabilities: [70] MSI-X: Enable+ Count=10 Masked- Capabilities: [a0] Express Endpoint, MSI 00 Kernel driver in use: igb

    Как мы видим, у этих устройств присутствует строка либо «MSI: Enable+», либо «MSI-X: Enable+»

    Начнём деградировать систему. Для начала загрузимся с опцией pci=nomsi.

    pci=nomsi

    Благодаря этой опции MSI прерывания станут IO-APIC/XT-PIC в зависимости от используемого контроллера прерываний

    В данном случае у нас всё ещё приоритетный контроллер прерываний APIC, так что картина будет такая:

     CPU0 CPU1 CPU2 CPU3 0: 15 0 0 0 IO-APIC-edge timer 1: 0 1 0 1 IO-APIC-edge i8042 8: 0 0 1 0 IO-APIC-edge rtc0 9: 0 0 0 0 IO-APIC-fasteoi acpi 12: 0 0 0 1 IO-APIC-edge 16: 1314 5625 342 555 IO-APIC-fasteoi i915, snd_hda_intel, eth59 17: 5 0 1 34 IO-APIC-fasteoi eth58 21: 2882 2558 963 2088 IO-APIC-fasteoi ahci 22: 26 81 2 170 IO-APIC-fasteoi snd_hda_intel 23: 23 369 8 8 IO-APIC-fasteoi ehci_hcd:usb1 NMI: 0 0 0 0 Non-maskable interrupts LOC: 3011 3331 2435 2617 Local timer interrupts SPU: 0 0 0 0 Spurious interrupts PMI: 0 0 0 0 Performance monitoring interrupts IWI: 197 228 544 85 IRQ work interrupts RTR: 3 0 0 0 APIC ICR read retries RES: 1708 2349 1821 1569 Rescheduling interrupts CAL: 520 554 509 555 Function call interrupts TLB: 187 181 205 179 TLB shootdowns TRM: 102 102 102 102 Thermal event interrupts THR: 0 0 0 0 Threshold APIC interrupts MCE: 0 0 0 0 Machine check exceptions MCP: 2 2 2 2 Machine check polls ERR: 0 MIS: 0

    Все прерывания MSI/MSI-X ожидаемо исчезли. Вместо них устройства теперь используют прерывания вида IO-APIC-fasteoi.

    Обратим внимание на то, что раньше до включения этой опции у eth58 и eth59 было по 9 прерываний! А сейчас только по одному. Ведь как мы помним, без MSI одной функции PCI доступно только одно прерывание!

    Немного информации из dmesg по инициализации ethernet контроллеров:

    — загрузка без опции pci=nomsi:

    igb: Intel(R) Gigabit Ethernet Network Driver - version 5.0.5-k igb: Copyright (c) 2007-2013 Intel Corporation. acpi:acpi_pci_irq_enable: igb 0000:05:00.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16 igb 0000:05:00.0: irq 63 for MSI/MSI-X igb 0000:05:00.0: irq 64 for MSI/MSI-X igb 0000:05:00.0: irq 65 for MSI/MSI-X igb 0000:05:00.0: irq 66 for MSI/MSI-X igb 0000:05:00.0: irq 67 for MSI/MSI-X igb 0000:05:00.0: irq 68 for MSI/MSI-X igb 0000:05:00.0: irq 69 for MSI/MSI-X igb 0000:05:00.0: irq 70 for MSI/MSI-X igb 0000:05:00.0: irq 71 for MSI/MSI-X igb 0000:05:00.0: irq 63 for MSI/MSI-X igb 0000:05:00.0: irq 64 for MSI/MSI-X igb 0000:05:00.0: irq 65 for MSI/MSI-X igb 0000:05:00.0: irq 66 for MSI/MSI-X igb 0000:05:00.0: irq 67 for MSI/MSI-X igb 0000:05:00.0: irq 68 for MSI/MSI-X igb 0000:05:00.0: irq 69 for MSI/MSI-X igb 0000:05:00.0: irq 70 for MSI/MSI-X igb 0000:05:00.0: irq 71 for MSI/MSI-X igb 0000:05:00.0: added PHC on eth0 igb 0000:05:00.0: Intel(R) Gigabit Ethernet Network Connection igb 0000:05:00.0: eth0: (PCIe:5.0Gb/s:Width x1) 00:15:d5:03:00:2a igb 0000:05:00.0: eth0: PBA No: 106300-000 igb 0000:05:00.0: Using MSI-X interrupts. 4 rx queue(s), 4 tx queue(s) acpi:acpi_pci_irq_enable: igb 0000:05:00.1: PCI INT B -> GSI 17 (level, low) -> IRQ 17 igb 0000:05:00.1: irq 72 for MSI/MSI-X igb 0000:05:00.1: irq 73 for MSI/MSI-X igb 0000:05:00.1: irq 74 for MSI/MSI-X igb 0000:05:00.1: irq 75 for MSI/MSI-X igb 0000:05:00.1: irq 76 for MSI/MSI-X igb 0000:05:00.1: irq 77 for MSI/MSI-X igb 0000:05:00.1: irq 78 for MSI/MSI-X igb 0000:05:00.1: irq 79 for MSI/MSI-X igb 0000:05:00.1: irq 80 for MSI/MSI-X igb 0000:05:00.1: irq 72 for MSI/MSI-X igb 0000:05:00.1: irq 73 for MSI/MSI-X igb 0000:05:00.1: irq 74 for MSI/MSI-X igb 0000:05:00.1: irq 75 for MSI/MSI-X igb 0000:05:00.1: irq 76 for MSI/MSI-X igb 0000:05:00.1: irq 77 for MSI/MSI-X igb 0000:05:00.1: irq 78 for MSI/MSI-X igb 0000:05:00.1: irq 79 for MSI/MSI-X igb 0000:05:00.1: irq 80 for MSI/MSI-X igb 0000:05:00.1: added PHC on eth1 igb 0000:05:00.1: Intel(R) Gigabit Ethernet Network Connection igb 0000:05:00.1: eth1: (PCIe:5.0Gb/s:Width x1) 00:15:d5:03:00:2b igb 0000:05:00.1: eth1: PBA No: 106300-000 igb 0000:05:00.1: Using MSI-X interrupts. 4 rx queue(s), 4 tx queue(s)

    — загрузка с опцией pci=nomsi

    igb: Intel(R) Gigabit Ethernet Network Driver - version 5.0.5-k igb: Copyright (c) 2007-2013 Intel Corporation. acpi:acpi_pci_irq_enable: igb 0000:05:00.0: PCI INT A -> GSI 16 (level, low) -> IRQ 16 igb 0000:05:00.0: added PHC on eth0 igb 0000:05:00.0: Intel(R) Gigabit Ethernet Network Connection igb 0000:05:00.0: eth0: (PCIe:5.0Gb/s:Width x1) 00:15:d5:03:00:2a igb 0000:05:00.0: eth0: PBA No: 106300-000 igb 0000:05:00.0: Using legacy interrupts. 1 rx queue(s), 1 tx queue(s) acpi:acpi_pci_irq_enable: igb 0000:05:00.1: PCI INT B -> GSI 17 (level, low) -> IRQ 17 igb 0000:05:00.1: added PHC on eth1 igb 0000:05:00.1: Intel(R) Gigabit Ethernet Network Connection igb 0000:05:00.1: eth1: (PCIe:5.0Gb/s:Width x1) 00:15:d5:03:00:2b igb 0000:05:00.1: eth1: PBA No: 106300-000 igb 0000:05:00.1: Using legacy interrupts. 1 rx queue(s), 1 tx queue(s)

    Из-за уменьшения количества прерываний на устройство, включение данной опции может приводить к существенному ограничению производительности работы драйвера (это без учёта того, что согласно исследованию Intel Reducing Interrupt Latency Through the Use of Message Signaled Interrupts прерывания через MSI в 3 раза быстрее чем через IO-APIC и в 5 раз быстрее чем через PIC).

    noapic

    Данная опция отключает I/O APIC. MSI прерывания всё ещё могут идти на все CPU, но прерывания от устройств смогут идти только на CPU0, так как PIC связан только с CPU0. Но LAPIC работает и другие CPU могут работать и обрабатывать прерывания.

     CPU0 CPU1 CPU2 CPU3 0: 5 0 0 0 XT-PIC-XT-PIC timer 1: 2 0 0 0 XT-PIC-XT-PIC i8042 2: 0 0 0 0 XT-PIC-XT-PIC cascade 8: 1 0 0 0 XT-PIC-XT-PIC rtc0 9: 0 0 0 0 XT-PIC-XT-PIC acpi 12: 172 0 0 0 XT-PIC-XT-PIC ehci_hcd:usb1 56: 0 0 0 0 PCI-MSI-edge aerdrv, PCIe PME 57: 0 0 0 0 PCI-MSI-edge aerdrv, PCIe PME 58: 0 0 0 0 PCI-MSI-edge aerdrv, PCIe PME 59: 0 0 0 0 PCI-MSI-edge aerdrv, PCIe PME 60: 0 0 0 0 PCI-MSI-edge aerdrv, PCIe PME 61: 0 0 0 0 PCI-MSI-edge aerdrv, PCIe PME 62: 2833 2989 1021 811 PCI-MSI-edge ahci 63: 0 1 0 0 PCI-MSI-edge eth59 64: 301 52 9 3 PCI-MSI-edge eth59-rx-0 65: 12 24 3 178 PCI-MSI-edge eth59-rx-1 66: 14 85 6 2 PCI-MSI-edge eth59-rx-2 67: 17 24 307 1 PCI-MSI-edge eth59-rx-3 68: 70 18 8 10 PCI-MSI-edge eth59-tx-0 69: 7 0 0 23 PCI-MSI-edge eth59-tx-1 70: 15 227 2 2 PCI-MSI-edge eth59-tx-2 71: 18 6 27 2 PCI-MSI-edge eth59-tx-3 72: 0 0 0 0 PCI-MSI-edge eth58 73: 1 0 0 27 PCI-MSI-edge eth58-rx-0 74: 1 22 0 5 PCI-MSI-edge eth58-rx-1 75: 1 0 22 5 PCI-MSI-edge eth58-rx-2 76: 23 0 0 5 PCI-MSI-edge eth58-rx-3 77: 1 0 0 27 PCI-MSI-edge eth58-tx-0 78: 1 22 0 5 PCI-MSI-edge eth58-tx-1 79: 1 0 22 5 PCI-MSI-edge eth58-tx-2 80: 23 0 0 5 PCI-MSI-edge eth58-tx-3 81: 187 17 70 7 PCI-MSI-edge snd_hda_intel 82: 698 1647 247 129 PCI-MSI-edge i915 83: 438 135 16 59 PCI-MSI-edge snd_hda_intel NMI: 0 0 0 0 Non-maskable interrupts LOC: 1975 2499 2245 1474 Local timer interrupts SPU: 0 0 0 0 Spurious interrupts PMI: 0 0 0 0 Performance monitoring interrupts IWI: 132 67 429 91 IRQ work interrupts RTR: 3 0 0 0 APIC ICR read retries RES: 1697 2178 1903 1541 Rescheduling interrupts CAL: 561 496 534 567 Function call interrupts TLB: 229 254 170 137 TLB shootdowns TRM: 78 78 78 78 Thermal event interrupts THR: 0 0 0 0 Threshold APIC interrupts MCE: 0 0 0 0 Machine check exceptions MCP: 2 2 2 2 Machine check polls ERR: 0 MIS: 0

    Как видим, все прерывания IO-APIC-* превратились в XT-PIC-XT-PIC, причём эти прерывания роутятся только на CPU0. Прерывания MSI остались без изменений и идут на все CPU0-3.

    nolapic

    Отключает LAPIC. MSI прерывания не могут работать без LAPIC, I/O APIC не может работать без LAPIC. Поэтому все прерывания от устройств будут идти на PIC, а он работает только с CPU0. И без LAPIC остальные CPU даже работать в системе не будут.

     CPU0 0: 6416 XT-PIC-XT-PIC timer 1: 2 XT-PIC-XT-PIC i8042 2: 0 XT-PIC-XT-PIC cascade 3: 5067 XT-PIC-XT-PIC aerdrv, aerdrv, PCIe PME, PCIe PME, i915, snd_hda_intel, eth59 4: 32 XT-PIC-XT-PIC aerdrv, aerdrv, PCIe PME, PCIe PME, eth58 5: 0 XT-PIC-XT-PIC aerdrv, PCIe PME 6: 0 XT-PIC-XT-PIC aerdrv, PCIe PME 8: 1 XT-PIC-XT-PIC rtc0 9: 0 XT-PIC-XT-PIC acpi 11: 274 XT-PIC-XT-PIC snd_hda_intel 12: 202 XT-PIC-XT-PIC ehci_hcd:usb1 15: 7903 XT-PIC-XT-PIC ahci NMI: 0 Non-maskable interrupts LOC: 0 Local timer interrupts SPU: 0 Spurious interrupts PMI: 0 Performance monitoring interrupts IWI: 0 IRQ work interrupts RTR: 0 APIC ICR read retries RES: 0 Rescheduling interrupts CAL: 0 Function call interrupts TLB: 0 TLB shootdowns TRM: 0 Thermal event interrupts THR: 0 Threshold APIC interrupts MCE: 0 Machine check exceptions MCP: 1 Machine check polls ERR: 0 MIS: 0 

    Комбинации:

    На самом деле всего одна для нового варианта: «noapic pci=nomsi». Все прерывания от устройств смогут идти только на CPU0 через PIC. Но LAPIC работает и другие CPU могут работать и обрабатывать прерывания.

    Одна, потому что с «nolapic» можно ничего не комбинировать, т.к. эта опция и так сделает недоступным I/O APIC и MSI. Так что если вы когда-то прописывали опции загрузки «noapic nolapic» (или самый распространённый вариант «acpi=off noapic nolapic»), то судя по всему вы набирали лишние буквы.

    Итак, что будет от опций «noapic pci=nomsi»:

     CPU0 CPU1 CPU2 CPU3 0: 5 0 0 0 XT-PIC-XT-PIC timer 1: 2 0 0 0 XT-PIC-XT-PIC i8042 2: 0 0 0 0 XT-PIC-XT-PIC cascade 3: 5072 0 0 0 XT-PIC-XT-PIC i915, snd_hda_intel, eth59 4: 32 0 0 0 XT-PIC-XT-PIC eth58 8: 1 0 0 0 XT-PIC-XT-PIC rtc0 9: 0 0 0 0 XT-PIC-XT-PIC acpi 11: 281 0 0 0 XT-PIC-XT-PIC snd_hda_intel 12: 200 0 0 0 XT-PIC-XT-PIC ehci_hcd:usb1 15: 7930 0 0 0 XT-PIC-XT-PIC ahci NMI: 0 0 0 0 Non-maskable interrupts LOC: 2595 2387 2129 1697 Local timer interrupts SPU: 0 0 0 0 Spurious interrupts PMI: 0 0 0 0 Performance monitoring interrupts IWI: 159 90 482 135 IRQ work interrupts RTR: 3 0 0 0 APIC ICR read retries RES: 1568 1666 1810 1833 Rescheduling interrupts CAL: 431 556 549 558 Function call interrupts TLB: 124 184 156 274 TLB shootdowns TRM: 116 116 116 116 Thermal event interrupts THR: 0 0 0 0 Threshold APIC interrupts MCE: 0 0 0 0 Machine check exceptions MCP: 2 2 2 2 Machine check polls ERR: 0 MIS: 0

    Таблицы роутинга прерываний и опции «acpi=noirq», «pci=noacpi», «acpi=off»

    Как операционная система получает информацию о роутинге прерываний от устройств? BIOS подготавливает информацию для ОС в виде:

    • ACPI таблиц (методы _PIC/_PRT)
    • _MP_ таблицы (MPtable)
    • $PIR таблицы
    • Регистров 0x3C/0x3D конфигурационного пространства PCI устройств

    Таблицы в списке выше обозначены в порядке приоритета. Рассмотрим это подробней.

    Допустим BIOS предоставил все эти данные и мы грузимся без каких-либо дополнительных опций:

    • ОС находит таблицы ACPI
    • ОС выполняет метод ACPI «_PIC», передаёт ему аргумент, что нужно грузиться в режиме APIC. Тут код метода обычно сохраняет выбранный режим в переменной (допустим PICM=1)
    • Для получения данных о прерываниях ОС вызывает метод ACPI «_PRT». Он внутри себя проверяет переменную PICM и возвращает роутинг для APIC случая
    • ОС находит таблицы ACPI
    • ОС выполняет метод ACPI «_PIC», передаёт ему аргумент, что нужно грузиться в режиме PIC. Тут код метода обычно сохраняет выбранный режим в переменной (допустим PICM=0)
    • Для получения данных о прерываниях ОС вызывает метод ACPI «_PRT». Он внутри себя проверяет переменную PICM и возвращает роутинг для PIC случая
    • ОС не находит/не смотрит таблицы ACPI
    • ОС находит таблицу MPtable (_MP_)
    • ОС не находит/не смотрит таблицу ACPI
    • ОС не находит/не смотрит таблицу MPtable (_MP_)
    • ОС находит таблицу $PIR

    Суммируем всё вышеизложенное следующей картинкой:

    Следует помнить, что не каждый BIOS предоставляет все 3 таблицы (ACPI/MPtable/$PIR), так что если вы передали опцию загрузчику отказаться от использования ACPI или ACPI и MPtable для роутинга прерываний, далеко не факт, что ваша система загрузится.

    Замечание 1: в случае если мы попытаемся загрузиться в режиме APIC с опцией acpi=noirq и без наличия MPtable, то картина прерываний будет как и в случае обычной загрузки с единственной опцией noapic. Операционная система сама перейдёт в режим PIC прерываний.
    В случае если мы попытаемся загрузиться вообще без таблиц ACPI (acpi=off) и не предоставив MPtable, то картина будет такая:

     CPU0 0: 6 XT-PIC-XT-PIC timer 1: 2 XT-PIC-XT-PIC i8042 2: 0 XT-PIC-XT-PIC cascade 8: 0 XT-PIC-XT-PIC rtc0 12: 373 XT-PIC-XT-PIC ehci_hcd:usb1 16: 0 PCI-MSI-edge PCIe PME 17: 0 PCI-MSI-edge PCIe PME 18: 0 PCI-MSI-edge PCIe PME 19: 0 PCI-MSI-edge PCIe PME 20: 0 PCI-MSI-edge PCIe PME 21: 0 PCI-MSI-edge PCIe PME 22: 8728 PCI-MSI-edge ahci 23: 1 PCI-MSI-edge eth59 24: 1301 PCI-MSI-edge eth59-rx-0 25: 113 PCI-MSI-edge eth59-tx-0 26: 0 PCI-MSI-edge eth58 27: 45 PCI-MSI-edge eth58-rx-0 28: 45 PCI-MSI-edge eth58-tx-0 29: 1280 PCI-MSI-edge snd_hda_intel NMI: 2 Non-maskable interrupts LOC: 24076 Local timer interrupts SPU: 0 Spurious interrupts PMI: 2 Performance monitoring interrupts IWI: 2856 IRQ work interrupts RTR: 0 APIC ICR read retries RES: 0 Rescheduling interrupts CAL: 0 Function call interrupts TLB: 0 TLB shootdowns TRM: 34 Thermal event interrupts THR: 0 Threshold APIC interrupts MCE: 0 Machine check exceptions MCP: 2 Machine check polls ERR: 0 MIS: 0 

    Это проиcходит из-за того, что без ACPI таблицы MADT (Multiple APIC Description Table) и необходимой информации из MPtable, операционная система не знает APIC идентификаторы (APIC ID) для других процессоров и не может с ними работать, но LAPIC основного процессора работает, так как мы это не запрещали, и MSI прерывания могут на него приходить. То есть будет так:

    Замечание 2: в целом роутинг прерываний при использовании ACPI в случае APIC совпадает с роутингом прерываний через MPtable. А роутинг прерываний через ACPI в случае использования PIC совпадает с роутингом прерываний через $PIR. Так что и выводы /proc/interrupts отличаться не должны. Однако в процессе исследований заметил одну странность. При роутинге через MPtable в выводе почему-то присутствует каскадное прерывание «XT-PIC-XT-PIC cascade».

     CPU0 CPU1 CPU2 CPU3 0: 15 0 0 0 IO-APIC-edge timer 1: 2 0 0 0 IO-APIC-edge i8042 2: 0 0 0 0 XT-PIC-XT-PIC cascade 8: 0 1 0 0 IO-APIC-edge rtc0 9: 0 0 0 0 IO-APIC-edge acpi . 

    Немного странно, что так происходит, но в документации ядра вроде говорится, что это нормально.

    Заключение:

    В заключении ещё раз обозначим разобранные опции.

    Опции выбора контроллера прерываний:

    • pci=nomsi — MSI прерывания станут IO-APIC/XT-PIC в зависимости от используемого контроллера прерываний
    • noapic — Отключает I/O APIC. MSI прерывания всё ещё могут идти на все CPU, остальные прерывания от устройств смогут идти только на PIC, а он работает только с CPU0. Но LAPIC работает и другие CPU могут работать и обрабатывать прерывания
    • noapic pci=nomsi — Все прерывания от устройств могут идти только на PIC, а он работает только с CPU0. Но LAPIC работает и другие CPU могут работать и обрабатывать прерывания
    • nolapic — Отключает LAPIC. MSI прерывания не могут работать без LAPIC, I/O APIC не может работать без LAPIC. Все прерывания от устройств будут идти на PIC, а он работает только с CPU0. И без LAPIC остальные CPU не будут работать.
    • без опций — роутинг через APIC с помощью таблиц ACPI
    • noapic — роутинг через PIC с помощью таблиц ACPI
    • acpi=noirq (pci=noacpi/acpi=off) — роутинг через APIC с помощью таблицы MPtable
    • acpi=noirq (pci=noacpi/acpi=off) noapic (nolapic) — роутинг через PIC с помощью таблицы $PIR

    4. The MSI Driver Guide HOWTO¶

    This guide describes the basics of Message Signaled Interrupts (MSIs), the advantages of using MSI over traditional interrupt mechanisms, how to change your driver to use MSI or MSI-X and some basic diagnostics to try if a device doesn’t support MSIs.

    4.2. What are MSIs?¶

    A Message Signaled Interrupt is a write from the device to a special address which causes an interrupt to be received by the CPU.

    The MSI capability was first specified in PCI 2.2 and was later enhanced in PCI 3.0 to allow each interrupt to be masked individually. The MSI-X capability was also introduced with PCI 3.0. It supports more interrupts per device than MSI and allows interrupts to be independently configured.

    Devices may support both MSI and MSI-X, but only one can be enabled at a time.

    4.3. Why use MSIs?¶

    There are three reasons why using MSIs can give an advantage over traditional pin-based interrupts.

    Pin-based PCI interrupts are often shared amongst several devices. To support this, the kernel must call each interrupt handler associated with an interrupt, which leads to reduced performance for the system as a whole. MSIs are never shared, so this problem cannot arise.

    When a device writes data to memory, then raises a pin-based interrupt, it is possible that the interrupt may arrive before all the data has arrived in memory (this becomes more likely with devices behind PCI-PCI bridges). In order to ensure that all the data has arrived in memory, the interrupt handler must read a register on the device which raised the interrupt. PCI transaction ordering rules require that all the data arrive in memory before the value may be returned from the register. Using MSIs avoids this problem as the interrupt-generating write cannot pass the data writes, so by the time the interrupt is raised, the driver knows that all the data has arrived in memory.

    PCI devices can only support a single pin-based interrupt per function. Often drivers have to query the device to find out what event has occurred, slowing down interrupt handling for the common case. With MSIs, a device can support more interrupts, allowing each interrupt to be specialised to a different purpose. One possible design gives infrequent conditions (such as errors) their own interrupt which allows the driver to handle the normal interrupt handling path more efficiently. Other possible designs include giving one interrupt to each packet queue in a network card or each port in a storage controller.

    4.4. How to use MSIs¶

    PCI devices are initialised to use pin-based interrupts. The device driver has to set up the device to use MSI or MSI-X. Not all machines support MSIs correctly, and for those machines, the APIs described below will simply fail and the device will continue to use pin-based interrupts.

    4.4.1. Include kernel support for MSIs¶

    To support MSI or MSI-X, the kernel must be built with the CONFIG_PCI_MSI option enabled. This option is only available on some architectures, and it may depend on some other options also being set. For example, on x86, you must also enable X86_UP_APIC or SMP in order to see the CONFIG_PCI_MSI option.

    4.4.2. Using MSI¶

    Most of the hard work is done for the driver in the PCI layer. The driver simply has to request that the PCI layer set up the MSI capability for this device.

    To automatically use MSI or MSI-X interrupt vectors, use the following function:

    int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs, unsigned int max_vecs, unsigned int flags);

    which allocates up to max_vecs interrupt vectors for a PCI device. It returns the number of vectors allocated or a negative error. If the device has a requirements for a minimum number of vectors the driver can pass a min_vecs argument set to this limit, and the PCI core will return -ENOSPC if it can’t meet the minimum number of vectors.

    The flags argument is used to specify which type of interrupt can be used by the device and the driver (PCI_IRQ_LEGACY, PCI_IRQ_MSI, PCI_IRQ_MSIX). A convenient short-hand (PCI_IRQ_ALL_TYPES) is also available to ask for any possible kind of interrupt. If the PCI_IRQ_AFFINITY flag is set, pci_alloc_irq_vectors() will spread the interrupts around the available CPUs.

    To get the Linux IRQ numbers passed to request_irq() and free_irq() and the vectors, use the following function:

    int pci_irq_vector(struct pci_dev *dev, unsigned int nr);

    Any allocated resources should be freed before removing the device using the following function:

    void pci_free_irq_vectors(struct pci_dev *dev);

    If a device supports both MSI-X and MSI capabilities, this API will use the MSI-X facilities in preference to the MSI facilities. MSI-X supports any number of interrupts between 1 and 2048. In contrast, MSI is restricted to a maximum of 32 interrupts (and must be a power of two). In addition, the MSI interrupt vectors must be allocated consecutively, so the system might not be able to allocate as many vectors for MSI as it could for MSI-X. On some platforms, MSI interrupts must all be targeted at the same set of CPUs whereas MSI-X interrupts can all be targeted at different CPUs.

    If a device supports neither MSI-X or MSI it will fall back to a single legacy IRQ vector.

    The typical usage of MSI or MSI-X interrupts is to allocate as many vectors as possible, likely up to the limit supported by the device. If nvec is larger than the number supported by the device it will automatically be capped to the supported limit, so there is no need to query the number of vectors supported beforehand:

    nvec = pci_alloc_irq_vectors(pdev, 1, nvec, PCI_IRQ_ALL_TYPES) if (nvec < 0) goto out_err;

    If a driver is unable or unwilling to deal with a variable number of MSI interrupts it can request a particular number of interrupts by passing that number to pci_alloc_irq_vectors() function as both 'min_vecs' and 'max_vecs' parameters:

    ret = pci_alloc_irq_vectors(pdev, nvec, nvec, PCI_IRQ_ALL_TYPES); if (ret < 0) goto out_err;

    The most notorious example of the request type described above is enabling the single MSI mode for a device. It could be done by passing two 1s as 'min_vecs' and 'max_vecs':

    ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); if (ret < 0) goto out_err;

    Some devices might not support using legacy line interrupts, in which case the driver can specify that only MSI or MSI-X is acceptable:

    nvec = pci_alloc_irq_vectors(pdev, 1, nvec, PCI_IRQ_MSI | PCI_IRQ_MSIX); if (nvec < 0) goto out_err;

    4.4.3. Legacy APIs¶

    The following old APIs to enable and disable MSI or MSI-X interrupts should not be used in new code:

    pci_enable_msi() /* deprecated */ pci_disable_msi() /* deprecated */ pci_enable_msix_range() /* deprecated */ pci_enable_msix_exact() /* deprecated */ pci_disable_msix() /* deprecated */

    Additionally there are APIs to provide the number of supported MSI or MSI-X vectors: pci_msi_vec_count() and pci_msix_vec_count() . In general these should be avoided in favor of letting pci_alloc_irq_vectors() cap the number of vectors. If you have a legitimate special use case for the count of vectors we might have to revisit that decision and add a pci_nr_irq_vectors() helper that handles MSI and MSI-X transparently.

    4.4.4. Considerations when using MSIs¶

    4.4.4.1. Spinlocks¶

    Most device drivers have a per-device spinlock which is taken in the interrupt handler. With pin-based interrupts or a single MSI, it is not necessary to disable interrupts (Linux guarantees the same interrupt will not be re-entered). If a device uses multiple interrupts, the driver must disable interrupts while the lock is held. If the device sends a different interrupt, the driver will deadlock trying to recursively acquire the spinlock. Such deadlocks can be avoided by using spin_lock_irqsave() or spin_lock_irq() which disable local interrupts and acquire the lock (see Unreliable Guide To Locking ).

    4.4.5. How to tell whether MSI/MSI-X is enabled on a device¶

    Using 'lspci -v' (as root) may show some devices with "MSI", "Message Signalled Interrupts" or "MSI-X" capabilities. Each of these capabilities has an 'Enable' flag which is followed with either "+" (enabled) or "-" (disabled).

    4.5. MSI quirks¶

    Several PCI chipsets or devices are known not to support MSIs. The PCI stack provides three ways to disable MSIs:

    1. globally
    2. on all devices behind a specific bridge
    3. on a single device

    4.5.1. Disabling MSIs globally¶

    Some host chipsets simply don't support MSIs properly. If we're lucky, the manufacturer knows this and has indicated it in the ACPI FADT table. In this case, Linux automatically disables MSIs. Some boards don't include this information in the table and so we have to detect them ourselves. The complete list of these is found near the quirk_disable_all_msi() function in drivers/pci/quirks.c.

    If you have a board which has problems with MSIs, you can pass pci=nomsi on the kernel command line to disable MSIs on all devices. It would be in your best interests to report the problem to linux-pci @ vger . kernel . org including a full 'lspci -v' so we can add the quirks to the kernel.

    4.5.2. Disabling MSIs below a bridge¶

    Some PCI bridges are not able to route MSIs between busses properly. In this case, MSIs must be disabled on all devices behind the bridge.

    Some bridges allow you to enable MSIs by changing some bits in their PCI configuration space (especially the Hypertransport chipsets such as the nVidia nForce and Serverworks HT2000). As with host chipsets, Linux mostly knows about them and automatically enables MSIs if it can. If you have a bridge unknown to Linux, you can enable MSIs in configuration space using whatever method you know works, then enable MSIs on that bridge by doing:

    echo 1 > /sys/bus/pci/devices/$bridge/msi_bus

    where $bridge is the PCI address of the bridge you've enabled (eg 0000:00:0e.0).

    To disable MSIs, echo 0 instead of 1. Changing this value should be done with caution as it could break interrupt handling for all devices below this bridge.

    Again, please notify linux-pci @ vger . kernel . org of any bridges that need special handling.

    4.5.3. Disabling MSIs on a single device¶

    Some devices are known to have faulty MSI implementations. Usually this is handled in the individual device driver, but occasionally it's necessary to handle this with a quirk. Some drivers have an option to disable use of MSI. While this is a convenient workaround for the driver author, it is not good practice, and should not be emulated.

    4.5.4. Finding why MSIs are disabled on a device¶

    From the above three sections, you can see that there are many reasons why MSIs may not be enabled for a given device. Your first step should be to examine your dmesg carefully to determine whether MSIs are enabled for your machine. You should also check your .config to be sure you have enabled CONFIG_PCI_MSI.

    Then, 'lspci -t' gives the list of bridges above a device. Reading /sys/bus/pci/devices/*/msi_bus will tell you whether MSIs are enabled (1) or disabled (0). If 0 is found in any of the msi_bus files belonging to bridges between the PCI root and the device, MSIs are disabled.

    It is also worth checking the device driver to see whether it supports MSIs. For example, it may contain calls to pci_alloc_irq_vectors() with the PCI_IRQ_MSI or PCI_IRQ_MSIX flags.

    4.6. List of device drivers MSI(-X) APIs¶

    The PCI/MSI subsystem has a dedicated C file for its exported device driver APIs — drivers/pci/msi/api.c . The following functions are exported:

    int pci_enable_msi ( struct pci_dev * dev ) ¶

    Enable MSI interrupt mode on device

    Parameters

    struct pci_dev *dev

    the PCI device to operate on

    Description

    Legacy device driver API to enable MSI interrupts mode on device and allocate a single interrupt vector. On success, the allocated vector Linux IRQ will be saved at dev->irq. The driver must invoke pci_disable_msi() on cleanup.

    NOTE

    The newer pci_alloc_irq_vectors() / pci_free_irq_vectors() API pair should, in general, be used instead.

    Return

    0 on success, errno otherwise

    void pci_disable_msi ( struct pci_dev * dev ) ¶

    Disable MSI interrupt mode on device

    Parameters

    struct pci_dev *dev

    the PCI device to operate on

    Description

    Legacy device driver API to disable MSI interrupt mode on device, free earlier allocated interrupt vectors, and restore INTx emulation. The PCI device Linux IRQ (dev->irq) is restored to its default pin-assertion IRQ. This is the cleanup pair of pci_enable_msi() .

    NOTE

    The newer pci_alloc_irq_vectors() / pci_free_irq_vectors() API pair should, in general, be used instead.

    int pci_msix_vec_count ( struct pci_dev * dev ) ¶

    Get number of MSI-X interrupt vectors on device

    Parameters

    struct pci_dev *dev

    the PCI device to operate on

    Return

    number of MSI-X interrupt vectors available on this device (i.e., the device's MSI-X capability structure "table size"), -EINVAL if the device is not MSI-X capable, other errnos otherwise.

    int pci_enable_msix_range ( struct pci_dev * dev , struct msix_entry * entries , int minvec , int maxvec ) ¶

    Enable MSI-X interrupt mode on device

    Parameters

    struct pci_dev *dev

    the PCI device to operate on

    struct msix_entry *entries

    input/output parameter, array of MSI-X configuration entries

    minimum required number of MSI-X vectors

    maximum desired number of MSI-X vectors

    Description

    Legacy device driver API to enable MSI-X interrupt mode on device and configure its MSI-X capability structure as appropriate. The passed entries array must have each of its members "entry" field set to a desired (valid) MSI-X vector number, where the range of valid MSI-X vector numbers can be queried through pci_msix_vec_count() . If successful, the driver must invoke pci_disable_msix() on cleanup.

    NOTE

    The newer pci_alloc_irq_vectors() / pci_free_irq_vectors() API pair should, in general, be used instead.

    Return

    number of MSI-X vectors allocated (which might be smaller than maxvecs), where Linux IRQ numbers for such allocated vectors are saved back in the entries array elements' "vector" field. Return -ENOSPC if less than minvecs interrupt vectors are available. Return -EINVAL if one of the passed entries members "entry" field was invalid or a duplicate, or if plain MSI interrupts mode was earlier enabled on device. Return other errnos otherwise.

    bool pci_msix_can_alloc_dyn ( struct pci_dev * dev ) ¶

    Query whether dynamic allocation after enabling MSI-X is supported

    Parameters

    struct pci_dev *dev

    PCI device to operate on

    Return

    True if supported, false otherwise

    struct msi_map pci_msix_alloc_irq_at ( struct pci_dev * dev , unsigned int index , const struct irq_affinity_desc * affdesc ) ¶

    Allocate an MSI-X interrupt after enabling MSI-X at a given MSI-X vector index or any free vector index

    Parameters

    struct pci_dev *dev

    PCI device to operate on

    unsigned int index

    Index to allocate. If index == MSI_ANY_INDEX this allocates the next free index in the MSI-X table

    const struct irq_affinity_desc *affdesc

    Optional pointer to an affinity descriptor structure. NULL otherwise

    Return

    A struct msi_map

    On success msi_map::index contains the allocated index (>= 0) and msi_map::virq contains the allocated Linux interrupt number (> 0).

    On fail msi_map::index contains the error code and msi_map::virq is set to 0.

    void pci_msix_free_irq ( struct pci_dev * dev , struct msi_map map ) ¶

    Free an interrupt on a PCI/MSIX interrupt domain

    Parameters

    struct pci_dev *dev

    The PCI device to operate on

    struct msi_map map

    A struct msi_map describing the interrupt to free

    Description

    Undo an interrupt vector allocation. Does not disable MSI-X.

    void pci_disable_msix ( struct pci_dev * dev ) ¶

    Disable MSI-X interrupt mode on device

    Parameters

    struct pci_dev *dev

    the PCI device to operate on

    Description

    Legacy device driver API to disable MSI-X interrupt mode on device, free earlier-allocated interrupt vectors, and restore INTx. The PCI device Linux IRQ (dev->irq) is restored to its default pin assertion IRQ. This is the cleanup pair of pci_enable_msix_range() .

    NOTE

    The newer pci_alloc_irq_vectors() / pci_free_irq_vectors() API pair should, in general, be used instead.

    int pci_alloc_irq_vectors ( struct pci_dev * dev , unsigned int min_vecs , unsigned int max_vecs , unsigned int flags ) ¶

    Allocate multiple device interrupt vectors

    Parameters

    struct pci_dev *dev

    the PCI device to operate on

    unsigned int min_vecs

    minimum required number of vectors (must be >= 1)

    unsigned int max_vecs

    maximum desired number of vectors

    unsigned int flags

    • PCI_IRQ_MSIX Allow trying MSI-X vector allocations
    • PCI_IRQ_MSI Allow trying MSI vector allocations
    • PCI_IRQ_LEGACY Allow trying legacy INTx interrupts, if and only if min_vecs == 1
    • PCI_IRQ_AFFINITY Auto-manage IRQs affinity by spreading the vectors around available CPUs

    Description

    Allocate up to max_vecs interrupt vectors on device. MSI-X irq vector allocation has a higher precedence over plain MSI, which has a higher precedence over legacy INTx emulation.

    Upon a successful allocation, the caller should use pci_irq_vector() to get the Linux IRQ number to be passed to request_threaded_irq() . The driver must call pci_free_irq_vectors() on cleanup.

    Return

    number of allocated vectors (which might be smaller than max_vecs), -ENOSPC if less than min_vecs interrupt vectors are available, other errnos otherwise.

    int pci_alloc_irq_vectors_affinity ( struct pci_dev * dev , unsigned int min_vecs , unsigned int max_vecs , unsigned int flags , struct irq_affinity * affd ) ¶

    Allocate multiple device interrupt vectors with affinity requirements

    Parameters

    struct pci_dev *dev

    the PCI device to operate on

    unsigned int min_vecs

    minimum required number of vectors (must be >= 1)

    unsigned int max_vecs

    maximum desired number of vectors

    unsigned int flags

    struct irq_affinity *affd

    affinity requirements (can be NULL ).

    Description

    Same as pci_alloc_irq_vectors() , but with the extra affd parameter. Check that function docs, and struct irq_affinity , for more details.

    int pci_irq_vector ( struct pci_dev * dev , unsigned int nr ) ¶

    Get Linux IRQ number of a device interrupt vector

    Parameters

    struct pci_dev *dev

    the PCI device to operate on

    unsigned int nr

    device-relative interrupt vector index (0-based); has different meanings, depending on interrupt mode:

    • MSI-X the index in the MSI-X vector table
    • MSI the index of the enabled MSI vectors
    • INTx must be 0

    Return

    the Linux IRQ number, or -EINVAL if nr is out of range

    const struct cpumask * pci_irq_get_affinity ( struct pci_dev * dev , int nr ) ¶

    Get a device interrupt vector affinity

    Parameters

    struct pci_dev *dev

    the PCI device to operate on

    device-relative interrupt vector index (0-based); has different meanings, depending on interrupt mode:

    • MSI-X the index in the MSI-X vector table
    • MSI the index of the enabled MSI vectors
    • INTx must be 0

    Return

    MSI/MSI-X vector affinity, NULL if nr is out of range or if the MSI(-X) vector was allocated without explicit affinity requirements (e.g., by pci_enable_msi() , pci_enable_msix_range() , or pci_alloc_irq_vectors() without the PCI_IRQ_AFFINITY flag). Return a generic set of CPU IDs representing all possible CPUs available during system boot if the device is in legacy INTx mode.

    struct msi_map pci_ims_alloc_irq ( struct pci_dev * dev , union msi_instance_cookie * icookie , const struct irq_affinity_desc * affdesc ) ¶

    Allocate an interrupt on a PCI/IMS interrupt domain

    Parameters

    struct pci_dev *dev

    The PCI device to operate on

    union msi_instance_cookie *icookie

    Pointer to an IMS implementation specific cookie for this IMS instance (PASID, queue ID, pointer. ). The cookie content is copied into the MSI descriptor for the interrupt chip callbacks or domain specific setup functions.

    const struct irq_affinity_desc *affdesc

    Optional pointer to an interrupt affinity descriptor

    Description

    There is no index for IMS allocations as IMS is an implementation specific storage and does not have any direct associations between index, which might be a pure software construct, and device functionality. This association is established by the driver either via the index - if there is a hardware table - or in case of purely software managed IMS implementation the association happens via the irq_write_msi_msg() callback of the implementation specific interrupt chip, which utilizes the provided icookie to store the MSI message in the appropriate place.

    Return

    A struct msi_map

    On success msi_map::index contains the allocated index (>= 0) and msi_map::virq the allocated Linux interrupt number (> 0).

    On fail msi_map::index contains the error code and msi_map::virq is set to 0.

    void pci_ims_free_irq ( struct pci_dev * dev , struct msi_map map ) ¶

    Allocate an interrupt on a PCI/IMS interrupt domain which was allocated via pci_ims_alloc_irq()

    Parameters

    struct pci_dev *dev

    The PCI device to operate on

    struct msi_map map

    A struct msi_map describing the interrupt to free as returned from pci_ims_alloc_irq()

    void pci_free_irq_vectors ( struct pci_dev * dev ) ¶

    Free previously allocated IRQs for a device

    Parameters

    struct pci_dev *dev

    the PCI device to operate on

    Description

    Undo the interrupt vector allocations and possible device MSI/MSI-X enablement earlier done through pci_alloc_irq_vectors_affinity() or pci_alloc_irq_vectors() .

    void pci_restore_msi_state ( struct pci_dev * dev ) ¶

    Restore cached MSI(-X) state on device

    Parameters

    struct pci_dev *dev

    the PCI device to operate on

    Description

    Write the Linux-cached MSI(-X) state back on device. This is typically useful upon system resume, or after an error-recovery PCI adapter reset.

    int pci_msi_enabled ( void ) ¶

    Are MSI(-X) interrupts enabled system-wide?

    Parameters

    Return

    true if MSI has not been globally disabled through ACPI FADT, PCI bridge quirks, or the "pci=nomsi" kernel command-line option.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *