software-development
November 19

Аморальный патч для Intel DRM

На свете есть не так много вещей, которым под силу меня выбесить до невменяемости. Но кое-что делает это с гарантией: оборзевшая в край машина, возомнившая себя умнее человека.

А значит снова пришло время карать и патчить!

Видите эти повторяющиеся записи справа? Так будет выглядеть буфер сообщений ядра (dmesg), если вам не повезло нарваться на этот баг.

Direct Rendering Manager (DRM)

Развитие современных видеокарт пошло по весьма сюрреалистичному пути:

крупные вендоры страстно хотят чтобы их устройства имели максимально широкую совместимость с открытым ПО и одновременно были закрытыми, неповторяемыми и недоступными для клонирования, плюс защищенными разнообразными патентами.

То что звучит как чистая шизофрения для человека с техническим образованием, будучи спущенным сверху в виде директивы, еще и подкрепленной серьезными бюджетами (с угрозой увольнения в случае провала) — породило на свет такую хтонь как binary blob.

Это когда основная часть управляющей устройством логики реализуется в виде специальной прошивки, с защитой и обфрускацией — того самого «блоба», затем вокруг создается открытая часть, которая линкуется с открытым ядром и окружением.

А все вместе оно задорно и без смущения объявляется как частично беременна открытое, ага.

Хотя это еще не все.

В современном Linux есть такая штука как Direct Rendering Manager:

The Direct Rendering Manager (DRM) is a subsystem of the Linux kernel responsible for interfacing with GPUs of modern video cards

Если кратко и без мата, то это такая специальная дырка в ядре Linux, для максимально прямой коммуникации между видеокартой и клиентским ПО, создаваемая в первую очередь ради игор.

В угаре оптимизации «ядростроители» дошли до использования 3D-ускорения (GPU) даже для отрисовки консоли (тот самый KMS):

И теперь мы имеем «клевый терминал» в разрешении 1920×1280 и со сглаживанием шрифтов, на котором что-то разобрать можно лишь с лупой.

Даже на 14' ноутбуке.

Угар портирования

Под натиском волн малолетних долбо#бов, желающих «гонять игоры» на серверной ОС, разработчики FreeBSD не выдержали:

подсистема DRM и KMS, вместе с проприетарными блобами была перенесена из Linux и теперь используется в системе по-умолчанию.

С тех лет и до сих пор разработка DRM синхронизируется с апстримом (поскольку это отдельный проект) и ядром Linux.

Заодно были фактически похоронены все альтернативные варианты:

старый текстовый TTY и драйвер Intel для Xorg пока еще существуют, но их связку и настройку, а главное — все сопутствующие баги в клиентском ПО вы ныне будете отлавливать и исправлять самостоятельно.

Поскольку интерес сообщества к таким вещам оказался утрачен.

В качестве вишенки на этом торте из навоза, добавлю что всенародно любимый браузер Chrome откровенно хреново работает без загруженного модуля KMS, так что заводить весь этот цирк с DRM и KMS приходится даже на откровенно винтажных машинах — просто ради сраного браузера.

И вариантов фактически нет.

Оборзевшая машина

Вся эта технологическая «многоножка» из Intel с их блобами и апстрима ядра Linux с их любовью к тотальным переделкам на Rust, на практике приводит к тому, что в FreeBSD постоянно попадают ломающие обновления, ни отследить ни исправить которые в моменте не получается.

«Думали что работает» — говорят в таких случаях разработчики FreeBSD и советуют пройти нах#й обновиться до -CURRENT версии.

Что для обычных людей и рабочего окружения на машине равносильно старому японскому ритуалу сеппуку поскольку упадет и сломается вообще все и с концами.

В какой-то момент обновление пакета drm-kmod, содержащего тот самый порт подсистемы DRM из ядра Linux принесло вот такое:

drmn0: [drm] ERROR Fault errors on pipe A: 0x00000080

Ну принесло и принесло, ошибок много разных, исправляются далеко не все и так далее.

Но конкретно эта забивала весь буфер сообщений ядра!

Сообщений генерировалось настолько много, что dmesg — команда для отображения этого самого буфера, показывала только одну эту бесконечно повторяющуюся ошибку.

Ошибка сама по себе известная, страдают как пользователи FreeBSD:

Так и линуксоиды:

Но самое веселое, что баг оказался с рогами и копытами совсем не специфичным и подобное сообщение означает буквально «что-то сломалось».

Ну что, вы все еще любите проприетарные драйвера от уважаемых производителей?

Беглый поиск в репозитории, в котором ведется разработка подсистемы DRM (да, она ведется отдельно от ядра Linux) показал, что сообщений с этой ошибкой откровенно немало:

Положение дел

В итоге получается есть некий баг, с гнездом где-то на уровне прошивки видекарт от Intel. Который (судя по репортам) проявляет себя самым феерическим образом — от спама сообщениями до мигания экрана и полного зависания системы.

Исправить своими силами этот баг нельзя, а все обнаруженные «workaround» в сети по накалу дичи напоминают известное шоу «Битва Экстрасенсов»:

нарисуйте ночью в поле пентаграмму из соли, разложите по углам загрузочные диски FreeBSD с 5й по 10ю и громко читайте файл Changelog задом наперед.

