7. Машина с мостом Host/PCI 7.1. Усовершенствованный образец машины Теперь, когда мы определились с основами, давайте добавим некоторое оборудование к образцу машины, чтобы обсудить некоторые из более сложных вариантов использования. Усовершенствованный образец машины добавляет мост хоста PCI с регистрами управления, отображаемый в память по адресу 0x10180000, и BAR, запрограммированный на запуск выше адреса 0x80000000. Учитывая то, что мы уже знаем о дереве устройств, мы можем начать с добавления следующего узла для описания моста хоста PCI. ![]() 7.2. Мост Host/PCI В этом разделе описывается узел моста Host/PCI. Обратите внимание, что в этом разделе предполагается наличие некоторых базовых знаний о PCI. Это не руководство по PCI, если вам нужна более подробная информация, прочтите PCI System Architecture by Tom Shanley/Don Anderson , а также PCI Bus Binding 7.2.1. Нумерация шины PCI Каждый сегмент шины PCI имеет уникальный номер, и нумерация шины отображается в узле pci с помощью свойства bus-range, которое содержит две ячейки. Первая ячейка дает номер шины, присвоенный этому узлу, а вторая ячейка дает максимальный номер шины любой из подчиненных шин PCI. У тестовой машины одна шина pci, поэтому обе ячейки равны 0. ![]() 7.2.2. Трансляция адресов PCI Подобно локальной шине, описанной ранее, адресное пространство PCI полностью отделено от адресного пространства ЦП, поэтому для перехода от адреса PCI к адресу ЦП требуется преобразование адресов. Как всегда, это делается с помощью свойств range, #address-cells и #size-cells. ![]() Как видите, дочерние адреса (адреса PCI) используют 3 ячейки, а диапазоны PCI кодируются в 2 ячейки. Возникает вопрос, зачем нам нужны три 32-битные ячейки для указания адреса PCI. Эти три ячейки помечены как Phys.hi, Phys.mid и Phys.low Адреса PCI имеют ширину 64 бита и закодированы в Phys.mid и Phys.low. При этом Phys.high является битовым полем:
Для преобразования адресов PCI важными полями являются биты p и ss. Значения p и ss в Phys.hi определяют, к какому адресному пространству PCI осуществляется доступ. В представленном здесь свойстве range есть три региона: Наличие битового поля phys.hi означает что операционная система должна знать, что узел представляет собой мост PCI, чтобы она могла игнорировать нерелевантные поля для целей трансляции. ОС будет искать строку pci в узлах шины PCI, чтобы определить, нужно ли маскировать дополнительные поля. 7.2.3. Трансляция адресов PCI DMA Вышеуказанные диапазоны определяют, как ЦП видит память PCI, и помогают ЦП настраивать правильные окна памяти и записывать правильные параметры в различные регистры устройства PCI. Иногда это называют исходящей памятью (outbound memory). Особый случай трансляции адресов касается того, как оборудование хоста PCI видит основную память системы. Это происходит, когда хост-контроллер PCI будет действовать как главный и независимо обращаться к основной памяти системы. Поскольку это часто другое представление, чем у ЦП (из-за того, как были подключены линии памяти), это может потребоваться запрограммировать в хост-контроллере PCI при инициализации. Это рассматривается как своего рода DMA, поскольку шина PCI независимо выполняет прямой доступ к памяти, и по этой причине сопоставления называются dma-range. Этот тип отображения памяти иногда называют входящей памятью (inbound memory), который не является частью спецификации дерева устройств PCI. В некоторых случаях ПЗУ (BIOS) или аналогичный будет настраивать эти регистры при загрузке, но в других случаях контроллер PCI полностью не инициализирован, и эти преобразования необходимо настраивать из дерева устройств. Затем драйвер хоста PCI обычно анализирует свойство dma-range и соответствующим образом настраивает некоторые регистры в хост-контроллере. Расширяя пример выше: ![]() Эта запись dma-range указывает, что с точки зрения хост-контроллера PCI 512 Мб по адресу PCI 0x00000000 появятся в основной памяти ядра по адресу 0x80000000. Как видите, мы просто установили тип адреса ss равным 0x02, указывая, что это некоторая 32-битная память. 7.3. Расширенное отображение прерываний Теперь мы подошли к самому интересному - отображению прерываний PCI. Устройство PCI может инициировать прерывания, используя провода #INTA, #INTB, #INTC и #INTD. Знак решетки # перед именами прерываний означает, что активен низкий уровень, это общепринятое соглашение, и линии прерывания PCI всегда активны на низком уровне. Однофункциональное устройство обязано использовать #INTA для прерываний. Многофункциональное устройство должно использовать #INTA, если оно использует один вывод прерывания, #INTA и #INTB, если оно использует два вывода прерывания и т.д. Согласно этим правилам, #INTA обычно используется большим количеством функций, чем #INTB, #INTC. и #INTD. Чтобы распределить нагрузку по четырем линиям IRQ, поддерживающим #INTA - #INTD, каждый слот PCI или устройство обычно подключаются к разным входам на контроллере прерываний поочередно, чтобы избежать подключения всех клиентов #INTA к одной и той же входящей линии прерывания. Эта процедура называется переключением прерываний. Таким образом, дереву устройств требуется способ отображения каждого сигнала прерывания PCI на входы контроллера прерывания. Свойства #interrupt-cells, interrupt-map и interrupt-map-mask используются для описания отображения прерываний. Фактически, описанное здесь отображение прерываний не ограничивается шинами PCI, любой узел может указывать сложные карты прерываний, но случай PCI является наиболее распространенным. ![]() Обратите внимание, что номера прерываний PCI используют только одну ячейку, в отличие от контроллера прерываний системы, который использует 2 ячейки; один для номера IRQ и один для флагов. PCI требуется только одна ячейка для прерываний, потому что прерывания PCI всегда должны быть чувствительными к низкому уровню. В нашем примере платы у нас есть 2 слота PCI с 4 линиями прерывания, соответственно, поэтому мы должны сопоставить 8 линий прерывания с контроллером прерываний. Это делается с помощью свойства interrupt-map. Поскольку номера прерывания (#INTA и т.д.) недостаточно для различения нескольких устройств PCI на одной шине PCI, мы также должны указать, какое устройство PCI инициировало линию прерывания. У каждого устройства PCI есть уникальный номер устройства, который мы можем использовать. Чтобы различать прерывания нескольких устройств PCI, нам нужен кортеж, состоящий из номера устройства PCI и номера прерывания PCI. Мы создаем спецификатор единичного прерывания, который имеет четыре ячейки: Поскольку нам нужна только часть номера устройства в адресе PCI, используется свойство interrupt-map-mask, которое также состоит из 4-ного кортежа, как спецификатор единичного прерывания. Биты 1 в маске обозначают, какую часть спецификатора единичного прерывания следует учитывать. В нашем примере мы видим, что требуется только номер устройства, часть phys.hi, и нам нужны 3 бита, чтобы различать четыре линии прерывания (счетчик линий прерывания PCI начинается с 1, а не с 0!). Теперь мы можем построить свойство прерывания. Это свойство представляет собой таблицу, и каждая запись в этой таблице состоит из спецификатора прерывания дочернего модуля (шина PCI), родительского дескриптора (контроллера прерывания, который отвечает за обслуживание прерываний) и спецификатора прерывания родительского модуля. Итак, в первой строке мы можем прочитать, что прерывание PCI #INTA отображается на IRQ9, низкий уровень чувствительности нашего контроллера прерываний. Единственная отсутствующая часть на данный момент - это странные числа в спецификаторе прерывания модуля шины PCI. Важной частью спецификатора единичного прерывания является номер устройства из битового поля phys.hi. Номер устройства зависит от платы и зависит от того, как каждый хост-контроллер PCI активирует вывод IDSEL на каждом устройстве. В этом примере слоту PCI 1 назначен идентификатор устройства 24 (0x18), а слоту 2 PCI назначен идентификатор устройства 25 (0x19). Значение phys.hi для каждого слота определяется путем сдвига номера устройства на 11 бит в раздел ddddd битового поля следующим образом: phys.hi для слота 1 - 0xC000 phys.hi для слота 2 - 0xC800 В окончательном виде свойство interrupt-map показывает: Свойство interrupts = <8 0> ; описывает прерывания, которые может запускать сам контроллер хост/PCI-моста. Не путайте эти прерывания с прерываниями, которые могут вызывать устройства PCI (с использованием INTA, INTB, ...). Нужно отметить, что как и в случае со свойством interrupt-parent, наличие свойства interrupt-map на узле изменит контроллер прерывания по умолчанию для всех дочерних и внучатых узлов. В приведенном примере PCI это означает, что мост Host/PCI становится контроллером прерываний по умолчанию. Если устройство, подключенное через шину PCI, имеет прямое соединение с другим контроллером прерываний, ему также необходимо указать собственное свойство родительского прерывания. |
![]() |