Linux 3.x не удается назначить память PCI BAR

Вопрос или проблема

У меня есть машина IBM x3850 типа 8864, я могу успешно загрузиться с помощью ядра 2.6.32, но когда я пытаюсь использовать ядро 3.10 или новее, ядро не удается инициализировать все слоты PCI (я могу это исправить (вручную), см. ниже):

pci 0000:19:00.0: BAR 14: не удается назначить память (размер 0x1a00000)
pci 0000:19:00.0: BAR 13: не удается назначить ввод-вывод (размер 0x3000)
pci 0000:19:00.0: BAR 14: не удается назначить память (размер 0x1600000)
pci 0000:19:00.0: BAR 13: не удается назначить ввод-вывод (размер 0x3000)
pci 0000:1a:00.0: BAR 14: не удается назначить память (размер 0x1600000)
pci 0000:1a:00.0: BAR 13: назначен [io  0x7000-0x8fff]
pci 0000:1b:02.0: BAR 14: не удается назначить память (размер 0xa00000)
pci 0000:1b:04.0: BAR 14: не удается назначить память (размер 0xa00000)
pci 0000:1b:02.0: BAR 13: назначен [io  0x7000-0x7fff]
pci 0000:1b:04.0: BAR 13: назначен [io  0x8000-0x8fff]
...

Это приводит к тому, что моя сетевая карта не загружается успешно, так как шина PCI явно не правильно инстанциирована.

lspci показывает следующее:

00:00.0 Мост хоста: IBM Calgary PCI-X Host Bridge (rev 04)
00:01.0 VGA совместимый контроллер: Advanced Micro Devices, Inc. [AMD/ATI] RV100 [Radeon 7000 / Radeon VE]
00:03.0 USB контроллер: NEC Corporation OHCI USB Controller (rev 43)
00:03.1 USB контроллер: NEC Corporation OHCI USB Controller (rev 43)
00:03.2 USB контроллер: NEC Corporation uPD72010x USB 2.0 Controller (rev 04)
00:0f.0 Мост хоста: Broadcom CSB6 South Bridge (rev a0)
00:0f.1 IDE интерфейс: Broadcom CSB6 RAID/IDE Controller (rev a0)
00:0f.3 ISA мост: Broadcom GCLE-2 Host Bridge
01:00.0 Мост хоста: IBM Calgary PCI-X Host Bridge (rev 04)
01:01.0 Ethernet контроллер: Broadcom Corporation NetXtreme BCM5704 Gigabit Ethernet (rev 10)
01:01.1 Ethernet контроллер: Broadcom Corporation NetXtreme BCM5704 Gigabit Ethernet (rev 10)
01:02.0 RAID контроллер: Adaptec AAC-RAID (rev 02)
02:00.0 Мост хоста: IBM Calgary PCI-X Host Bridge (rev 04)
06:00.0 Мост хоста: IBM Calgary PCI-X Host Bridge (rev 04)
0a:00.0 PCI мост: IBM CalIOC2 PCI-E Root Port (rev 01)
0f:00.0 PCI мост: IBM CalIOC2 PCI-E Root Port (rev 01)
14:00.0 PCI мост: IBM CalIOC2 PCI-E Root Port (rev 01)
19:00.0 PCI мост: IBM CalIOC2 PCI-E Root Port (rev 01)
1a:00.0 PCI мост: Integrated Device Technology, Inc. [IDT] PES12N3A PCI Express Switch (rev 0c)
1b:02.0 PCI мост: Integrated Device Technology, Inc. [IDT] PES12N3A PCI Express Switch (rev 0c)
1b:04.0 PCI мост: Integrated Device Technology, Inc. [IDT] PES12N3A PCI Express Switch (rev 0c)
1c:00.0 Ethernet контроллер: Intel Corporation 82576 Gigabit Network Connection (rev 01)
1c:00.1 Ethernet контроллер: Intel Corporation 82576 Gigabit Network Connection (rev 01)
1d:00.0 Ethernet контроллер: Intel Corporation 82576 Gigabit Network Connection (rev 01)
1d:00.1 Ethernet контроллер: Intel Corporation 82576 Gigabit Network Connection (rev 01)

