Эскиз к диагностике шины PCI Express с помощью Link Training

24 Дек 2012

Эскиз к диагностике шины PCI Express с помощью Link Training

Топология шины PCI Express декларирует соединение двух ее агентов меж­ду собой по схеме «точка-точка». Па­ра­мет­ры каждого линка — предмет осо­бо­го внимания процедур BIOS. На этапе выполнения POST его задача со­сто­ит в том, чтобы определить функциональность таблично заданных аген­тов и подготовить их для операционной системы с по­мо­щью спе­ци­аль­ной про­це­ду­ры, которая называется Link Training. Инициализационные про­це­ду­ры должны оп­ре­де­лить разрядность PCIe-шины и проверить ее го­тов­ность к работе в заданной полосе пропускания. Кроме того, вы­пол­ня­ет­ся еще ряд манипуляций в конфигурационном PCI-про­стран­стве, на которых мы останавливаться не будем, огра­ни­чив эксперименты стартовой процедурой, направленной, как следует из ее на­зва­ния, на запуск и «тре­ни­ров­ку» шинных соединений.

Операционная система принимает в эксплуатацию подсистему PCI Express как данность, и, как правило, не пе­ре­оп­ре­де­ля­ет ее параметры. Из этого правила есть одно маленькое, но очень существенное исключение: функ­ци­о­наль­ность PCIe-шины предполагает «горячую» замену плат расширения (только при наличии поддержки со сто­ро­ны платформы). А это значит, что процедура Link Training не запрещается после ее выполнения в BIOS и может в лю­бое время потребоваться для нужд операционки.

«Этим нужно воспользоваться!», — вскричал бы судья Криггс голосом Армена Джигарханяна.

«Блестящая идея», — подумали мы и решили набросать эскиз к диагностике компьютера в той части, которая ка­са­ет­ся проверки PCIe-шины.

Постановка задачи

Реализация задуманного потребует повторного инициирования процедуры Link Training для заданного PCIe-порта уже после старта платформы.

В структуре PCI Express Capability Structure есть регистр Link Control Register. Его бит Retrain Link можно установить в «единицу» для запуска процедуры Link Retrain. Статус ее завершения можно проконтролировать по состоянию бита Link Training в регистре Link Status Register.

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

  1. PCIe-контроллер будет аппаратно генерировать импульсные последовательности, заданные его разработчиком, оптимизированные для проверки соединительных цепей и пригодные для наблюдения внешними приборами.
  2. PCIe-контроллер при выполнении процедуры Link Training диагностирует функциональность линий заданного порта, и аппаратное отключение неисправных, выполняется только по результатам проверки. Мы ожидаем, что импульсы должны наблюдаться по всем линиям, что должно решить известную проблему с недоступностью неисправных линий Rx(i), Tx(i) из-за аппаратного их отключения на этапе POST.
  3. Процедура Link Training допускает цикличное выполнение. Результаты каждой итерации можно выводить в диагностический порт и мониторить их с помощью POST-карты. Например, порт 80h будет отображать разрядность шины, а в порт 81h — частоту. Предполагается, что для удобства данные визуализируются в двоично-десятичной  системе: код 2516h будет означать полосу пропускания в 2.5GT/s на 16-ти битной шине.  
  4. В качестве самопроверки можно намеренно вносить искажения путем замыкания керамических конденсаторов либо изоляцией ламелей PCIe-устройства, контролируя при этом статус процедуры Link Training на индикаторе POST-карты.

К недостаткам эксперимента (или чтобы сохранить лицо, скажем, — к особенностям :) можно отнести требование то­го порядка, что в список тестируемых линков будут включены только те из них, к которым подключены за­ве­до­мо исправные бортовые контроллеры либо контроллеры, установленные в неповрежденный PCIe-слот. Связи, обес­пе­чи­ва­ю­щие «пустые» слоты, отслеживаться не могут по определению. Из точки А шагнуть в неизвестность не пред­став­ля­ет­ся возможным. Процедура BIOS POST обычно отключает PCI Express мосты, если не найдено под­клю­чен­ных к ним устройств. Поэтому, регистры, требуемые для выполнения эксперимента, будут недоступны в кон­фи­гу­ра­ци­он­ном пространстве.

