Конфигурационное пространство PCIe хранит параметры устройства: идентификаторы, capability-структуры, бары, настройки управления питанием и расширенные возможности. В Linux доступ идёт через sysfs, lspci и setpci, и правильное чтение конфигурации открывает настройку Max Payload Size, ASPM, SRI-OV и стандарных возможностей без пересборки драйвера. Ниже разобраны структура конфигурационного пространства, чтение через lspci и sysfs, запись через setpci, capability-структуры MSI MSI-X AER и типичные ловушки.

Структура конфигурационного пространства и capability списки

Конфигурационное пространство PCIe занимает 4096 байт: первые 64 байта стандартный заголовок, далее capability-структуры связаны в список через указатель Capability Pointer. Каждый capability начинается с байта ID и байта Next Pointer, и обход списка идёт до нуля.

Стандартные capability ID: 0x01 Power Management, 0x05 MSI, 0x10 PCI Express, 0x11 MSI-X, 0x13 PCI Express Advanced Error Reporting, 0x15 Resizable BAR, 0x19 Secondary PCIe, 0x1B Precision Time Measurement. Вендор-специфичные возможности начинаются с 0x09 Vendor Specific и 0x0F Designated Vendor Specific.

Чтение списка через lspci -vvv показывает все capability с расшифровкой:

lspci -vvv -s 01:00.0

В выводе видны Capabilities с адресами в квадратных скобках, и каждый блок раскрывает поля структуры. Для понимания значений полезен флаг -xxx, который показывает сырые байты конфигурационного пространства.

Чтение через sysfs и запись через setpci

Конфигурационное пространство доступно в sysfs как бинарный файл config:

hexdump -C /sys/bus/pci/devices/0000:01:00.0/config | head -20

Файл config поддерживает чтение и запись от суперпользователя, и модификация отдельных байтов делается dd:

dd if=/dev/zero of=/sys/bus/pci/devices/0000:01:00.0/config bs=1 seek=88 count=2 conv=notrunc

Утилита setpci делает запись удобнее с параметрами и масками:

setpci -s 01:00.0 COMMAND=0x0006
setpci -s 01:00.0 CAP_EXP+0x0c.w=0x2820
setpci -s 01:00.0 0xc8.w=0x0001:0x000f

Первый пример включает Bus Master и Memory Space через регистр COMMAND, второй пишет слово в регистр Device Control из capability Express по смещению 0x0c, третий модифицирует биты с маской. Параметр -D включает dry-run, показывающий изменения без записи.

Чтение через setpci с форматированием:

setpci -s 01:00.0 CAP_EXP+0x0a.w

Ключ .b, .w, .l задаёт размер операции в байтах, словах или двойных словах.

Capability MSI MSI-X и настройка векторов

MSI capability по смещению с ID 0x05 содержит Message Address, Message Upper Address, Message Data и Message Control. Поле Count в Message Control показывает, сколько векторов выдано драйверу. MSI-X с ID 0x11 содержит Table Size, BAR индекс и смещение таблицы векторов.

Чтение через lspci -vvv:

Capabilities: [70] MSI: Enable+ Count=1/8 Maskable- 64bit+
Capabilities: [a0] MSI-X: Enable+ Count=17 Masked- Vector table: BAR=4 offset=00000000

Enable состояние управляется драйвером, и ручное включение MSI через setpci COMMAND регистр не рекомендуется: драйвер управляет последовательностью включения и выделением векторов через irq_domain.

AER capability с ID 0x13 содержит регистры ошибок: Uncorrectable Error Status, Correctable Error Status, Root Error Command. Маскирование ошибок через AER делается setpci на регистры статуса:

setpci -s 01:00.0 CAP_AER+0x08.l=0xffffffff

Маскирование оправдано для известных шумов линка, и полное отключение AER скрывает деградацию железа.

Настройка ASPM, MPS, MRRS и SRI-OV

ASPM, Active State Power Management, управляет энергосбережением линка: L0s и L1 состояния. Регистр Link Control в capability Express содержит биты ASPM:

setpci -s 00:01.0 CAP_EXP+0x10.w=0x0040:0x00c0

Маска 0x00c0 выбирает биты ASPM Control, значение 0x0040 включает L1. Полное отключение ASPM снижает латентность линка на 2-5 микросекунд, что критично для HFT и NVMe с низким latency budget.