ИСПРАВЛЕНИЕ

Я на самом деле могу это исправить, удалив корневой PCI мост 19:00.0 PCI мост: IBM CalIOC2 PCI-E Root Port (rev 01) с помощью echo 1 > /sys/bus/pci/devices/0000\:19\:00.0/remove и последующим повторным сканированием: echo 1 > /sys/bus/pci/rescan, что вызывает следующий вывод:

pci _bus 0000:1c: busn_res: [bus 1c] освободен
pci _bus 0000:1d: busn_res: [bus 1d] освобожден
pci _bus 0000:1b: busn_res: [bus 1b-1d] освобожден
pci _bus 0000:1a: busn_res: [bus 1a-1d] освобожден
pci  0000:19:00.0: [1014:0308] type 01 класс 0x060401
pci  0000:19:00.0: поддерживает D1 D2
pci  0000:19:00.0: PME# поддерживается с D0 D1 D2 D3hot D3cold
pci  0000:1a:00.0: [111d:8018] type 01 класс 0x060400
pci  0000:1a:00.0: PME# поддерживается с D0 D3hot D3cold
pci  0000:19:00.0:     pci  мост к [bus 1a-1d] (субтрактивное декодирование)
pci  0000:19:00.0:   окно моста [mem 0xea800000-0xea9fffff 64bit pref]
pci  0000:19:00.0:   окно моста [mem 0xea800000-0xebcfffff] (субтрактивное декодирование)
pci  0000:19:00.0:   окно моста [io  0x7000-0x8fff] (субтрактивное декодирование)
pci  0000:1b:02.0: [111d:8018] type 01 класс 0x060400
pci  0000:1b:02.0: PME# поддерживается с D0 D3hot D3cold
pci  0000:1b:04.0: [111d:8018] type 01 класс 0x060400
pci  0000:1b:04.0: PME# поддерживается с D0 D3hot D3cold
pci  0000:1a:00.0:     pci  мост к [bus 1b-1d]
pci  0000:1a:00.0:   окно моста [io  0x7000-0x8fff]
pci  0000:1a:00.0:   окно моста [mem 0xea800000-0xea9fffff 64bit pref]

....

