Всем привет!
Меня зовут Алфёров Валентин, я директор по развитию компании Е-Флопс. В этой статье хочу поделиться с вами интересным рассказом и полезным патчем нашего инженера-программиста, который рассказал мне эту историю. Всё, что написано дальше, рассказ Никита Еремеева от первого лица.
Проблема
При подготовке наших модульных серверов М1 с вычислительными модулями на отечественных процессорах ARM64 команда столкнулась с дефектом вывода видео. Изображение выводилось с артефактами, получали эффект «снега». Картинка была одинаково испорчена и на мониторе, подключённом напрямую к серверу, и в Web-KVM сервисного процессора BMC.
Рассказываем почему, как и что получилось.
Что диагностировали
Отдельные пиксели неверного цвета: на светлом фоне – тёмные, на тёмном – светлые. Они выстраивались в вертикальные цепочки. Геометрия, синхронизация и расположение текста при этом оставались правильными, то есть видеотракт работал, портилось содержимое кадра. Ошибок в журналах и счётчиках не было, и это надолго завело диагностику в тупик. Искать было нечего, явных дефектов исходники не показывали.
Откуда берётся картинка
У этого процессора нет собственного видеовыхода (что логично, ведь это серверный ЦП). Изображение даёт сервисный процессор, в нашем случае Контроллер BMC на Aspeed AST2600, подключённый по PCIe. Хост пишет кадр через PCIe в видеопамять AST2600, а та физически находится в оперативной памяти самого Контроллера BMC. Читают эту память два независимых потребителя: развёртка видеовыхода и движок захвата для KVM.
Это наблюдение стало первой зацепкой. Артефакт был одинаковый на обоих выходах, значит дело не в одном конкретном тракте вывода. Испорчено само содержимое памяти – ещё до того, как его прочитал потребитель. Искать надо было не в выводе, а в записи.
Почему версия виновности Контроллера BMC не подтвердилась?
Поскольку память принадлежит Контроллеру BMC, первой версией была та, в которой со стороны BMC её кто-то затирает. Эту линию мы прошли до конца: разобрали резервирование видеопамяти в U-Boot, настройку памяти в дереве устройств, драйверы видеодвижка и захвата, мост PCIe. Опорной точкой служила вторая наша платформа на том же Контроллере BMC, но с центральным процессором arm64 другого производителя, где вывод работает чисто.
Расхождений, которые могли бы объяснить дефект, там не нашлось. Программная часть BMC в обоих случаях ведёт себя одинаково. Отсюда вывод, что дело не в вычислительных модулях (серверах) и не в прошивке сервисного процессора (AST2600). Железо работает так, как предусмотрено документацией.
В итоге наши ожидания от реализации драйвера на хосте не совпали с тем, что нам описывала его документация.
Что оказалось на самом деле
Драйвер ast в ядре Linux (drivers/gpu/drm/ast/) отображает видеопамять как write-combining через devm_ioremap_wc (файл drivers/gpu/drm/ast/ast_mm.c, строка 90). На x86 это обычная и выгодная практика – процессору разрешено объединять, переупорядочивать и дробить записи, чтобы отдавать их шине крупными пачками. На процессорах с архитектурой arm64 такое отображение означает память типа Normal non-cacheable с теми же правами на слияние.
Перерисовка экрана идёт построчно. Функция drm_fb_memcpy (drivers/gpu/drm/drm_format_helper.c, строки 291-295) копирует прямоугольник обновления частями – кусок шириной в прямоугольник, затем прыжок на шаг строки. Между частями остаются пропуски. Буфер слияния вправе собрать два соседних куска в одну пачку AXI, и тогда пропуск между ними окажется дырой посреди этой пачки. И ее исходящий мост AXI-PCIe у отечественного процессора arm64 не поддерживает.
А что документация?
В программной документации на этот процессор для исходящих пачек записи перечислены допустимые комбинации байтовых стробов. Первый такт пачки с ненулевым стробом может иметь одну из комбинаций 1000 / 1100 / 1110 / 1111, последний – одну из 0001 / 0011 / 0111 / 1111. А про все промежуточные такты сказано прямо – в них должны быть выставлены все стробы.
Таким образом, выставленные байты внутри пачки обязаны образовывать один сплошной участок. Пачка с дырой посередине недопустима. В документации также описано, насколько ограниченно сам PCIe работает с записями с несплошным байтовым разрешением – только длиной в одно-два слова с отдельным предупреждением для исходящего направления.
Именно такую недопустимую пачку и порождает связка из отображения write-combining и построчного копирования с пропусками.
Почему ошибку не было видно
В той же документации сказано, что механизм расширенного отчёта об ошибках PCIe (AER) в мосте не поддерживается. AER работает только для самого контроллера PCIe, а ошибки, обнаруженные мостом, в него не попадают. Мост обрабатывает нарушение неправильно и молча.
Ни AER, ни счётчики ошибок линка не двигались, потому что для них ничего не произошло. Единственным видимым следом был испорченный пиксель на экране. Этим и объясняется, почему диагностика заняла продолжительное время.
Что сделали
Патч меняет в ast_mm.c отображение видеопамяти с devm_ioremap_wc на devm_ioremap, то есть на тип Device. Для Device-памяти слияние записей запрещено архитектурно, записи уходят в мост такими, какими их сформировал драйвер, без дыр. Попутно убираются два вызова резервирования диапазона write-combining, которые вне x86 всё равно ничего не делают.
Собрали, проверили на плате, артефакты исчезли. Это одна строка, и она закрывает дефект целиком. Платой за него, служат некэшируемые записи вместо объединённых, и мы пока не измеряли задержки видео. У отображения Device есть задержка при полноэкранной перерисовке, и постоянным решением может оказаться другой вариант – сохранить слияние, но писать в видеопамять целыми строками без пропусков. Это быстрее, но требует правки пути перерисовки, а не одной строки.
Чем мы хотим поделиться
Что вышеизложенное значит для вендоров отечественных операционных систем? Ограничение касается не только видео. Любой драйвер, который отображает память устройства за мостом отечественного процессора arm64 как write-combining и пишет в неё фрагментами, становится слабым звеном. Ошибка при этом не будет видна в AER, только по последствиям. Для платформ на этом процессоре разумно считать правилом тот факт, что память устройства за исходящим мостом либо не отображается write-combining, либо в неё пишут без пропусков.
Если вы работаете в вашей инфраструктуре с сервером на отечественном процессоре arm64 совместно с AST2600 и видите похожую картину, проверьте в первую очередь, что используете сборку ОС с корректным отображением framebuffer.
Чтобы вы понимали о каком дефекте изображения идет речь, демонстрируем два изображения, до и после устранения дефекта.

Наш патч можно взять и проверить в своём окружении в ОС вашей сборки. Мы будем рады замечаниям и отзывам в комментариях и при прямом обращении. Все вендоры ОС (а у AstraLinux работает это уже из коробки), запускающихся на отечественном процессоре ARM64, могут применять у себя обновлённый драйвер для улучшения пользовательского опыта при эксплуатации своих продуктов на серверах с данным ЦП.
С наилучшими пожеланиями, инженер-программист ООО «Е-Флопс» Никита Еремеев!
ссылка на оригинал статьи https://habr.com/ru/articles/1104566/