Описание эксперимента

Программный макет планируется отладить в среде MS-DOS, после чего возможна его реализация в виде UEFI-приложения или интеграция в Legacy BIOS. В качестве среды программирования используется язык ассемблера в версии Borland: TASM, TLINK и Turbo Debugger. Листинг программы приведен в Приложении.

Для последующей интеграции в BIOS намеренно не используются сервисные функции PCIBIOS (INT 1Ah) в силу того, что этот сервис может быть недоступен на момент выполнения макета в составе POST-процедуры. Доступ к PCI-пространству выполняется через порты Config_Address и Config_Data (0CF8h, 0CFCh).

Для простоты реализации макет не сканирует все конфигурационное пространство для поиска всех доступных PCIe линков. Адрес, задающий тестируемый порт, передается в виде константы BusDevFncReg, которую нужно уста­но­вить вручную перед ассемблированием. Обращения к INT 16h и INT 21h, необходимые в DOS версии, потребуется убрать при интеграции в BIOS.

Программа циклически выполняет Link Training и выводит в диагностические порты его результаты: порт 80h — Width (разрядность), порт 81h — Speed (скорость). При ошибке программа завершается шестнадцатибитным выводом в порт 80h значения 0FFFFh. Штатно работу эскизного макета можно прекратить, нажав любую клавишу. В этом случае в порт 80h выводится значение 0000h.

Программа была проверена на плате с чипсетом i915 (ASUS P5GPL-X). Тестировался 16-битный PCI Express порт между северным мостом и видеокартой ATI Radeon X800. При отсутствии ошибок: Speed=2.5 Gb/S, Width=16 bit, как и должно быть. В 16-битный порт 80h выводится код 2516h.

Если во время выполнения нашего теста имитировать короткое замыкание между линиями PCI Express, программа детектирует ошибку. Детально увидеть процессы по линиям Rx, Tx осциллограф с полосой пропускания 100 МГц не позволяет, но вносимые замыкания влияют на статус контроллера, а значит, Link Training выполняется. На ис­пы­ту­емой платформе, искусственное внесение ошибок препятствует завершению процедуры Link Training, в результате происходит выход по таймауту и программа завершается с выводом на индикаторы пост карты кода FFFFh.

Информация о разрядности и частоте шины PCIe доступна в статусном регистре и без повторного вы­пол­не­ния Link Training в сеансе ОС. В этом случае данные параметры являются результатом выполнения Link Training при старте платформы. Именно поэтому были необходимы самопроверка с искусственным внесением ошибок не­по­сред­ствен­но во время выполнения нашей программы, а также анализ времени выполнения процедуры, о котором будет идти речь ниже. Так мы убедились в том, что на испытуемой платформе Link Training в сеансе ОС действительно вы­пол­ня­ет­ся.

Для наборов системной логики и видео адаптеров NVidia, характерна поддержка переключения на меньшую раз­ряд­ность шины PCI Express, если часть линий неработоспособна. На плате ASUS A8N-E (AMD Socket 939, Nvidia nF4) в сочетании с видеокартой ASUS EN9800GT мы изолировали контакты старших восьми линий шины PCI Express бумажной вставкой. В результате, при старте платформы, шина инициализировалась в режиме 8 бит и ра­бо­то­спо­соб­ность видео адаптера сохранилась. При запуске нашей программы в сеансе ОС, на POST-карте получаем код 2508h. В режиме нормальной эксплуатации поддерживается разрядность в 16 бит, что подтверждается по­ка­за­ни­ями POST-карты:

 

Настройка на топологию платформы

Выбор адреса тестируемого PCIe-порта устанавливается вручную до ассемблирования программы. Для этого сле­ду­ет отредактировать константу BusDevFncReg.

