3. Как работает адресация
Адресуемые устройства используют следующие свойства для кодирования адресной информации в дереве устройств:
reg #address-cells #size-cells Каждое адресуемое устройство получает список reg кортежей в формате: reg = < address1 length1 [address2 length2] [address3 length3] ... >.
Примечание ред.. По определению, кортеж ( tuple )- это упорядоченный набор даных фиксированной длины. Кортеж отличается от списка или массива тем, что элементы кортежа могут принадлежать разным типам и набор таких типов заранее определён типом кортежа, а значит, и размер кортежа также определён.
Каждый кортеж представляет собой диапазон адресов, используемый устройством.
Каждое значение адреса представляет собой список из одного или нескольких 32-битных целых чисел, называемых ячейками (cells). Точно так же значение длины (length) может быть списком ячеек или пустым.
Поскольку поля адреса и длины являются переменными и имеют переменный размер, свойства #address-cells и #size-cells родительского узла используются для определения количества ячеек в каждом поле. Или, другими словами, для правильной интерпретации свойства reg требуются значения #address-cells и #size-cells родительского узла.
Чтобы увидеть, как все это работает, давайте добавим свойства адресации в образец дерева устройств, начиная с процессоров.
3.1. Адресация ЦП
Узлы ЦП представляют собой простейший случай, когда речь идет об адресации. Каждому ЦП назначается один уникальный идентификатор, и с идентификаторами ЦП не связан размер.
В узле cpus значение свойства #address-cells=1 и #size-cells=0. Это означает, что дочерние значения reg - это один uint32, представляющий адрес без поля размера.
В этом случае двум процессорам назначаются адреса 0 и 1. Значение свойства #size-cells равно 0 для узлов процессора, потому что каждому процессору назначается только один адрес. Обратите внимание, что значение reg соответствует значению в имени узла. По соглашению, если узел имеет свойство reg, тогда имя узла должно включать адрес устройства, который является первым значением адреса в свойстве reg.
3.2. Устройства с отображением в памяти
Вместо одиночных значений адресов, как в узлах процессора, устройству с отображением в памяти назначается диапазон адресов, на которые оно будет отвечать.
Свойство #size-cells используется для указания размера поля длины в каждом дочернем кортеже reg. В следующем примере каждое значение адреса составляет 1 ячейку (32 бита), и каждое значение длины также равно 1 ячейке, что типично для 32-битных систем.
64-битные машины могут использовать значение #address-cells=2 и #size-cells=2 чтобы получить 64-битную адресацию в дереве устройств.
Каждому устройству назначается базовый адрес и диапазон адресов. Для портов GPIO в этом примере назначены два диапазона адресов:
0x101f3000 - 0x101f3fff 0x101f4000 - 0x101f400f Некоторые устройства подключены к шине с другой схемой адресации. Например, устройство можно подключить к внешней шине с помощью дискретных линий выбора микросхемы. Поскольку каждый родительский узел определяет домен адресации для своих дочерних узлов, отображение адресов может быть выбрано для наилучшего описания системы.
В приведенном ниже примере показано назначение адреса для устройств, подключенных к внешней шине, с номером выбора микросхемы, закодированным в адресе.
external-bus использует 2 ячейки для значения адреса: один для номера выбора чипа (CS) и один для смещения от базового адреса выбора чипа (CS). Поле длины остается одной ячейкой, поскольку только часть смещения адреса должна иметь диапазон. Итак, в этом примере каждая запись reg содержит 3 ячейки; номер выбора чипа, смещение и длина.
Поскольку адресные домены принадлежат узлу и его дочерним узлам, родительские узлы могут определять любую схему адресации, имеющую смысл для шины. Узлы за пределами непосредственных родительских и дочерних узлов обычно не должны заботиться о локальном домене адресации, и адреса должны быть сопоставлены, чтобы перейти от одного домена к другому.
3.3. Устройства без отображения в памяти
Другие устройства не отображаются в память на шину процессора. У них могут быть диапазоны адресов, но они не доступны напрямую ЦП. Вместо этого драйвер родительского устройства будет выполнять косвенный доступ от имени ЦП.
В качестве примера с устройствами i2c каждому устройству назначается адрес, но с ним не связана длина или диапазон. Это похоже на назначение адресов ЦП.
3.4. Трансляция адресов (Ranges)
Мы говорили о том, как назначать адреса устройствам, но на данный момент эти адреса являются локальными только для узла устройства. Он еще не описывает, как сопоставить этот адрес с адресом, который может использовать ЦП. Корневой узел всегда описывает точку зрения ЦП на адресное пространство.
Дочерние узлы корня уже используют адресный домен ЦП и поэтому не нуждаются в явном отображении. Например, устройству serial @ 101f0000 напрямую назначается адрес 0x101f0000.
Узлы, которые не являются прямыми потомками корня, не используют адресный домен ЦП. Чтобы получить адрес, отображаемый в памяти, в дереве устройств должно быть указано, как транслировать адреса из одного домена в другой. Для этого используется свойство ranges.
Вот пример дерева устройств с добавленным свойством ranges.
Свойство ranges - это список трансляции адресов. Каждая запись в таблице диапазонов представляет собой тройной кортеж, содержащий :
дочерний адрес родительский адрес размер области в дочернем адресном пространстве. Размер каждого поля определяется путем взятия значения дочернего #address-cells, значения родительского #address-cells и значения дочернего #size-cells. Для внешней шины в нашем примере дочерний адрес составляет 2 ячейки, родительский адрес - 1 ячейка, а размер также равен 1 ячейке.
Транслируются три диапазона:
Смещение 0 для chip select 0 отображается в диапазон адресов 0x10100000 - 0x1010ffff Смещение 0 для chip select 1 отображается в диапазон адресов 0x10160000 - 0x1016ffff Смещение 0 для chip select 2 отображается в диапазон адресов 0x30000000 - 0x30ffffff В качестве альтернативы, если родительское и дочернее адресные пространства идентичны, то может вместо этого добавить в узел пустое свойство ranges. Наличие пустых диапазонов свойства означает, что адреса в дочернем адресном пространстве отображаются 1:1 в родительское адресное пространство.
Возникает вопрос, зачем вообще используется преобразование адресов, если все это можно записать с отображением 1:1.
Некоторые шины (например, PCI) имеют совершенно разные адресные пространства, детали которых должны быть доступны операционной системе. У других есть механизмы DMA, которым необходимо знать реальный адрес на шине. Иногда устройства необходимо сгруппировать вместе, потому что все они используют одно и то же программируемое физическое отображение адресов.
Использование отображения 1:1 во многом зависит от информации, необходимой операционной системе, и от конструкции оборудования.
Обратите внимание, что в узле i2c@1,0 нет свойства ranges Причина этого в том, что, в отличие от внешней шины, устройства на шине i2c не отображают в память в адресном пространстве ЦП. Вместо этого ЦП косвенно обращается к устройству rtc@58 через устройство i2c@1,0.
Отсутствие свойства ranges означает, что к устройству не может получить прямой доступ ни одно устройство, кроме его родительского.