Max Payload Size и Max Read Request настраиваются через Device Control регистр по смещению 0x08 в capability Express. MPS занимает биты 7-5, MRRS биты 14-12:

setpci -s 01:00.0 CAP_EXP+0x08.w=0x2820

Значение 0x2820 устанавливает MPS 256 байт и MRRS 512 байт. Настройка должна быть согласована по всему пути от root до устройства, иначе транзакции режутся или отклоняются.

SRI-OV capability с ID 0x10e содержит регистры TotalVFs и NumVFs. Включение виртуальных функций через sysfs:

echo 8 > /sys/bus/pci/devices/0000:01:00.0/sriov_numvfs

Появятся VF с адресами 01:00.2, 01:00.3 и далее, каждый VF виден как отдельное устройство с собственной конфигурацией. Отключение через запись нуля.

Настройка VF через setpci ограничена: физическая функция управляет распределением ресурсов, и VF-специфичные параметры задаются через драйвер PF или через ip link set eth0 vf 0 trust on. Чтение VF конфигурации через lspci показывает Capability SR-IOV с TotalVFs, NumVFs и VF Offset.

Типичные ошибки, примеры setpci и ReBAR

1. запись в capability без выравнивания, ядро возвращает ошибку, проверка размера и смещения через lspci -xxx;
2. установка MPS больше, чем у соседей по линку, транзакции режутся, согласование через pci=pcie_bus_perf;
3. ASPM отключён в BIOS, setpci не поможет, включение через BIOS и проверка через lspci -vvv LnkCtl;
4. SRI-OV без поддержки в прошивке, sriov_numvfs возвращает ошибку, проверка lspci -vvv и обновления прошивки;
5. запись в конфигурационное пространство на работающем драйвере, драйвер перечитывает регистры и возвращает значения, отключение драйвера перед модификацией;
6.Capability отсутствует, setpci возвращает ошибку, проверка списка через lspci -vvv.

Диагностика: lspci -vvv полный дамп возможностей, lspci -xxx сырые байты, hexdump config файла sysfs, dmesg показывает ошибки AER и изменения конфигурации. Для мониторинга изменений полезен цикл с diff дампов конфигурации.

Включение Bus Master и Memory Space для устройства без драйвера:

setpci -s 01:00.0 COMMAND=0x0006

Настройка MPS и MRRS на 512 байт:

setpci -s 01:00.0 CAP_EXP+0x08.w=0x2920

Отключение ASPM L1 на порте и устройстве:

setpci -s 00:01.0 CAP_EXP+0x10.w=0x0000:0x00c0
setpci -s 01:00.0 CAP_EXP+0x10.w=0x0000:0x00c0

Чтение Serial Number из capability 0x03:

setpci -s 01:00.0 CAP_SN+0x04.l

Правильная работа с конфигурационным пространством открывает тонкую настройку железа без пересборки драйвера: MPS, MRRS, ASPM, маскирование ошибок, включение SRI-OV. Порядок работы: прочитать текущее состояние через lspci -vvv, зафиксировать базовый дамп, внести изменения через setpci с масками, проверить эффект через тест нагрузки, зафиксировать изменения в скрипте запуска или в udev-правилах. Один вечер настройки конфигурации обычно даёт 5-15 процентов производительности на шинно-ограниченных нагрузках.
BAR, Base Address Register, задают отображение памяти устройства в адресное пространство. BAR 64-битный занимает два 32-битных слота, и его размер определяется записью всех единиц в регистр с последующим чтением. lspci -vvv показывает Memory space с размером: [Mem 0xfc00000000-0xfdffffffff 64bit pref].

Resizable BAR capability с ID 0x15 позволяет менять размер BAR при загрузке. Настройка через sysfs:

cat /sys/bus/pci/devices/0000:01:00.0/resource
echo 1 > /sys/bus/pci/devices/0000:01:00.0/rebar

ReBAR полезен для видеокарт: Linux драйвер amdgpu и nouveau включают Resizable BAR через pci=realloc или через BIOS. Настройка в BIOS Big Banner: Above 4G Decoding и Re-Size BAR Support. Выигрыш для видеоигр и GPGPU до 10-15 процентов за счёт полного доступа к видеопамяти без окон.