pci  0000:1b:04.0:   окно моста [mem 0xea900000-0xea9fffff 64bit pref]
pci  0000:1b:02.0: окно моста [mem 0x00100000-0x001fffff 64bit pref] к [bus 1c] add_size 100000
pci  0000:1b:04.0: окно моста [mem 0x00100000-0x001fffff 64bit pref] к [bus 1d] add_size 100000
pci  0000:1b:02.0: res[15]=[mem 0x00100000-0x001fffff 64bit pref] get_res_add_size add_size 100000
pci  0000:1b:04.0: res[15]=[mem 0x00100000-0x001fffff 64bit pref] get_res_add_size add_size 100000
pci  0000:1a:00.0: окно моста [mem 0x00100000-0x002fffff 64bit pref] к [bus 1b-1d] add_size 200000
pci  0000:19:00.0: окно моста [io  0x1000-0x2fff] к [bus 1a-1d] add_size 1000
pci  0000:1a:00.0: res[15]=[mem 0x00100000-0x002fffff 64bit pref] get_res_add_size add_size 200000
pci  0000:19:00.0: окно моста [mem 0x00100000-0x002fffff 64bit pref] к [bus 1a-1d] add_size 200000
pci  0000:19:00.0: окно моста [mem 0x00200000-0x015fffff] к [bus 1a-1d] add_size 200000
pci  0000:19:00.0: res[14]=[mem 0x00200000-0x015fffff] get_res_add_size add_size 200000
pci  0000:19:00.0: res[15]=[mem 0x00100000-0x002fffff 64bit pref] get_res_add_size add_size 200000
pci  0000:19:00.0: res[13]=[io  0x1000-0x2fff] get_res_add_size add_size 1000
pci  0000:19:00.0: BAR 14: не удается назначить память (размер 0x1600000)
pci  0000:19:00.0: BAR 15: назначен [mem 0xea800000-0xeabfffff 64bit pref]
pci  0000:19:00.0: BAR 13: не удается назначить ввод-вывод (размер 0x3000)
pci  0000:19:00.0: BAR 14: назначен [mem 0xea800000-0xebbfffff]
pci  0000:19:00.0: BAR 15: не удается назначить память с предпочтением (размер 0x200000)
pci  0000:19:00.0: BAR 13: назначен [io  0x7000-0x8fff]
pci  0000:19:00.0: BAR 14: не удается назначить память (размер 0x1400000)
pci  0000:19:00.0: не удалось добавить 200000 res[14]=[mem 0xea800000-0xebbfffff]
pci  0000:19:00.0: BAR 13: не удается назначить ввод-вывод (размер 0x2000)
pci  0000:19:00.0: не удалось добавить 1000 res[13]=[io  0x7000-0x8fff]
pci  0000:1a:00.0: res[15]=[mem 0x00100000-0x002fffff 64bit pref] get_res_add_size add_size 200000
pci  0000:1a:00.0: BAR 14: назначен [mem 0xea800000-0xebbfffff]
pci  0000:1a:00.0: BAR 15: не удается назначить память с предпочтением (размер 0x400000)
pci  0000:1a:00.0: BAR 13: назначен [io  0x7000-0x8fff]
pci  0000:1a:00.0: BAR 14: назначен [mem 0xea800000-0xebbfffff]
pci  0000:1a:00.0: BAR 15: не удается назначить память с предпочтением (размер 0x200000)
pci  0000:1b:02.0: res[15]=[mem 0x00100000-0x001fffff 64bit pref] get_res_add_size add_size 100000
pci  0000:1b:04.0: res[15]=[mem 0x00100000-0x001fffff 64bit pref] get_res_add_size add_size 100000
pci  0000:1b:02.0: BAR 14: назначен [mem 0xea800000-0xeb1fffff]
pci  0000:1b:04.0: BAR 14: назначен [mem 0xeb200000-0xebbfffff]
pci  0000:1b:02.0: BAR 15: не удается назначить память с предпочтением (размер 0x200000)
pci  0000:1b:04.0: BAR 15: не удается назначить память с предпочтением (размер 0x200000)
pci  0000:1b:02.0: BAR 13: назначен [io  0x7000-0x7fff]
pci  0000:1b:04.0: BAR 13: назначен [io  0x8000-0x8fff]
pci  0000:1b:02.0: BAR 14: назначен [mem 0xea800000-0xeb1fffff]
pci  0000:1b:04.0: BAR 14: назначен [mem 0xeb200000-0xebbfffff]
pci  0000:1b:02.0: BAR 15: не удается назначить память с предпочтением (размер 0x100000)
pci  0000:1b:04.0: BAR 15: не удается назначить память с предпочтением (размер 0x100000)
pci  0000:1c:00.0: reg 184: [mem 0xea800000-0xea803fff 64bit pref]
pci  0000:1c:00.0: reg 190: [mem 0xea820000-0xea823fff 64bit pref]
pci  0000:1c:00.0: reg 184: [mem 0xea800000-0xea803fff 64bit pref]
pci  0000:1c:00.0: reg 184: [mem 0xea800000-0xea803fff 64bit pref]
pci  0000:1c:00.0: reg 190: [mem 0xea820000-0xea823fff 64bit pref]
pci  0000:1c:00.0: reg 184: [mem 0xea800000-0xea803fff 64bit pref]
pci  0000:1c:00.0: reg 190: [mem 0xea820000-0xea823fff 64bit pref]
pci  0000:1c:00.1: reg 184: [mem 0xea840000-0xea843fff 64bit pref]
pci  0000:1c:00.0: reg 184: [mem 0xea800000-0xea803fff 64bit pref]
pci  0000:1c:00.0: reg 190: [mem 0xea820000-0xea823fff 64bit pref]
pci  0000:1c:00.1: reg 190: [mem 0xea860000-0xea863fff 64bit pref]
pci  0000:1c:00.0: reg 184: [mem 0xea800000-0xea803fff 64bit pref]
pci  0000:1c:00.0: reg 190: [mem 0xea820000-0xea823fff 64bit pref]
pci  0000:1c:00.1: reg 184: [mem 0xea840000-0xea843fff 64bit pref]
pci  0000:1c:00.0: res[7]=[mem 0xea800000-0xea7fffff 64bit pref] get_res_add_size add_size 20000
pci  0000:1c:00.0: res[10]=[mem 0xea820000-0xea81ffff 64bit pref] get_res_add_size add_size 20000
pci  0000:1c:00.1: res[7]=[mem 0xea840000-0xea83ffff 64bit pref] get_res_add_size add_size 20000
pci  0000:1c:00.1: res[10]=[mem 0xea860000-0xea85ffff 64bit pref] get_res_add_size add_size 20000
pci  0000:1c:00.0: BAR 1: назначен [mem 0xea800000-0xeabfffff]
pci  0000:1c:00.1: BAR 1: назначен [mem 0xeac00000-0xeaffffff]
pci  0000:1c:00.0: BAR 0: назначен [mem 0xeb000000-0xeb01ffff]
pci  0000:1c:00.1: BAR 0: назначен [mem 0xeb020000-0xeb03ffff]
pci  0000:1c:00.0: BAR 3: назначен [mem 0xeb040000-0xeb043fff]
pci  0000:1c:00.0: reg 184: [mem 0xea800000-0xea803fff 64bit pref]
pci  0000:1c:00.0: BAR 7: назначен [mem 0xeb044000-0xeb063fff 64bit pref]
pci  0000:1c:00.0: reg 190: [mem 0xea820000-0xea823fff 64bit pref]
pci  0000:1c:00.0: BAR 10: назначен [mem 0xeb064000-0xeb083fff 64bit pref]
pci  0000:1c:00.1: BAR 3: назначен [mem 0xeb084000-0xeb087fff]
pci  0000:1c:00.1: reg 184: [mem 0xea840000-0xea843fff 64bit pref]
pci  0000:1c:00.1: BAR 7: назначен [mem 0xeb088000-0xeb0a7fff 64bit pref]
pci  0000:1c:00.1: reg 190: [mem 0xea860000-0xea863fff 64bit pref]
pci  0000:1c:00.1: BAR 10: назначен [mem 0xeb0a8000-0xeb0c7fff 64bit pref]
pci  0000:1c:00.0: BAR 2: назначен [io  0x7000-0x701f]
pci  0000:1c:00.1: BAR 2: назначен [io  0x7020-0x703f]
pci  0000:1b:02.0:     pci  мост к [bus 1c]
pci  0000:1b:02.0:   окно моста [io  0x7000-0x7fff]
pci  0000:1b:02.0:   окно моста [mem 0xea800000-0xeb1fffff]
pci  0000:1d:00.0: reg 184: [mem 0xea900000-0xea903fff 64bit pref]
pci  0000:1d:00.0: reg 190: [mem 0xea920000-0xea923fff 64bit pref]
pci  0000:1d:00.0: reg 184: [mem 0xea900000-0xea903fff 64bit pref]
pci  0000:1d:00.0: reg 184: [mem 0xea900000-0xea903fff 64bit pref]
pci  0000:1d:00.0: reg 190: [mem 0xea920000-0xea923fff 64bit pref]
pci  0000:1d:00.0: reg 184: [mem 0xea900000-0xea903fff 64bit pref]
pci  0000:1d:00.0: reg 190: [mem 0xea920000-0xea923fff 64bit pref]
pci  0000:1d:00.1: reg 184: [mem 0xea940000-0xea943fff 64bit pref]
pci  0000:1d:00.0: reg 184: [mem 0xea900000-0xea903fff 64bit pref]
pci  0000:1d:00.0: reg 190: [mem 0xea920000-0xea923fff 64bit pref]
pci  0000:1d:00.1: reg 190: [mem 0xea960000-0xea963fff 64bit pref]
pci  0000:1d:00.0: reg 184: [mem 0xea900000-0xea903fff 64bit pref]
pci  0000:1d:00.0: reg 190: [mem 0xea920000-0xea923fff 64bit pref]
pci  0000:1d:00.1: reg 184: [mem 0xea940000-0xea943fff 64bit pref]
pci  0000:1d:00.0: res[7]=[mem 0xea900000-0xea8fffff 64bit pref] get_res_add_size add_size 20000
pci  0000:1d:00.0: res[10]=[mem 0xea920000-0xea91ffff 64bit pref] get_res_add_size add_size 20000
pci  0000:1d:00.1: res[7]=[mem 0xea940000-0xea93ffff 64bit pref] get_res_add_size add_size 20000
pci  0000:1d:00.1: res[10]=[mem 0xea960000-0xea95ffff 64bit pref] get_res_add_size add_size 20000
pci  0000:1d:00.0: BAR 1: назначен [mem 0xeb400000-0xeb7fffff]
pci  0000:1d:00.1: BAR 1: назначен [mem 0xeb800000-0xebbfffff]
pci  0000:1d:00.0: BAR 0: назначен [mem 0xeb200000-0xeb21ffff]
pci  0000:1d:00.1: BAR 0: назначен [mem 0xeb220000-0xeb23ffff]
pci  0000:1d:00.0: BAR 3: назначен [mem 0xeb240000-0xeb243fff]
pci  0000:1d:00.0: reg 184: [mem 0xea900000-0xea903fff 64bit pref]
pci  0000:1d:00.0: BAR 7: назначен [mem 0xeb244000-0xeb263fff 64bit pref]
pci  0000:1d:00.0: reg 190: [mem 0xea920000-0xea923fff 64bit pref]
pci  0000:1d:00.0: BAR 10: назначен [mem 0xeb264000-0xeb283fff 64bit pref]
pci  0000:1d:00.1: BAR 3: назначен [mem 0xeb284000-0xeb287fff]
pci  0000:1d:00.1: reg 184: [mem 0xea940000-0xea943fff 64bit pref]
pci  0000:1d:00.1: BAR 7: назначен [mem 0xeb288000-0xeb2a7fff 64bit pref]
pci  0000:1d:00.1: reg 190: [mem 0xea960000-0xea963fff 64bit pref]
pci  0000:1d:00.1: BAR 10: назначен [mem 0xeb2a8000-0xeb2c7fff 64bit pref]
pci  0000:1d:00.0: BAR 2: назначен [io  0x8000-0x801f]
pci  0000:1d:00.1: BAR 2: назначен [io  0x8020-0x803f]
pci  0000:1b:04.0:     pci  мост к [bus 1d]
pci  0000:1b:04.0:   окно моста [io  0x8000-0x8fff]
pci  0000:1b:04.0:   окно моста [mem 0xeb200000-0xebbfffff]
pci  0000:1a:00.0:     pci  мост к [bus 1b-1d]
pci  0000:1a:00.0:   окно моста [io  0x7000-0x8fff]
pci  0000:1a:00.0:   окно моста [mem 0xea800000-0xebbfffff]
pci  0000:19:00.0:     pci  мост к [bus 1a-1d]
pci  0000:19:00.0:   окно моста [io  0x7000-0x8fff]
pci  0000:19:00.0:   окно моста [mem 0xea800000-0xebbfffff]