Константа содержит битовые поля Bus, Device, Function, Register, задающие адрес в конфигурационном пространстве PCI. Эти параметры должны соответствовать адресу контроллера PCI Express, соответствующего тестируемому порту и представленному в конфигурационном пространстве как мост PCI-PCI. Параметр Register должен соответствовать адресу регистра Link Control внутри структуры PCI Express Capability. Смещение этого регистра относительно базового адреса структуры PCI Express Capability равно 10h. Заметим, что второй используемый нами регистр — Link Status имеет смещение 12h и находится в пределах того же 32-битного слова, что упрощает программное взаимодействие с ними. Базовый адрес структуры PCI Express Capability можно узнать из документации на чипсет, либо, если она недоступна, проследив цепочку Capability-структур в блоке конфигурационных регистров моста PCI-PCI, найти искомую структуру можно по Capability ID = 10h.

В соответствии со спецификацией PCI, битовые поля 32-битного регистра Configuration_Address, а значит и константа BusDevFncReg, формируются следующим образом:

D [31] = 1 for enable configuration space access
D [30-24] = 0000000b, reserved
D [23-16] = PCI Bus Number, 8-bit
D [15-11] = PCI Device Number, 5-bit
D [10-08] = PCI Function Number, 3-bit
D [07-00] = PCI Register Number, 8-bit, aligned by 4, bits [1-0] = 00b.

В экспериментах использовался диагностический контроллер IC80 V5.0 производства компании IC Book Labs. Устройство обеспечивает 16-битный вывод и возможность переназначения адреса диагностического порта, что существенно для обеспечения совместимости с некоторыми платформами. POST-карта также обеспечивает пошаговый режим с ожиданием нажатия кнопки после вывода каждого диагностического кода. Эта функция будет полезной при интеграции предлагаемого ассемблерного фрагмента в BIOS, так как делает возможным наблюдение быстропротекающих процессов при инициализации платформы.

Несколько слов об оценке времени выполнения процедуры Link Training. После ее завершения, в момент перехода на метку Train_Stop, регистр CX, используемый как декрементируемый счетчик цикла при ожидании выполнения Link Training, будет содержать 0, если имеет место одна из двух ошибок:

  1. Процедура не была запущена, контроллер сообщил о готовности на первой итерации цикла ожидания, то есть неожиданно быстро.
  2. Выход по таймауту, выполнено 65536 итераций, контроллер не сообщил о готовности.

Ненулевое значение CX может использоваться для оценки времени ожидания. Количество выполненных итераций равно разности 65536-CX. Например, CX=FFFFh означает выход после первой итерации, CX=FFFEh после второй, и т.д. Время выполнения одной итерации зависит от времени чтения регистра Configuration_Data и может быть различным у различных платформ. При необходимости точно измерить время выполнения, в программу следует добавить операции с системным таймером или TSC. А для определения причины ошибки, вызвавшей нулевое значение CX, может потребоваться дополнительный анализ статуса.

Справочная литература

Шина PCI, конфигурационное пространство и программный доступ к нему описывается в документе:
Шина PCI Express, структура PCI Express Capability и ее регистровые поля описываются в документе:
Перед выполнением экспериментов, рекомендуется также ознакомиться с документацией на набор системной логики исследуемой платформы, если, конечно, такая документация доступна. В нашем примере это документ:
Intel 915G/915GV/915GL/915P/915PL/910GL Express Chipset Datasheet. February 2005. Document number: 301467-005
  • LCTL — Link Control (D1:F0) на странице 155.
  • LSTS — Link Status (D1:F0) на >странице 156

Приложение. Листинг программы

