• Por qué es mejor separar audio y video en PCIPassThrough

    Cuando realizamos PCI Passthrough de una tarjeta gráfica hacia una máquina virtual, es habitual asignar todas las funciones PCI de la tarjeta de forma conjunta. En Proxmox VE podemos hacerlo seleccionando la opción «All Functions», de manera que tanto la GPU como su controlador de audio HDMI/DisplayPort se presentan a la máquina virtual como un dispositivo PCI multifunción.

    Aunque esta configuración suele funcionar correctamente, puede provocar problemas poco evidentes cuando queremos utilizar determinadas capacidades de la GPU, especialmente las relacionadas con la computación mediante AMD KFD (Kernel Fusion Driver).

    Nos encontramos precisamente con este problema al realizar PCI Passthrough de una Sapphire Radeon RX 580, basada en la arquitectura AMD Polaris, hacia una máquina virtual Linux ejecutada sobre Proxmox VE. La tarjeta gráfica funcionaba correctamente y el sistema operativo invitado podía utilizarla para generar vídeo. Sin embargo, al ejecutar la herramienta de monitorización amd-smi, esta no mostraba ninguna GPU disponible.

    El problema no estaba en el funcionamiento gráfico de la tarjeta, sino en cómo QEMU exponía determinadas capacidades PCIe al sistema operativo invitado. Lo resolvimos modificando la configuración del passthrough para asignar la función gráfica y la función de audio mediante dos dispositivos PCI independientes dentro de la máquina virtual.

    Por qué una tarjeta gráfica aparece como dos dispositivos PCI

    Las tarjetas gráficas modernas suelen integrar varias funciones PCI en un mismo dispositivo físico. En el caso de nuestra RX 580, encontramos una función dedicada al procesamiento gráfico y otra destinada a proporcionar audio digital a través de HDMI o DisplayPort.

    Podemos identificar estas funciones desde el anfitrión Proxmox ejecutando:

    lspci -nn | grep -Ei 'VGA|Display|Audio'

    Por ejemplo, si nuestra tarjeta está conectada a la dirección PCI 03:00, sus funciones pueden aparecer de la siguiente manera:

    03:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Ellesmere [Radeon RX 580]
    03:00.1 Audio device: Advanced Micro Devices, Inc. [AMD/ATI] Ellesmere HDMI Audio

    El sufijo .0 identifica la función gráfica, mientras que el .1 corresponde al controlador de audio. Ambas funciones forman parte de la misma tarjeta física, pero PCI permite identificarlas y gestionarlas por separado.

    En Proxmox, cuando seleccionamos «All Functions» o utilizamos una dirección PCI sin indicar el número de función, estamos solicitando que se transfieran todas las funciones de ese dispositivo. Por ejemplo, suponiendo que nuestra tarjeta se encuentre en 03:00, podemos encontrar una configuración similar a esta en el archivo de configuración de la máquina virtual:

    hostpci0: 0000:03:00,pcie=1

    Esta configuración hace que QEMU agrupe las funciones de vídeo y audio en un mismo dispositivo PCI multifunción dentro de la máquina virtual.

    La alternativa consiste en asignarlas mediante dos entradas diferentes:

    hostpci0: 0000:03:00.0,pcie=1
    hostpci1: 0000:03:00.1,pcie=1

    Con esta segunda configuración, ambas funciones siguen perteneciendo a la misma tarjeta física y continúan asignadas a la misma máquina virtual, pero QEMU puede conectarlas a puertos PCIe virtuales independientes. Esta diferencia resulta fundamental para comprender el problema que experimentamos.

    El problema está relacionado con las operaciones atómicas PCIe

    PCI Express incorpora una característica denominada Atomic Operations (AtomicOps), que permite realizar determinadas operaciones de lectura, modificación y escritura sobre memoria de forma indivisible. Esto garantiza que una operación atómica se complete sin interferencias de otras operaciones concurrentes sobre la misma ubicación.

    Estas operaciones son importantes para ciertos mecanismos de sincronización entre procesadores y dispositivos PCIe. En particular, algunas GPU AMD las necesitan para inicializar correctamente sus capacidades de computación a través de KFD.

    Las operaciones atómicas PCIe requieren soporte a lo largo de la ruta PCIe correspondiente. No basta con que la propia GPU las admita: los puertos y puentes que intervienen también deben anunciar y permitir las capacidades necesarias.

    Aquí es donde interviene una particularidad de QEMU. En su código fuente encontramos la función vfio_pci_enable_rp_atomics(), implementada en el archivo hw/vfio/pci.c.

    Esta función permite que QEMU anuncie automáticamente el soporte de AtomicOps en un puerto raíz PCIe virtual, utilizando las capacidades comunicadas por VFIO. Sin embargo, esta habilitación automática solo se realiza cuando el dispositivo asignado es de una única función, está conectado a un puerto raíz PCIe compatible y se cumplen las demás condiciones de la implementación.

    La restricción está expresamente documentada en el código de QEMU. Su objetivo es evitar conflictos cuando un mismo slot virtual contiene varias funciones o dispositivos que pueden tener capacidades PCIe diferentes.

    En consecuencia, si agrupamos nuestra GPU y su función de audio como un dispositivo multifunción, QEMU puede dejar de anunciar el soporte para completar operaciones atómicas de 32 y 64 bits en el puerto PCIe virtual correspondiente, incluso cuando el hardware físico sí permite utilizarlas.

    Por el contrario, si asignamos la función gráfica de forma independiente, QEMU puede habilitar estas capacidades en su propio puerto PCIe virtual, siempre que VFIO y la topología PCIe física confirmen que son compatibles.

    Este comportamiento explica por qué una GPU puede funcionar perfectamente para mostrar imágenes y, al mismo tiempo, presentar problemas al inicializar sus capacidades de computación.

    Por qué KFD rechaza la GPU y amd-smi no la detecta

    En Linux, el controlador amdgpu proporciona las funciones necesarias para gestionar la GPU, mientras que AMDKFD incorpora la infraestructura del kernel destinada a determinadas cargas de computación heterogénea.

    Son componentes relacionados, pero que una tarjeta funcione con el controlador gráfico no garantiza que también pueda inicializarse correctamente en KFD.

    Durante la inicialización, el controlador AMD comprueba si puede habilitar operaciones atómicas PCIe de 32 y 64 bits hasta el complejo raíz mediante la función pci_enable_atomic_ops_to_root().

    Si esta comprobación falla, el controlador puede registrar el siguiente mensaje:

    PCIE atomic ops is not supported

    Posteriormente, KFD verifica si la GPU necesita estas operaciones. En el caso de Polaris, esta capacidad es necesaria para su inicialización en KFD. Si no está disponible, podemos encontrar mensajes similares al siguiente, dependiendo de la versión del kernel:

    kfd kfd: amdgpu: skipped device ..., PCI rejects atomics ...

    El resultado es que la GPU puede seguir funcionando mediante amdgpu para tareas gráficas, pero no llega a registrarse correctamente como dispositivo de computación en KFD.

    Esta situación resulta especialmente desconcertante porque herramientas como lspci muestran la tarjeta y el sistema operativo puede utilizarla para proporcionar una salida de vídeo, mientras que herramientas de monitorización o computación como amd-smi pueden no mostrarla correctamente. Esto último fue precisamente lo que ocurrió con nuestra Sapphire RX 580.

    Podemos consultar la lógica responsable de este comportamiento en el código del kernel Linux, concretamente en amdgpu_device.c y kfd_device.c.

    Qué cambió al separar las funciones de vídeo y audio

    En nuestro caso, no tuvimos que sustituir la tarjeta gráfica ni modificar físicamente el hardware. La solución consistió únicamente en cambiar cómo estaban asignadas las funciones PCI dentro de Proxmox.

    Al dejar de agrupar ambas funciones, el sistema operativo invitado pasó de verlas en un mismo dispositivo multifunción a identificarlas como dos dispositivos PCI independientes.

    Característica Antes Después
    Función gráfica 01:00.0 01:00.0
    Función de audio HDMI 01:00.1 02:00.0
    Topología PCIe virtual Dispositivo multifunción con puerto compartido Puertos independientes
    AtomicOps de 32 y 64 bits No anunciadas en el puerto virtual Anunciadas y disponibles
    Registro de la GPU en KFD Rechazado Correcto
    Detección mediante amd-smi Sin GPU detectada GPU detectada

    La diferencia más importante no fue el cambio de dirección PCI del dispositivo de audio, sino que la función gráfica dejó de formar parte de un dispositivo multifunción dentro de la máquina virtual.

    Gracias a ello, QEMU pudo anunciar las capacidades AtomicOps correspondientes en el puerto PCIe virtual de la GPU. El controlador amdgpu pudo habilitarlas y KFD dejó de rechazar la tarjeta, permitiendo que amd-smi volviera a detectarla.

    Cómo realizar la separación en Proxmox VE

    Si queremos utilizar esta configuración, primero debemos identificar las direcciones PCI reales de la GPU y de su controlador de audio desde el anfitrión Proxmox.

    lspci -nn

    Después, con la máquina virtual apagada, accedemos a su sección Hardware y eliminamos la asignación PCI que agrupa todas las funciones de la tarjeta.

    Añadimos nuevamente la GPU mediante «Add → PCI Device», seleccionando exclusivamente su función gráfica, sin marcar «All Functions». Repetimos el procedimiento para añadir la función de audio como un segundo dispositivo PCI.

    Para este escenario debemos utilizar una máquina virtual de tipo q35 y habilitar la opción PCI-Express en ambas asignaciones, de manera que QEMU pueda conectarlas a puertos PCIe virtuales. Proxmox también recomienda OVMF para mejorar la compatibilidad del passthrough gráfico cuando la GPU dispone de una ROM UEFI compatible.

    Podemos comprobar el resultado consultando la configuración de la máquina virtual desde el anfitrión:

    qm config IDDeLaMaquinaVirtual

    La parte relevante de la configuración debería ser equivalente al siguiente ejemplo, sustituyendo las direcciones PCI por las correspondientes a nuestra tarjeta:

    machine: q35
    hostpci0: 0000:03:00.0,pcie=1
    hostpci1: 0000:03:00.1,pcie=1

    Si ya tenemos configurado correctamente el passthrough, no necesitamos modificar los parámetros IOMMU del anfitrión ni reinstalar los controladores de la máquina virtual. Estamos cambiando la topología PCIe virtual, no la configuración física de la tarjeta.

    Cómo verificar que las AtomicOps están disponibles

    Una vez iniciada la máquina virtual, podemos comprobar cómo se presentan los dispositivos PCI ejecutando:

    lspci -nn

    También podemos consultar la topología PCIe virtual para identificar el puerto raíz al que está conectada nuestra GPU:

    lspci -t

    Para comprobar las capacidades PCIe anunciadas por los diferentes dispositivos y puertos, ejecutamos:

    lspci -vv

    En la sección correspondiente al puerto raíz PCIe virtual que conecta nuestra GPU, debemos prestar atención al campo AtomicOpsCap. Cuando QEMU no anuncia compatibilidad con operaciones atómicas de 32 y 64 bits, podemos encontrar:

    AtomicOpsCap: 32bit- 64bit-

    Cuando la configuración permite anunciar ambas capacidades, los valores aparecen activados:

    AtomicOpsCap: 32bit+ 64bit+

    Debemos tener en cuenta que estos valores corresponden al puerto PCIe que estamos examinando. Es importante comprobar el puerto conectado a la GPU y no interpretar las capacidades de cualquier otro dispositivo como si fueran las de nuestra tarjeta.

    También podemos revisar los mensajes del kernel relacionados con AMDGPU, KFD y las operaciones atómicas:

    dmesg | grep -Ei 'amdgpu|kfd|atomic'

    En una inicialización correcta deberíamos comprobar que KFD registra la GPU, sin rechazarla por falta de soporte para operaciones atómicas. Finalmente, podemos verificar si amd-smi vuelve a enumerar el dispositivo:

    amd-smi list

    La detección mediante amd-smi también depende de su versión, de los controladores instalados y de la compatibilidad de la GPU. Por tanto, la disponibilidad de AtomicOps es una comprobación importante, pero no garantiza por sí sola el funcionamiento de todas las herramientas AMD.

    Separar las funciones PCI no modifica los grupos IOMMU

    Hay un detalle importante que debemos aclarar: separar las funciones de vídeo y audio dentro de Proxmox no significa separar físicamente los dispositivos ni modificar sus grupos IOMMU.

    Los grupos IOMMU dependen de la topología PCIe física y de las capacidades de aislamiento de nuestra plataforma. Si las funciones gráfica y de audio pertenecen al mismo grupo IOMMU, seguirán perteneciendo a ese grupo después de modificar la configuración de la máquina virtual.

    VFIO utiliza estos grupos como unidades de aislamiento. Por eso, cuando ambas funciones comparten un grupo, debemos respetar sus requisitos de propiedad y asignación. No debemos interpretar la separación en dos entradas hostpci como una autorización para repartir las funciones de un mismo grupo entre máquinas virtuales diferentes.

    En nuestro caso, ambas funciones continuaron asignadas a la misma máquina virtual. Lo único que modificamos fue cómo QEMU las presentaba en su topología PCIe virtual.

    Tampoco debemos considerar esta separación como una mejora universal de rendimiento o compatibilidad. Su ventaja concreta aparece cuando necesitamos capacidades PCIe que QEMU no anuncia automáticamente en determinadas configuraciones multifunción. Si la GPU se utiliza exclusivamente para mostrar vídeo, es posible que nunca lleguemos a experimentar este problema.

    Este comportamiento tampoco es exclusivo de nuestra RX 580. De hecho, en agosto de 2026 se propuso documentar esta limitación en Proxmox VE después de reproducir un problema de AtomicOps con dos tarjetas Radeon RX 7900 XT asignadas a una misma máquina virtual. En ese caso, la ausencia de operaciones atómicas provocaba fallos en operaciones colectivas de RCCL, que desaparecían al asignar explícitamente las funciones gráficas.

    Esto demuestra que la forma en la que organizamos las funciones PCI de una GPU dentro de QEMU puede afectar a las capacidades que detectan los controladores del sistema operativo invitado, incluso aunque estemos utilizando exactamente la misma tarjeta física, el mismo controlador y la misma máquina virtual.

    Deja una respuesta