ВОПРОС

Можно ли как-то сказать ядру (например, через параметр), чтобы оно автоматически это сделало? Что вызывает эту проблему изначально?

Спасибо заранее!

Обновление

Так как описанное исправление не работает на системе 4.x (фактически начиная с 3.12, я полагаю), я посмотрел на ядро и обнаружил, что если я отключу PCI ASPM (который уже был отключен ACPI (это также можно принудительно сделать с помощью pcie_aspm=off в параметре загрузки ядра)), следующее небольшое исправление (на 4.4.0) решает проблему с нулевым указателем ядра:

--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -552,11 +552,12 @@ static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev)
 void pcie_aspm_init_link_state(struct pci_dev *pdev)
 {
        struct pcie_link_state *link;
-       int blacklist = !!pcie_aspm_sanity_check(pdev);
-
+       int blacklist;
        if (!aspm_support_enabled)
                return;

+       blacklist = !!pcie_aspm_sanity_check(pdev);
+
        if (pdev->link_state)
                return;

Довольно странно, что проверка корректности выполняется, если функция сама же деактивирована, фактическое обращение к нулевому указателю произошло в pcie_aspm_sanity_check в этой строке list_for_each_entry(child, &pdev->subordinate->devices, bus_list) {. Это ошибка ядра?

Можно ли как-то сказать ядру (например, через параметр), чтобы оно автоматически это сделало?

Попробуйте загрузиться с параметром pci=realloc, у нас были аналогичные проблемы с горячей заменой дисков NVMe на древних материнских платах, пока мы не передали этот параметр.

Ответ или решение

Проблема с назначением памяти PCI BAR в ядре Linux 3.x и новее

На вашей машине IBM x3850 типа 8864 вы столкнулись с проблемой, что ядро 3.10 или более новой версии не может правильно инициализировать все слоты PCI, в отличие от ядра 2.6.32, которое работает безупречно. При этом ядро генерирует предупреждения, например:

pci 0000:19:00.0: BAR 14: can't assign mem (size 0x1a00000)
pci 0000:19:00.0: BAR 13: can't assign io (size 0x3000)

Это приводит к тому, что ваша сетевая карта не может загрузиться, так как шина PCI некорректно инициализируется.

Причины проблемы

Среди причин, по которым могут возникать такие проблемы с назначением памяти PCI BAR, можно выделить:

  1. Изменения в управлении PCI в ядре: С выходом новых версий ядра Linux может меняться логика управления памятью и шинами PCI. Новые механизмы могут быть несовместимы с устаревшим оборудованием.

  2. Настройки BIOS/UEFI: Иногда параметры конфигурации системы, такие как настройки ACPI и ASPM (Active State Power Management), могут оказывать влияние на управление шинами PCI.

  3. Сложная иерархия PCI: В вашем случае вы наблюдаете сложную иерархию PCI, включающую переходы между шинами PCIe и PCI-X, что может приводить к конфликтам адресации памяти.

Возможные решения

1. Автоматическое устранение проблемы с помощью параметров ядра

Чтобы попробовать решить проблему, вы можете добавить опцию загрузки pci=realloc. Эта опция позволяет ядру автоматически перераспределять ресурсы шины PCI. Это может помочь в случаях, когда память не назначается должным образом.

Пример изменения параметров загрузки для GRUB:

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash pci=realloc"

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

sudo update-grub

2. Ручное исправление через sysfs

Как вы уже упомянули, удаление корневого PCI-шины и последующая повторная инициализация могут временно решить проблему:

echo 1 > /sys/bus/pci/devices/0000:19:00.0/remove
echo 1 > /sys/bus/pci/rescan

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

3. Отключение ASPM

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

pcie_aspm=off

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

Заключение

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

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

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

Капча загружается...