Пробрасывание видеокарты в виртуальную машину¶
Введение¶
GPU passthrough позволяет напрямую передавать видеокарту внутрь виртуальной машины. Это может понадобиться по разным причинам - например, для запуска нейросетей или реализации рабочего места.
В дальнейшей заметке я опишу свой опыт проброса видеокарты Nvidia GTX 1660 Super. По хорошему, данная заметка должна работать и на других видеокартах
Настройки на гипервизоре¶
Настройка BIOS¶
- Включаем поддержку виртуализации, если еще не сделали это - VT-x для Intel и SVM для AMD. Да и если не сделали - как у вас Proxmox вообще нормально работает?
- Отключаем CSM (Compatibility Support Module) - без него остальные вещи (IOMMU и прочее), как правило, не получится включить.
- Включаем VT-d (если Intel) или AMD-Vi/IOMMU (если AMD) - это аппаратные технологии ввода-вывода, которые предназначены для виртуализации устройств. Как раз именно эта опция позволит напрямую использовать нашу видеокарту в виртуалке. Скажу сразу, эти опции могут быть запрятаны глубоко - например в моем BIOS они были аж в "Advanced > AMD CBS > NBIO Common Options > IOMMU".
- Включаем Above 4G Decoding - позволяет устройствам использовать адреса памяти выше 4х ГБ. Без этой опции в логах ядра мы сможем увидеть
vfio-pci: BAR 0 region memory size exceeds supported 32-bit limit
. - Если в процессоре есть встроенное видеоядро - ищем опцию "Init Display Output" - это нужно для того, чтобы минимизировать шанс ядра на захват видеокарты буфером вывода.
Получение vendor id и device id¶
Запускаемся, заходим на хост, теперь нам нужно получить vendor id и device id которые будут использоваться в дальнейшем.
Для того, чтобы узнать эти ID, нам нужно найти все устройства NVIDIA, для этого выполняем:
Получим такой вывод:
07:00.0 VGA compatible controller [0300]: NVIDIA Corporation TU116 [GeForce GTX 1660 SUPER] [10de:21c4] (rev a1)
07:00.1 Audio device [0403]: NVIDIA Corporation TU116 High Definition Audio Controller [10de:1aeb] (rev a1)
где 10de:21c4
и 10de:1aeb
- это и есть наши пары vendorId:deviceId. Запоминаем их, они понадобятся нам много где позже.
Настройка запуска ядра¶
Заходим в /etc/default/grub
и редактируем строку:
GRUB_CMDLINE_LINUX_DEFAULT="quiet amd_iommu=on iommu=pt pci=realloc vfio-pci.ids=10de:21c4,10de:1aeb"
Разберемся с опциями:
amd_iommu=on
- включает поддержку IOMMU для AMD. Если intel - вставляемintel_iommu=on
iommu=pt
- включает тегирование iommu только для тех устройств, которые настроены на проброс. Сильно ускоряет производительность.pci=realloc
перераспределение BAR-овvfio-pci.ids=10de:21c4,10de:1aeb
- вместо10de:21c4,10de:1aeb
нужно вставить vendorId:deviceId устройств, которые мы получили в предыдущем шаге. Опция не всегда обязательна, но некоторые видеокарты без неё не захватываются при помощи vfio.
Сохраняем файл, прописываем update-grub
, перезагружаемся.
Проверка IOMMU¶
Заходим в систему после перезагрузки и проверяем следующим скриптом, появились ли IOMMU-группы:
for g in $(find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V); do
echo "IOMMU Group ${g##*/}:"
for d in $g/devices/*; do
echo -e "\t$(lspci -nns ${d##*/})"
done;
done;
Если есть вывод с группами - всё окей, можно продолжать. Если нет - значит IOMMU не включен.
Отключение драйверов видеокарты¶
Перед включением vfio, нам нужно выключить драйвера нашей видеокарты, чтобы они не мешали захвату vfio. Для этого добавьте в /etc/modprobe.d/blacklist.conf
следующие строки:
- Для карт NVIDIA
Настройка vfio¶
Добавляем модули vfio¶
Добавляем следующие модули в /etc/modules
:
Если ядро меньше 6.2, нужно добавить vfio_virqfd
. В 6.2 и старше он включен по умолчанию.
Настраиваем vfio¶
В файле /etc/modprobe.d/vfio.conf
нужно добавить следующую строку:
Очевидно, что вместо 10de:1b81,10de:10f0
мы вставляем наши пары vendorId:deviceId которые получили ранее.
Обновляем initramfs¶
На этом настройка на гипервизоре закончена. Нам остается обновить initramfs и перезагрузиться:
Проверка корректности захвата vfio нашей видеокарты:¶
В dmesg | grep vfio
должны получить примерный вывод:
[ 40.004872] vfio-pci 0000:07:00.0: vgaarb: deactivate vga console
[ 40.004876] vfio-pci 0000:07:00.0: vgaarb: VGA decodes changed: olddecodes=io+mem,decodes=io+mem:owns=none
[ 40.004992] vfio_pci: add [10de:21c4[ffffffff:ffffffff]] class 0x000000/00000000
[ 40.054256] vfio_pci: add [10de:1aeb[ffffffff:ffffffff]] class 0x000000/00000000
[ 235.344905] vfio-pci 0000:07:00.1: enabling device (0000 -> 0002)
Если получили - значит всё ок, vfio захватил видеокарту.
Вводим lspci -nnk -d 10de:21c4
и если видим - Kernel driver in use: vfio-pci
- всё ок.
Дальнейшая настройка¶
Дальше в Proxmox через GUI в Hardware -> PCI Device -> Raw Device добавляем наше устройство. На самой виртуалке ставим драйвер видеокарты - ну а как иначе?
Решение проблем¶
probe of 0000:07:00.0 failed with error -22¶
Если видим ошибку в dmesg по типу:
[ 46.901149] vfio-pci 0000:07:00.0: vgaarb: deactivate vga console
[ 46.901154] vfio-pci 0000:07:00.0: vgaarb: VGA decodes changed: olddecodes=io+mem,decodes=io+mem:owns=io+mem
[ 46.901171] vfio-pci: probe of 0000:07:00.0 failed with error -22
[ 46.901177] vfio_pci: add [10de:21c4[ffffffff:ffffffff]] class 0x000000/00000000
[ 46.901193] vfio-pci 0000:07:00.0: vgaarb: deactivate vga console
[ 46.901195] vfio-pci 0000:07:00.0: vgaarb: VGA decodes changed: olddecodes=io+mem,decodes=io+mem:owns=io+mem
[ 46.901201] vfio-pci: probe of 0000:07:00.0 failed with error -22
[ 46.901253] vfio-pci: probe of 0000:07:00.1 failed with error -22
[ 46.901257] vfio_pci: add [10de:1aeb[ffffffff:ffffffff]] class 0x000000/00000000
Значит vfio не смогу получить доступ к BAR-у карты.
Отключение фреимбуффера¶
Заранее скажу, что это очень редкая ситуация, но отключение фреимбуффера и драйверов дает эксклюзивный доступ vfio к видеокарте.
В файле /etc/default/grub
в GRUB_CMDLINE_LINUX_DEFAULT
добавляем следующие опции:
video=efifb:off
иnomodeset
отключаем фреимбуффер.initcall_blacklist=simplefb_init
- ещё один способ выключить фреимбуффер.
Еще помогает отключить модули для fb, для этого создаем файл /etc/modprobe.d/blacklist-fb.conf
и добавляем:
Обновляем initramfs и перезагружаемся:
Внимание! При отключении фреимбуффера, мы не сможем видеть при подключии HDMI-кабеля видеть изображение!
vfio-pci не смог захватить устройство¶
Получаем наше устройство: lspci -nnk -d 10de:21c4
Получим вывод в виде такого:
07:00.0 VGA compatible controller [0300]: NVIDIA Corporation TU116 [GeForce GTX 1660 SUPER] [10de:21c4] (rev a1)
Subsystem: Gigabyte Technology Co., Ltd TU116 [GeForce GTX 1660 SUPER] [1458:4014]
Kernel driver in use: vfio-pci
Kernel modules: nvidiafb, nouveau
Если в Kernel driver in use
у вас что-то другое кроме vfio-pci
- vfio не смог захватить видеокарту и его захватил другой драйвер. Для решения, вернитесь на пункт с отключением драйверов видеокарты.
Если вместо сервера используется ноутбук¶
Есть смысл в GRUB опцию pcie_aspm=off
- этот параметр управляет потреблением шин PCI-E. Если он включен, ответ устройства увеличивается из-за времени, которое затрачивается на переключение режимов шины.
Можно ли использовать 1 видеокарту сразу на нескольких устройствах?¶
Нет, это вам нужно смотреть в сторону vGPU. Но никто не мешает создать несколько ВМ и включать их по мере необходимости.
Ссылки¶
- Есть похожая статья на Habr.
- PCI Passthrough в вики проксмокса.
- Хороший gist с некоторыми дополнительными пояснениями.