Linux kernel: определение совместимости драйвера с устройством
Опубликовано 29.01.2008
Иногда бывает необходимо определить, поддерживает ли имеющийся драйвер некое устройство. Например, когда планируется установка новой сетевой карты на работающий сервер или запуск специально собранного ядра на сервере с новейшим RAID-контроллером.
Как обычно, имеется несколько способов решения.
Способ первый: списки совместимости железа (HCL, hardware compatible lists).
Если используется родное ядро дистрибутива, то достаточно зайти на сайт производителя используемого дистрибутива Linux и найти там Hardware Compatibility List. Ещё производители серверного железа пишут, с какими ОС совместимы их устройства и иногда даже выкладывают драйвера с исходниками. Если с производителем оборудования повезло, то можно просто скачать и собрать последнюю версию драйвера.
Можно обратиться к Linux Hardware Compatibility HOWTO, но на данный момент (январь 2008) последняя дата обновления этого документа — 22 мая 2007 года, т.е. по меркам развития технологий очень давно. Ещё я не нашёл там ни одного контроллера Serial ATA, которые в последнее время очень распространены. Тем не менее, если интересующее вас устройство присутствует в этом документе, то оно наверняка поддерживается вашим ядром.
Существует несколько десятков сайтов, имеющих своей целью собрать абсолютно всю информацию о совместимости различного железа с Linux. Как правило, информация на таких сайтах добавляется посетителями и имеет формат «такая-то штука заработала под таким-то ядром в такой-то ОС после таких-то манипуляций с modprobe.conf» и может быть неверной или устаревшей. Примером такого сайта может являться Linux on laptops, содержащий список ссылок на статьи и заметки на тему установки различных дистрибутивов Linux на ноутбуки.
Способ второй: ручная проверка PCI IDs.
Вышеописанный метод гугления может лишь дать представление о том, поддерживается ли данное устройство вообще. Ответ на вопрос «поддерживается ли данный девайс данным ядром» можете дать только вы сами :)
Каждое устройство, подключаемое через шину PCI, имеет 8-байтный код, называемый PCI ID (и еще 8 байт, называемые Vendor ID, но нас они не интересуют). Первые четыре байта означают производителя, оставшиеся — собственно код устройства. Существует единый список известных кодов устройств http://pciids.sourceforge.net, используемый, в частности, командой lspci для отображения читабельного писка установленного оборудования (однако факт включения устройства в этот список вовсе не означает, что оно поддерживается Linux’ом :))
Драйвера Linux «подцепляют» железо по его PCI ID; список совместимых с данным драйвером девайсов «зашит» в структуре pci_device_id, Например, в драйвере sata_nv версии 0.09 из ядра 2.6.15 эта структура выглядит таким образом:
static const struct pci_device_id nv_pci_tbl[] = {
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE2 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA,PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_RAID<<8, 0xffff00, GENERIC },
{ 0, }
};
Поскольку драйвер sata_nv входит в состав ядра, то константы PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA
, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA
и т.д. определены в файле /usr/src/linux/include/linux/pci_ids.h
. Если же драйвер был скачан с сайта производителя, то необходимые константы могут быть переопределены в коде самого драйвера, grep вам в помощь :) Комбинируя значения этих констант со значением PCI_VENDOR_ID_NVIDIA
, определённой в том же pci_ids.h
, можно получить полный PCI ID устройства.
Эту же информацию можно извлечь из уже скомпилированного драйвера с помощью команды modinfo sata_nv
, которая также выдаст список PCI IDs устройств, поддерживаемых данным драйвером. Есть еще файл /lib/modules/`uname -r`/modules.pcimap
, содержащий сводную информацию о том, какие pci ids и vendor ids к какому модулю относятся, но в более подходящем для парсинга формате.Но в случае, если драйвер «вкомпилен» в ядро (например, в конфиге ядра (/usr/src/linux/.config
или /proc/config.gz) указано CONFIG_SCSI_SATA_NV=y
), то из скомпилированного ядра вытащить этот список очень проблематично . Хотя, наверно, как-то можно. Мне кажется, что проще залезть в исходники, надеясь, что в интересующей вас части они не изменились со времени последней компиляции.
Собственно определение совместимости драйвера с устройством состоит из двух этапов:
- выяснение PCI ID данного контроллера. Можно поискать его название, указанное в прилагаемой документации или на чипсете, в файле
/usr/share/hwinfo/pci.ids
(не забывайте его периодически обновлять с сайта http://pciids.sourceforge.net.) или на сайте производителя устройства. Если устройство уже подключено, то поможет командаlspci -nn
- проверка вхождения этого PCI ID в драйвер. Тут можно либо лезть в исходники драйвера, как описано выше, либо воспользоваться командой
modinfo driver_name
.
Однако следует помнить, что возможна ситуация, когда драйвер подцепляет устройство, но работает с ним некорректно. Тут уж ничего не попишешь, нужно искать решение в другом месте.
Бонус для тех, кто дочитал до этого места. Если у вас есть устройство, при загрузке оно почему-то не подцепляется автоматически и вы не знаете, какой драйвер с ним работает, вам поможет сервис Debian GNU/Linux device driver check page (никогда не устану ссылаться на эту страницу!). Он принимает вывод команды lspci -n
и сообщает, какие драйвера подходят для имеющихся устройств. Можно просто указать PCI ID и это сработает.
Спасибо! Добавил в RSS.
Спасибо большое! Очень хорошая статья.
А отдельное спасибо за Debian GNU/Linux device driver check page
[...] предыдущей заметке был рассмотрен способ ручного определения [...]
Спасибо за информацию.