У меня есть модель PCIe, написанная в System Verilog, хотя я думаю, что этот вопрос не зависит от языка. Модель выполняет чтение и запись конфигурации PCIe, а также чтение и запись в память при симуляции. Однако мне нужно «обнаружить» мое устройство PCIe и настроить регистры конфигурационного пространства в симуляции. Есть ли шаблонный фрагмент псевдокода, который представляет процесс перечисления Linux PCIe, что я могу просто добавить свои собственные функции транзакций моделей, чтобы я мог получить "Автобусную прогулку", за которой следует программирование BAR, включение SR-IOV, если оно обнаружено, Конфигурация MSIx? Похоже, это обычное упражнение для устройства PCIe, так что, возможно, есть модель.
Псевдокод алгоритма обнаружения устройства PCIe
Ответы (1)
Сделать это не так уж и сложно. В основном вы просматриваете пространство конфигурации, проверяя каждое возможное устройство на первой корневой шине 0. Когда устройство найдено, вы выделяете для него пространство памяти на основе его запрошенного размера и соответственно программируете полосы BAR. Если вы обнаружите какие-либо мосты, вы также сконфигурируете и активируете их - базовые регистры моста для этого являются стандартными. Это включает в себя назначение номеров восходящей и нисходящей шины, что затем позволяет вам пронумеровать новую нисходящую шину и так далее.
Мне пришлось сделать это один раз, чтобы получить доступ к карте ввода-вывода PCI в системе, в которой не было ОС или другой программной среды. Это было неплохо, и это было через два моста от двух производителей, а также регистры карты ввода-вывода и настройку корневого моста шины ЦП. Это был PCI, а не PCIe, но он был бы почти таким же. Вы даже могли бы сделать это с полностью жестко закодированными числами, если бы оборудование никогда не менялось, но в моем случае было несколько вариантов, поэтому мне действительно пришлось выполнить простое перечисление, чтобы найти номера устройств динамически. Одна из проблем заключается в том, что вам, возможно, придется немного подождать или повторить попытку, чтобы дать всем устройствам время подключиться к сети, прежде чем вы попытаетесь получить к ним доступ.
При этом я нашел эту книгу бесценной: Архитектура системы PCI (4-е издание). Я заметил, что есть также версия для PCIe: Архитектура системы PCI Express (1-е издание). Я бы определенно получил один из них, если вы еще этого не сделали. Эти книги содержат подробные алгоритмы и объяснения того, как все это делать. В то время я действительно не использовал и не ссылался на какой-либо код, но ...
Лучший ресурс кода, который я нашел, - это U-Boot. Он работает на столь же низком уровне, полностью автономен, при этом довольно мал и максимально прост. Например, перечисление начинается с того, что функция pci_init()
вызывает конкретную плату pci_xxx_init()
. Затем это устанавливает корневой мост, а затем вызывает pci_hose_scan_bus()
в drivers / pci / pci.c, чтобы выполнить реальную работу. Также ознакомьтесь с подпрограммами в drivers / pci / pci_auto.c, а также остальную часть папки.
Для вашей задачи вам, вероятно, понадобится очень небольшое подмножество, и вы можете просто вырезать части этих файлов в простой драйвер. В основном цикл for () и некоторые вызовы pci_read / write_config () с логикой для распознавания идентификаторов вашего устройства и моста.