Планшет запускал 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×400 | 7,9 мс | 0,6–0,7 мс |
| Перетаскивание окна | 38–51 fps | 59 fps |
| Главный поток Shell | 66–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 МГц | Прирост |
|---|---|---|---|
| Задержка, нс | 294 | 207 | −30 % |
| Запись, 4 потока, МБ/с | 4985 | 8192 | +64 % |
| memcpy, МБ/с | 1717 | 2434 | +42 % |
| Чтение, МБ/с | 1612 | 1988 | +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:
| Частота, МГц | Напряжение, мВ |
|---|---|
| до 408 | 900 |
| 612 | 940 |
| 816 | 990 |
| 1020 | 1030 |
| 1224 | 1090 |
| 1326 | 1120 |
Защита: с 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.