[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v4 2/2] libxl: add OpRegion and VBT to firmware when assigning IGD



To provide support for newer IGD devices with an extended video bios table
(VBT), the device model needs to access the host OpRegion and VBT when the
IGD is bound to the xen-pciback driver but the Linux kernel only exposes
them in the debugfs when the IGD is bound to the i915 driver. Although the
OpRegion and VBT can be manually copied to a firmware directory from the
debugfs to a directory where the device model can access them when the IGD
is bound to the xen-pciback driver, libxl can do this automatically by
copying the OpRegion and VBT from the Linux debugfs to the Xen firmware
directory before unbinding the IGD from the i915 driver. Since the copying
of the OpRegion and VBT are not required for the device to be made assignable,
don't return an error if the only error is that the attempt to copy the
OpRegion and/or the VBT to the Xen firmware directory failed.

It is necessary to read the RVDS field of the OpRegion which stores the
size of the extended VBT. We cannot rely on stat(2) for this which returns
a value of 0 for the size of files stored in the Linux debugfs. This patch
relies on lstat(2) only to determine if the OpRegion and VBT files already
exist in the Xen firmware directory. If the value stored in the RVDS field
is 0, then there is no extended VBT and the VBT is embedded within mailbox
# 4 of the OpRegion, in which case we can assume the size of the VBT is 6
KiB.

For users of the Qemu device model, if the Xen firmware directory is not
configured as one of the Qemu firmware directories, the "intel-opregion"
and "intel-vbt" files must be moved or copied to a Qemu firmware directory
to provide proper support for an IGD with an extended VBT that is passed
through to a Xen HVM guest.

Signed-off-by: Chuck Zmudzinski <brchuckz@xxxxxxx>
---
This patch also depends on the companion patch for the Qemu device model
available here:

https://lore.kernel.org/qemu-devel/20260911072453.46256-7-brchuckz@xxxxxxx/

There is not an up-to-date specification for the OpRegion and VBT available
to the public online but an older version is available here:

https://www.intel.com/content/www/us/en/docs/graphics-for-linux/developer-reference/1-0/opregion-specification.html

Despite the fact that we do not have an up-to-date specification, patches
to the Linux kernel i915 driver and the igd-related files of the Linux kernel
vfio driver provide enough information about the specification to provide
support for the Intel IGD in Xen HVM guests. These patches to the Linux
kernel vfio driver were particularly helpful for this series of patches to
fix support for IGD passthrough for Xen HVM guests:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/vfio/pci/vfio_pci_igd.c?id=bab2c1990b78
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/drivers/vfio/pci/vfio_pci_igd.c?id=49ba1a2976c8

Many more details about the support for Intel IGD passthrough to Xen guests
is available in the other patch in this series and the 7 patches of the
companion patch series for the device model. Please refer to those patches
before asking questions that might be answered by reading through those
other patches.

Changes in v4:
  - This is the first version of this series of IGD fixes with this patch

 tools/libs/light/libxl_pci.c | 82 ++++++++++++++++++++++++++++++++++++
 1 file changed, 82 insertions(+)

diff --git a/tools/libs/light/libxl_pci.c b/tools/libs/light/libxl_pci.c
index 49d272d..ff28387 100644
--- a/tools/libs/light/libxl_pci.c
+++ b/tools/libs/light/libxl_pci.c
@@ -25,6 +25,9 @@
 #define PCI_OPTIONS            "msitranslate=%d,power_mgmt=%d"
 #define PCI_BDF_XSPATH         "%04x-%02x-%02x-%01x"
 #define PCI_PT_QDEV_ID         "pci-pt-%02x_%02x.%01x"
+#define PCI_OPREGION_SIZE      0x2000
+#define PCI_OPREGION_RVDS      0x3c2 /* offset of RVDS in OpRegion */
+#define PCI_VBT_MBOX4_SIZE     0x1800
 
 /* PCI Interrupt Line is an 8-bit value, 0xff means disconnected. */
 #define PCI_IRQ_LINE_LIMIT     0xff
