Меню
Linux на Microsoft Surface 2

GPU, память и частоты

От 8 мс на текстуру к 0,7 мс, память на 792 МГц и процессор, который обманывал о своей частоте.

Планшет запускал GNOME, но работал заметно медленнее, чем позволяет его железо. Причины оказались не в одном месте: в драйвере графики, в таблицах памяти и в настройках, которые UEFI оставляет при загрузке.

Текстуры: 80 % времени в memcpy

При перетаскивании окна профилировщик показал, что 80–87 % времени главного потока GNOME Shell уходит на memcpy из некешируемой памяти. Отрисовка одного окна 1045×400 занимала около 8 мс.

Дело в шаге строки. Аппаратный сэмплер GR3D требует для текстур размером не в степень двойки шаг 64 байта, а драйвер выделял их с шагом 32 байта, как для буфера рисования. Текстура не подходила, драйвер делал её упакованную копию, и делал это на каждую отрисовку.

Из описания патча:

The GR3D sampler has an implicit row stride (16 bytes for power-of-two
textures, 64 bytes for NPOT), but textures were allocated with the 32-byte
render-target pitch. Every NPOT texture whose row was not a multiple of 64
bytes (window textures, icons, glyph atlases, ...) therefore got a "packed"
shadow BO and was re-copied row by row, reading from uncached GEM memory,
on EVERY draw that sampled it.

Исправление простое: сразу выделять такие текстуры с шагом сэмплера, чтобы они читались на месте. Для импортированных буферов копия теперь обновляется только после записи в текстуру.

ПоказательДоПосле
Отрисовка окна 1045×4007,9 мс0,6–0,7 мс
Перетаскивание окна38–51 fps59 fps
Главный поток Shell66–92 %33–37 %
Открытие обзора0,65–1,1 с0,37–0,57 с

Рядом исправлены «призраки» на экране: аппаратура принимает не больше 4096 индексов за отрисовку, поэтому большие отрисовки теперь разбиваются на части.

Память: родные таблицы лежали в ACPI

Контроллер памяти EMC работал на 408 МГц при паспортных 792 МГц. Переключить частоту нельзя без таблицы таймингов, а она уникальна для каждой платы и типа памяти.

Таблица нашлась в самом планшете: \_SB.PEPD.DVF6 в SSDT-6, структура tegra11_emc_table ревизии 0x42, 10 частот. Запись на 408 МГц совпала с реальными регистрами, значит таблица настоящая.

Алгоритм переключения мы взяли из tegra11_emc.c в ядре NVIDIA. Модуль surface-emc никогда не меняет напряжение: он только проверяет, что VDD_CORE достаточно.

/*
 * Supported targets: 204000 (PLLP/2), 408000, 600000 (PLLC, reserved
 * exclusively), 792000 (PLLM reprogrammed to 792 MHz while EMC runs on PLLP).
 * VDD_CORE (Palmas SMPS457) must already be >= table min_mV; the module
 * never changes voltages.
 */
Тест408 МГц792 МГцПрирост
Задержка, нс294207−30 %
Запись, 4 потока, МБ/с49858192+64 %
memcpy, МБ/с17172434+42 %
Чтение, МБ/с16121988+23 %

Проверка: memtest на 792 МГц и 1680 переключений между частотами, 670 из них под нагрузкой, без единой ошибки.

Процессор: система врала о своей частоте

Сделав новое ядро, мы увидели странный результат: на части загрузок оно работало на 23 % медленнее. Конфигурация и компилятор были ни при чём. Счётчик тактов показал реальные 990 МГц при заявленных 1320.

UEFI передаёт управление с SUPER_CCLKG_DIVIDER = 0x40000203. Это аппаратный пропуск тактов с коэффициентом 3/4 и бит, отдающий управление блоку термозащиты. Драйвера этого блока для T114 нет, ядро отключает его как неиспользуемый, и троттлинг застывает навсегда.

/*
 * Firmware may leave SUPER_CDIV_USE_THERM_CONTROLS set, handing the
 * CPU-G clock skipper to SOC_THERM. There is no Tegra114 soctherm
 * driver and soc_therm gets gated as an unused clock, so a throttle
 * active at that moment stays frozen (e.g. 0x40000203: cclk_g at 3/4
 * while cpufreq reports the full rate). Like NVIDIA's downstream
 * tegra11_super_clk_init(), start with the skipper cleared.
 */
{
    u32 cdiv = readl(clk_base + SUPER_CCLKG_DIVIDER);

    if (cdiv)
        pr_info("tegra114: clearing SUPER_CCLKG_DIVIDER 0x%08x\n",
            cdiv);
    writel(0, clk_base + SUPER_CCLKG_DIVIDER);
}

Управление частотой и температурой

Модуль surface-cpufreq меняет частоту от 204 до 1320 МГц вместе с напряжением VDD_CPU:

Частота, МГцНапряжение, мВ
до 408900
612940
816990
10201030
12241090
13261120

Защита: с 85 °C частота снижается шагами, с 95 °C сразу падает до 612 МГц, а при 100 °C система штатно выключается. Под стрессом на 4 ядрах максимум составил около 80 °C.

Частота GPU поднята с 300 до 492 МГц без изменения напряжения, что сократило отрисовку смешанного слоя 1080p с 11,2 до 8,3 мс.

Видео

Аппаратный декодер H.264 работает на отдельном процессоре AVP и доступен как обычное устройство /dev/video60. Контрольные суммы всех кадров совпали с программным декодированием, а 1080p30 занимает около 61 % одного ядра. FFmpeg, GStreamer, mpv и VLC используют его через V4L2.

Чего не удалось добиться

Кодировщик MSENC запускается, но отклоняет каждый кадр с ошибкой e2640010, даже с оригинальной прошивкой и повторением команд. Это заняло больше всего экспериментов и осталось нерешённым. А GTK 4 на GPU невозможен в принципе: ему нужен GLES3, у GR3D только GLES2.