LINUX.ORG.RU

PCI ресурсы (диапазоны памяти, портов)

 


0

2

Есть конфигурационное пространство устройства PCIe, которое в адресах PC даже не представлено, а читается косвенно, кажется через io-порты 0xC8C, 0xC8E. А вот в BAR реальный физ. адрес региона. Откуда диапазоны адресов, размеры берутся в описаниях устройств? Я не понимаю. BAR 1шт., а ресурсов 3шт.

Есть код

mqnic->hw_regs_size = pci_resource_len(pdev, 0);
mqnic->hw_regs_phys = pci_resource_start(pdev, 0);
mqnic->app_hw_regs_size = pci_resource_len(pdev, 2);
mqnic->app_hw_regs_phys = pci_resource_start(pdev, 2);
mqnic->ram_hw_regs_size = pci_resource_len(pdev, 4);
mqnic->ram_hw_regs_phys = pci_resource_start(pdev, 4);

pci_resource_xxx это макросы из <include/linux/pci.h>.

.....
/*
 * These helpers provide future and backwards compatibility
 * for accessing popular PCI BAR info
 */
#define pci_resource_start(dev, bar)	((dev)->resource[(bar)].start)
#define pci_resource_end(dev, bar)	((dev)->resource[(bar)].end)
.....

Но где оно заполняется, где бы было "->resource[" как lvalue, не нашел. В драйвере нет. В функциях ядра есть, но где и когда их драйвер вызывает не знаю.

Где эта таблица ресурсов может заполняться?



Последнее исправление: bugs-bunny (всего исправлений: 1)

Устройства сами экспортируют эти данные через MMIO. Можно (и нужно) читать процессором прямо оттуда.

$ sudo cat /proc/iomem |& fgrep MMCONFIG
  f0000000-f7ffffff : PCI MMCONFIG 0000 [bus 00-7f]

0xC8C / 0xC8E - legacy indirect PCI mode, адрeсует первые 256 байт из 4KB конфига. Не адрусет полный PCI-express.

https://wiki.osdev.org/PCI#Memory_Mapped_PCI_Configuration_Space_Access:

PCI Express introduced a new way to access PCI configuration space, where it’s simply memory mapped and no IO ports are used. This access mechanism is described in PCI Express.

https://wiki.osdev.org/PCI_Express#Extended_PCI_Bus_Numbering

Адрес MMCONFIG достается через ACPI ‘MCFG’ table:

# acpidump -b
$ iasl -d mcfg.dat

$ fgrep 'Base Add' mcfg.dsl
[02Ch 0044   8]                 Base Address : 00000000F0000000

Совпадает с /proc/iomem.

sf ★★★
()
Последнее исправление: sf (всего исправлений: 1)
Ответ на: комментарий от sf

Сорри. Всё напутал.

struct pci_dev { ... struct resource resource[DEVICE_COUNT_RESOURCE]; } - внутренняя структура ядра.

Берем пример вычисления resource из PCI конфига: drivers/pci/probe.c:__pci_read_base().

