#include <linux/types.h>
 #include <linux/uaccess.h>
 #include <linux/vfio.h>
+#include <linux/vgaarb.h>
 
 #include "vfio_pci_private.h"
 
 #endif
 }
 
+/*
+ * Our VGA arbiter participation is limited since we don't know anything
+ * about the device itself.  However, if the device is the only VGA device
+ * downstream of a bridge and VFIO VGA support is disabled, then we can
+ * safely return legacy VGA IO and memory as not decoded since the user
+ * has no way to get to it and routing can be disabled externally at the
+ * bridge.
+ */
+static unsigned int vfio_pci_set_vga_decode(void *opaque, bool single_vga)
+{
+       struct vfio_pci_device *vdev = opaque;
+       struct pci_dev *tmp = NULL, *pdev = vdev->pdev;
+       unsigned char max_busnr;
+       unsigned int decodes;
+
+       if (single_vga || !vfio_vga_disabled() || pci_is_root_bus(pdev->bus))
+               return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM |
+                      VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
+
+       max_busnr = pci_bus_max_busnr(pdev->bus);
+       decodes = VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+
+       while ((tmp = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, tmp)) != NULL) {
+               if (tmp == pdev ||
+                   pci_domain_nr(tmp->bus) != pci_domain_nr(pdev->bus) ||
+                   pci_is_root_bus(tmp->bus))
+                       continue;
+
+               if (tmp->bus->number >= pdev->bus->number &&
+                   tmp->bus->number <= max_busnr) {
+                       pci_dev_put(tmp);
+                       decodes |= VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
+                       break;
+               }
+       }
+
+       return decodes;
+}
+
+static inline bool vfio_pci_is_vga(struct pci_dev *pdev)
+{
+       return (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA;
+}
+
 static void vfio_pci_try_bus_reset(struct vfio_pci_device *vdev);
 
 static int vfio_pci_enable(struct vfio_pci_device *vdev)
        } else
                vdev->msix_bar = 0xFF;
 
-       if (!vfio_vga_disabled() && (pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
+       if (!vfio_vga_disabled() && vfio_pci_is_vga(pdev))
                vdev->has_vga = true;
 
        return 0;
                kfree(vdev);
        }
 
+       if (vfio_pci_is_vga(pdev)) {
+               vga_client_register(pdev, vdev, NULL, vfio_pci_set_vga_decode);
+               vga_set_legacy_decoding(pdev,
+                                       vfio_pci_set_vga_decode(vdev, false));
+       }
+
        return ret;
 }
 
        struct vfio_pci_device *vdev;
 
        vdev = vfio_del_group_dev(&pdev->dev);
-       if (vdev) {
-               iommu_group_put(pdev->dev.iommu_group);
-               kfree(vdev);
+       if (!vdev)
+               return;
+
+       iommu_group_put(pdev->dev.iommu_group);
+       kfree(vdev);
+
+       if (vfio_pci_is_vga(pdev)) {
+               vga_client_register(pdev, NULL, NULL, NULL);
+               vga_set_legacy_decoding(pdev,
+                               VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM |
+                               VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM);
        }
 }