@@ -765,6 +768,17 @@ static int libxl__device_pci_assignable_add(libxl__gc *gc,
     const char *name;
     int rc;
     struct stat st;
+    uint32_t rvds = 0; /* Intel VBT size */
+    int fd = -1;
+    char *spath1 = NULL;
+    char *dpath1 = NULL;
+    char *spath2 = NULL;
+    char *dpath2 = NULL;
+    uint8_t *buf1 = NULL;
+    uint8_t *buf2 = NULL;
+    uint16_t pt_vendor = 0xffff;
+    uint16_t pt_device = 0xffff;
+    unsigned long class = 0;
 
     /* Local copy for convenience */
     dom = pci->domain;
@@ -797,6 +811,74 @@ static int libxl__device_pci_assignable_add(libxl__gc *gc,
         return ERROR_FAIL;
     }
 
+    pt_vendor = sysfs_dev_get_vendor(gc, pci);
+    pt_device = sysfs_dev_get_device(gc, pci);
+
+    /* Check if the device is an Intel IGD */
+    if ( pt_vendor != 0x8086 || pt_device == 0xffff ||
+        sysfs_dev_get_class(gc, pci, &class) ||
+        (class != 0x030000 && class != 0x038000) )
+        goto skipigd;
+
+    /* These filenames match the filenames used in the device model */
+    dpath1 = libxl__abs_path(gc, "intel-opregion",
+                             libxl__xenfirmwaredir_path());
+    dpath2 = libxl__abs_path(gc, "intel-vbt",
+                             libxl__xenfirmwaredir_path());
+
+    /* Check if the OpRegion and VBT files are already present */
+    if ( !lstat(dpath1, &st) && !lstat(dpath2, &st) )
+        goto skipigd;
+
+    spath1 = GCSPRINTF("/sys/kernel/debug/dri/"PCI_BDF"/i915_opregion",
+                       dom, bus, dev, func);
+    spath2 = GCSPRINTF("/sys/kernel/debug/dri/"PCI_BDF"/i915_vbt",
+                       dom, bus, dev, func);
+
+    /*
+     * Try to copy the OpRegion and VBT while IGD is bound to i915 driver
+     * but don't return an error if one or both of the copies fail.
+     */
+    if ( !lstat(spath1, &st) && !lstat(spath2, &st) ) {
+        fd = open(spath1, O_RDONLY);
+        GCNEW_ARRAY(buf1, PCI_OPREGION_SIZE);
+        rc = libxl_read_exactly(ctx, fd, (void *)buf1, PCI_OPREGION_SIZE,
+                                spath1, NULL);
+        close(fd);
+        if ( !rc ) {
+            fd = open(dpath1, O_CREAT|O_WRONLY|O_TRUNC, 0644);
+            rc = libxl_write_exactly(ctx, fd, (void *)buf1,
+                                     PCI_OPREGION_SIZE, dpath1, NULL);
+            close(fd);
+            if ( !rc ) {
+                rvds = *(uint32_t *)(buf1 + PCI_OPREGION_RVDS);
+                if ( !rvds ) /* VBT is embedded in the OpRegion */
+                    rvds = PCI_VBT_MBOX4_SIZE;
+                fd = open(spath2, O_RDONLY);
+                GCNEW_ARRAY(buf2, rvds);
+                rc = libxl_read_exactly(ctx, fd, (void *)buf2, rvds,
+                                        spath2, NULL);
+                close(fd);
+                if ( !rc ) {
+                    fd = open(dpath2, O_CREAT|O_WRONLY|O_TRUNC, 0644);
+                    rc = libxl_write_exactly(ctx, fd, (void *)buf2,
+                                             rvds, dpath2, NULL);
+                    close(fd);
+                    if ( rc ) {
+                        LOG(INFO, "Failed to copy VBT");
+                    }
+                } else {
+                    LOG(INFO, "Failed to read VBT from debugfs");
+                }
+            } else {
+                LOG(INFO, "Failed to copy OpRegion");
+            }
+        } else {
+            LOG(INFO, "Failed to read OpRegion from debugfs");
+        }
+    }
+
+skipigd:
     /* Check to see if it's already assigned to pciback */
     rc = pciback_dev_is_assigned(gc, pci);
     if ( rc < 0 ) {
-- 
2.52.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.