static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
{
        unsigned int pos, reg;
        // ...

        for (pos = 0; pos < howmany; pos++) {
                struct resource *res = &dev->resource[pos];
                reg = PCI_BASE_ADDRESS_0 + (pos << 2);
                pos += __pci_read_base(dev, pci_bar_unknown, res, reg);
        }
        ...

Вызывается из pci_setup_device().

sf ★★★
()

Где эта таблица ресурсов может заполняться?

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

Общая задача какая, написать драйвер или что то специфическое

I-Love-Microsoft ★★★★★
()
Последнее исправление: I-Love-Microsoft (всего исправлений: 1)

Почему BAR 1шт? Регионы в config-е pcie-устройства (они же resource в /sys/devices/pci0000:00/0000:00:1f.2) индексируются от 0 до 5 и каждый из них, если он есть, может иметь тип I/O space или Memory Space.

Пример из lspci -vvv для разных устройств

00:1f.2 SATA controller: Intel Corporation C600/X79 series chipset 6-Port SATA AHCI Controller (rev 05) (prog-if 01 [AHCI 1.0])
        Subsystem: Elitegroup Computer Systems C600/X79 series chipset 6-Port SATA AHCI Controller
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
        Status: Cap+ 66MHz+ UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0
        Interrupt: pin B routed to IRQ 34
        Region 0: I/O ports at f070 [size=8]
        Region 1: I/O ports at f060 [size=4]
        Region 2: I/O ports at f050 [size=8]
        Region 3: I/O ports at f040 [size=4]
        Region 4: I/O ports at f020 [size=32]
        Region 5: Memory at f9125000 (32-bit, non-prefetchable) [size=2K]

03:00.0 VGA compatible controller: NVIDIA Corporation GP104 [GeForce GTX 1070 Ti] (rev a1) (prog-if 00 [VGA controller])
        Subsystem: NVIDIA Corporation GP104 [GeForce GTX 1070 Ti]
        Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx+
        Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
        Latency: 0
        Interrupt: pin A routed to IRQ 59
        Region 0: Memory at fa000000 (32-bit, non-prefetchable) [size=16M]
        Region 1: Memory at b0000000 (64-bit, prefetchable) [size=256M]
        Region 3: Memory at c0000000 (64-bit, prefetchable) [size=32M]
        Region 5: I/O ports at e000 [size=128]
        Expansion ROM at 000c0000 [virtual] [disabled] [size=128K]


~ % ls -l /sys/bus/pci/devices/0000:00:1f.2/resource*
-r--r--r-- 1 root root 4096 Sep 13 10:43 /sys/bus/pci/devices/0000:00:1f.2/resource
-rw------- 1 root root    8 Sep 13 10:49 /sys/bus/pci/devices/0000:00:1f.2/resource0
-rw------- 1 root root    4 Sep 13 10:49 /sys/bus/pci/devices/0000:00:1f.2/resource1
-rw------- 1 root root    8 Sep 13 10:49 /sys/bus/pci/devices/0000:00:1f.2/resource2
-rw------- 1 root root    4 Sep 13 10:49 /sys/bus/pci/devices/0000:00:1f.2/resource3
-rw------- 1 root root   32 Sep 13 10:49 /sys/bus/pci/devices/0000:00:1f.2/resource4
-rw------- 1 root root 2048 Sep 13 10:49 /sys/bus/pci/devices/0000:00:1f.2/resource5

~ % ls -l /sys/bus/pci/devices/0000:03:00.0/resource*
-r--r--r-- 1 root root      4096 Sep 12 22:35 /sys/bus/pci/devices/0000:03:00.0/resource
-rw------- 1 root root  16777216 Sep 13 10:54 /sys/bus/pci/devices/0000:03:00.0/resource0
-rw------- 1 root root 268435456 Sep 13 10:54 /sys/bus/pci/devices/0000:03:00.0/resource1
-rw------- 1 root root 268435456 Sep 13 10:54 /sys/bus/pci/devices/0000:03:00.0/resource1_wc
-rw------- 1 root root  33554432 Sep 13 10:54 /sys/bus/pci/devices/0000:03:00.0/resource3
-rw------- 1 root root  33554432 Sep 13 10:54 /sys/bus/pci/devices/0000:03:00.0/resource3_wc
-rw------- 1 root root       128 Sep 13 10:54 /sys/bus/pci/devices/0000:03:00.0/resource5



GPFault ★★
()
Ответ на: комментарий от sf

Все немного не так у меня. 1 BAR, но в этом драйвере ресурс==BAR не работает. Этот регион 16МБ поделен на группы регистров, которые берутся из dev->resource[]. https://docs.corundum.io/en/latest/rb/index.html, так они располагаются в односвязном списке в одном BARе. Это проект OpenSource сетевухи.

А это в драйвере

 mqnic->hw_regs_size = pci_resource_len(pdev, 0);
 mqnic->hw_regs_phys = pci_resource_start(pdev, 0);
 mqnic->app_hw_regs_size = pci_resource_len(pdev, 2);
 mqnic->app_hw_regs_phys = pci_resource_start(pdev, 2);
 mqnic->ram_hw_regs_size = pci_resource_len(pdev, 4);
 mqnic->ram_hw_regs_phys = pci_resource_start(pdev, 4);

Вот я и думаю, что это какой-то нестандарт учудили.

bugs-bunny
() автор топика
Ответ на: комментарий от GPFault

Region 5: Memory at f9125000 (32-bit, non-prefetchable) [size=2K]

Кстати вопрос, Вы видели формат этого BAR-регистра? 28 бит базовый адрес страницы, бит memory/io.

Откуда взято, что размером 2КБ эта память?

bugs-bunny
() автор топика
Ответ на: комментарий от bugs-bunny

Очень интересный вопрос кстати, никгда не задумывался. В ответе до конца не уверен. Судя по написанному тут - https://stackoverflow.com/a/13521422 на момент окончания инициализации эта информация на шине уже не доступна, можно лишь утверждать что она не больше чем alignment установленного адреса. Но может быть меньше чем alignment. Соответственно узнать её можно только у того кто проводил инициализацию - то есть у ОС. В linux это где-то в районе https://elixir.bootlin.com/linux/latest/source/drivers/pci/probe.c#L111 происходит, правда не очень понимаю что делается с уствройствами проинициализированными ранее, при старте BIOS.

БольшИе размеры BAR, которые уже достаточно давно работают - позволяюь например смапить все гигабайты видеопамяти AMD-ных видеокарт - тоже идут через некий механизм расширения. Если для BAR указан type=0x2, то следующего BAR нет, а занимаемые им байты являются старшей частью адреса. А размеры могут меняться уже после первичной инициализации через Resizable BAR Control Register внутри Resizable BAR Extended Capability Header.

В следующей перспективе это видимо будет заменяться на механизм через расширение «PCI Enhanced Allocation BARs»

GPFault ★★
()
Ответ на: комментарий от bugs-bunny

Как именно использовать аддреса внутри одного bar - это детали реализации устройства. Специфиакция PCI на эту тему по идее ничего не говорит.

Сталкивался с тем что например в 256КБайтном BAR - есть один адрес чтение которого вешает CPU намертво. При этом драйвер туда просто не лезет и использует остальные - устройство просто работает.

GPFault ★★
()
Ответ на: комментарий от bugs-bunny

С виду похоже, что устройство реализует 3 64-битных BARа. +1 к комментарию @GPFault: BARы описывают только сами области памяти для MMIO с устройством, но не свойства этой памяти. Свойства определяются железом.

У современных устройств куча «регистров» в одном MMIO space. Даже у UART8250 8 регистров (в одном MMIO регионе). PCI ничего этого не онисывает, а только говорит о типе устройства. https://docs.corundum.io/en/latest/rb/index.html выглядт как описание регистров описываемых одним BAR-ом.

sf ★★★
()
Ответ на: комментарий от sf

Спасибо. Да, похоже все регистры разных функциональных блоков карты находятся все в одном BAR-е. https://docs.corundum.io/en/latest/rb/index.html конечно видел, односвязный список с группами регистров. Но кто в pci_device заполняет resources[] не нашел.

bugs-bunny
() автор топика
Ответ на: комментарий от bugs-bunny

Но кто в pci_device заполняет resources[] не нашел.

В struct pci_dev есть только struct resource resource[DEVICE_COUNT_RESOURCE]; (заполняется в drivers/pci/probe.c:__pci_read_base()). В struct pci_bus есть struct list_head resources;

sf ★★★
()
Ответ на: комментарий от sf

Вижу, заполняет. Пользуется активно pci_read_config_word, _dword и т.п. Как-то это драйверу устройства должно приходить в виде колбэка для заполнения.

bugs-bunny
() автор топика
Ответ на: комментарий от bugs-bunny

pci_read_config_word, _dword

Я в своих драйверах полагаюсь, что config space это состояние непосредственно в устройстве. Например, если сбросить прошивку и порт PCI оказывается неактивен, то пропадают данные в lspci, а оно то как раз отображает это config space в реалтайме, показывая те или иные флаги по факту, можно даже взять hex dump всего конфига, его длина динамическая если не ошибаюсь, но видимо имеет лимиты

Если ты пишешь драйвер, просто читай интересующие адреса. Трудно понять, почему тебе требуются какие то нестандартные действия

I-Love-Microsoft ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.