В качестве примера, так выглядит одно из решений:

Но есть и хорошие новости.

Хорошие новости

Которых целых две.

Первая заключается в том, что в свежих прошивках баг вроде бы исправили на стороне Intel, но чтобы эту прошивку поставить — нужна сборка модуля DRM для FreeBSD 15, которая еще не выпущена:

Прямо сейчас идет серьезная работа по перепиливанию DRM как в его основном проекте так и на стороне команды FreeBSD (в -CURRENT), поэтому даже пытаться бекпортировать текущую версию drm-kmod в 14.х ветку не стоит.

Был найден некий бекпорт текущей версии drm-kmod с 15 до 14.1 версии, но во-первых даже он успел устареть практически на год, во-вторых в 14.3 уже не собирается.

Еще (к сожалению) не стоит рассматривать переезд на 15ю версию как гарантированное решение, поскольку есть багрепорты уже и оттуда:

Вторая хорошая новость заключается в том, что на двух моих ноутбуках, где проявляется данный баг, все работает без критических сбоев, а само сообщение до недавних пор глушилось настройкой:

compat.linuxkpi.i915_disable_power_well="0"

Так что конкретно в моем случае, проблема заключается лишь в бесконечном засирании буфера сообщений ядра этой дурацкой и бессмысленной ошибкой:

drmn0: [drm] ERROR Fault errors on pipe A: 0x00000080

Будем глушить, что поделаешь.

Аморальный патч

Разумеется так делать нельзя — глушить сообщения об ошибках в ваших реальных проектах не стоит.

Хотя если в вашем проекте возникает ситуация, когда сообщение об ошибке генерируется по сотне раз в секунду — ну наверное вопрос уже к вам как к разработчику, допустившему такой п#здец.

Но тут и проект не мой и доступа к разработчикам нет и сам процесс разработки DRM сильно напоминает известный фильм «Human Centipede», так что где искать концы не очень понятно.

Для примера, багрепорты по ошибкам DRM в трекера ядра Linux сразу шлют нахер просят перенаправлять в отдельный проект DRM:

Так что было решено применить военную хитрость и просто заглушить сообщение об ошибке в исходниках, пересобрав DRM из портов.

Так выглядит конечный результат после патча:

Как видите буфер ядра не засран этими дурацкими сообщениями.

Поскольку новая 15я по счету версия FreeBSD еще официально не вышла на момент написания статьи, я все еще использую 14.3 — максимально доступная версия DRM для этой ветки это 6.1.

В портах она находится тут:

/usr/ports/graphics/drm-61-kmod

Поиск в исходном коде по тексту сообщения об ошибке показал, что встречается она всего в одном месте, файл i915_irq.c:

drivers/gpu/drm/i915/i915_irq.c

Так выглядит место появления:

..
fault_errors = iir & gen8_de_pipe_fault_mask(dev_priv);

if (fault_errors)
			drm_err(&dev_priv->drm,
				"Fault errors on pipe %c: 0x%08x\n",
				pipe_name(pipe),
				fault_errors);
..				

Все что нужно сделать — закомментировать этот блок, начиная с условия.

И это проклятое сообщение вы больше не увидите, ура.

Для уменьшения геммороя, я подготовил готовый патч, который достаточно положить в специальный каталог и он автоматически применится при сборке.

Создаете файл patch-i915_irq.c в каталоге /usr/ports/graphics/drm-61-kmod/files, вставляете туда вот такое содержимое:

*** drivers/gpu/drm/i915/i915_irq.c.orig	Tue Nov 18 17:17:39 2025
--- drivers/gpu/drm/i915/i915_irq.c	Tue Nov 18 17:17:52 2025
***************
*** 2571,2585 ****
  
  		if (iir & gen8_de_pipe_underrun_mask(dev_priv))
  			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
  
  		fault_errors = iir & gen8_de_pipe_fault_mask(dev_priv);
! 		if (fault_errors)
  			drm_err(&dev_priv->drm,
  				"Fault errors on pipe %c: 0x%08x\n",
  				pipe_name(pipe),
! 				fault_errors);
  	}
  
  	if (HAS_PCH_SPLIT(dev_priv) && !HAS_PCH_NOP(dev_priv) &&
  	    master_ctl & GEN8_DE_PCH_IRQ) {
  		/*
--- 2571,2585 ----
  
  		if (iir & gen8_de_pipe_underrun_mask(dev_priv))
  			intel_cpu_fifo_underrun_irq_handler(dev_priv, pipe);
  
  		fault_errors = iir & gen8_de_pipe_fault_mask(dev_priv);
! 		/*if (fault_errors)
  			drm_err(&dev_priv->drm,
  				"Fault errors on pipe %c: 0x%08x\n",
  				pipe_name(pipe),
! 				fault_errors);*/
  	}
  
  	if (HAS_PCH_SPLIT(dev_priv) && !HAS_PCH_NOP(dev_priv) &&
  	    master_ctl & GEN8_DE_PCH_IRQ) {
  		/*

Дальше перезапускаете сборку:

make clean
make

Проверяем что изменения в файле i915_irq.cприменились и запускаем:

make reinstall

После чего перезагружаем систему.