Проверка ReBAR через lspci -vvv: в выводе ищется Resizable BAR capability с перечислением поддерживаемых размеров. Включение на уже загруженной системе возможно только через повторное пробуждение устройства, и на практике настройку делают через BIOS.

Power Management capability с ID 0x01 содержит PMCSR регистр с полями Power State D0-D3. Перевод устройства в D3hot снижает потребление до уровня Standby:

setpci -s 01:00.0 CAP_PM+0x04.w=0x0003

Значение 0x0003 это D3hot, 0x0000 это D0 активное. Возврат в D0 требует ожидания 10 мс перед использованием устройства, что задано спецификацией PCI Power Management.

Linux управляет питанием через runtime PM драйвера: suspend и resume вызовы меняют D-состояние, и настройка через sysfs:

echo on > /sys/bus/pci/devices/0000:01:00.0/power/control

Значение on отключает runtime suspend, auto разрешает. Для NVMe и сетевых карт runtime suspend экономит 1-3 ватта на карту, и на сервере с десятками карт сумма существенна. Латентность выхода из D3hot до 10 мс, что критично для латентностных нагрузок, и там ставят on.

Регистр Link Control в capability Express содержит биты Retrain Link и Link Disable. Изменение скорости линка вручную через Retrain:

setpci -s 00:01.0 CAP_EXP+0x10.w=0x0020:0x0020

Бит 5 Retrain Link заставляет линк перетренироваться и выбрать максимальную поддерживаемую скорость. Проверка скорости через lspci -vvv: LnkSta показывает Speed и Width.

Downgrade линка происходит из-за физической проблемы: плохой контакт, длинная трасса, несовместимость. AER с корректируемыми ошибками Retrain показывает деградацию, и решение в переподключении или замене карты.

Настройка Target Link Speed в Link Control 2 по смещению 0x30 в capability Express:

setpci -s 01:00.0 CAP_EXP+0x30.w=0x0003:0x000f

Значение 3 задаёт Gen3, 4 Gen4, 5 Gen5. Ручное ограничение скорости используется для отладки и для карт с нестабильной работой на максимальной скорости.

Hot Plug, привязка NUMA и автоматизация через udev

Hot Plug контроллер на PCIe определяется через Slot Capability в Express. Регистр Slot Control управляет Power Indicator, Attention Indicator и командой Power On/Off:

setpci -s 00:01.0 CAP_EXP+0x14.w=0x0c00

Linux hotplug через sysfs: echo 1 > /sys/bus/pci/devices/.../remove отключает устройство, echo 1 > /sys/bus/pci/rescan сканирует шину заново. Серверные шасси с PCIe-стекерами поддерживают Hot Plug через стандарные слоты, и новые карты видны без перезагрузки.

Привязка устройства к NUMA-узлу настраивается через sysfs:

echo 0 > /sys/bus/pci/devices/0000:01:00.0/numa_node

Чтение текущего узла через cat numa_node показывает -1 если не настроено. Привязка влияет на выделение DMA-памяти и на балансировку прерываний, и неправильная привязка даёт 20-40 процентов падения полосы. Настройка обычно делается в BIOS через NUMA configuration, но sysfs позволяет корректировать на лету.

Автоматизация настройки при загрузке через udev-правило:

SUBSYSTEM=="pci", ATTR{vendor}=="0x8086", ATTR{device}=="0x1593", ACTION=="add", RUN+="/usr/local/bin/setup-nic.sh %k"

Скрипт setup-nic.sh содержит setpci команды для конкретного устройства. Альтернатива через systemd-юнит oneshot с ExecStart списком setpci.

Порядок настройки устройства при загрузке: драйвер грузится после udev, и setpci нужно выполнить до подключения драйвера, иначе драйвер перечитает регистры. Решение: udev-правило на ACTION add с номером устройства до загрузки драйвера через blacklist модуля и ручной modprobe после настройки.

Сравнение конфигурации до и после изменения делается сохранением дампа lspci -xxx в файл и diff. Такой подход позволяет документировать изменения и откатываться при деградации.

Правильная настройка конфигурационного пространства через setpci и sysfs открывает тонкую настройку железа без пересборки драйвера. MPS, MRRS, ASPM, ReBAR, SRI-OV, привязка NUMA все это делается за один вечер и обычно даёт 5-15 процентов на шинно-ограниченных нагрузках. Порядок: базовый дамп, изменения с масками, тест нагрузки, фиксация через udev или systemd.