Конфигурационное пространство 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.