;---------------------------------------------------------------------------;
;    PCI Express Link Training Debug Sample, for Intel 82915 North Bridge   ;
; Change Bus/Device/Function/Register for required platform and link number ;
;                    This edition for execution under DOS,                  ;
;                  remove INT 16h, INT 21h for BIOS edition                 ;
;---------------------------------------------------------------------------;
; Adiust  BusDevFncReg  for chipset model and link number
; Bus=0, Dev=1, Fnc=0, Reg=0B0h for North Bridge Intel 82915 x16 PCIe port
; D[31]=1 for enable configuration space access
; D[30-24]=0000000b, reserved
; D[23-16]=PCI Bus Number, 8-bit
; D[15-11]=PCI Device Number, 5-bit
; D[10-08]=PCI Function Number, 3-bit
; D[07-00]=PCI Register Number, 8-bit
; Register Number must be aligned by 4, bits [1,0] must be 00b
BusDevFncReg  EQU  800008B0h
;BusDevFncReg  EQU  80007090h
;--- Code segment ---
.386P
CODE_16  SEGMENT BYTE USE16
ASSUME CS:CODE_16, SS:STACK_16
ORG 0
PROGRAM PROC FAR
START:
;--- Start Link Training ---
Train_Make: cli               ; Disable interrupts
            mov   dx,0CF8h    ; PCI CONFIG_ADDRESS port
            mov   eax,BusDevFncReg
            out   dx,eax            ; Set address
            mov   dl,0FCh           ; PCI CONFIG_DATA port
            in    ax,dx       ; Read Link Control
            or    al,20h            ; Link Control.5=Retrain
            out   dx,ax       ; Write Link Control
            xor   cx,cx       ; Timeout wait 65536 iterations
Train_Wait: in    eax,dx            ; Read Link Status + Link Control
            bt    eax,26            ; Link Status.10  ( 26-16=10 )
            jc    Train_Stop  ; Exit if training error, CF=1
            bt    eax,27            ; Link Status.11  ( 27-16=11 )
            jnc   Train_Stop  ; Exit if training complete OK, CF=0
            loop  Train_Wait  ; Cycle if training in progress
            stc               ; CF=1 means error, timeout
Train_Stop: sti               ; Enable interrupts
;--- Check for timeout errors ---
            jcxz  Train_Error ; Exit if not started or  timeout error
            jc    Train_Error ; Exit if training error
;--- Results visualization ---
; Bits EAX.15-00 (AX) contain Link Control Register
; Bits EAX.31-16 contain Link Status Register
            shld  ebx,eax,12  ; Shift bits EAX.25-20 to BL.5-0
            and   bl,00111111b      ; BL=Link Width, bits, mask value
            shr   eax,16            ; Shift bits EAX.19-16 to AL.3-0
            and   al,00001111b      ; AL=Link Speed Code, mask value
            mov   bh,25h            ; 2.5 GT/S
            cmp   al,1
            je    Train_Visual      ; Go if 2.5 GT/S
            mov   bh,50h            ; 5.0 GT/S
            cmp   al,2
            je    Train_Visual      ; Go if 5.0 GT/S
            mov   bh,80h            ; 8.0 GT/S
            cmp   al,3
            je    Train_Visual      ; Go if 8.0 GT/S
            mov   bh,0FFh           ; This code for error
Train_Visual:     movzx ax,bl       ; AX=Width, Binary
            mov   cl,10       ; Convert to Binary Coded Decimal
            div   cl
            shl   al,4
            or    al,ah       ; AL=Width, Binary Coded Decimal
            mov   ah,bh       ; AH=Speed
            out   80h,ax            ; AH(port81)=Speed, AL(port80)=Width
;--- Check for user event ---
            mov   ah,1        ; Function 1
            int   16h         ; Check for key press
            jz    Train_Make  ; Repeat, if no keys pressed
            mov   ah,0        ; Function 0
            int   16h         ; Get scan code
            xor   ax,ax       ; 0000h = Exit with no errors
            jmp   Train_Exit  ; Exit because user press key
;--- Error signaling ---
Train_Error:      mov   ax,0FFFFh   ; FFFFh = Exit with error
Train_Exit: out   80h,ax
;--- Exit to DOS ---
            mov   ax,4C00h
            int   21h
PROGRAM ENDP
CODE_16 ENDS
;--- Stack Segment ---
Stack_Size  EQU  1024
STACK_16  SEGMENT PARA STACK 'STACK' USE16
DB  Stack_Size DUP (?)
STACK_16  ENDS
END START