@@ -3916,7 +3916,7 @@ int amdgpu_device_init(struct amdgpu_device *adev,
* ignore it
*/
if ((adev->pdev->class >> 8) == PCI_CLASS_DISPLAY_VGA)
- vga_client_register(adev->pdev, amdgpu_device_vga_set_decode);
+ vga_client_register(adev->pdev, amdgpu_device_vga_set_decode, NULL);
px = amdgpu_device_supports_px(ddev);
@@ -115,7 +115,6 @@ intel_vga_set_decode(struct pci_dev *pdev, bool enable_decode)
int intel_vga_register(struct drm_i915_private *i915)
{
-
struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
int ret;
@@ -127,7 +126,7 @@ int intel_vga_register(struct drm_i915_private *i915)
* then we do not take part in VGA arbitration and the
* vga_client_register() fails with -ENODEV.
*/
- ret = vga_client_register(pdev, intel_vga_set_decode);
+ ret = vga_client_register(pdev, intel_vga_set_decode, NULL);
if (ret && ret != -ENODEV)
return ret;
@@ -289,7 +289,7 @@ static int lsdc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, ddev);
- vga_client_register(pdev, lsdc_vga_set_decode);
+ vga_client_register(pdev, lsdc_vga_set_decode, NULL);
drm_kms_helper_poll_init(ddev);
@@ -92,7 +92,7 @@ nouveau_vga_init(struct nouveau_drm *drm)
return;
pdev = to_pci_dev(dev->dev);
- vga_client_register(pdev, nouveau_vga_set_decode);
+ vga_client_register(pdev, nouveau_vga_set_decode, NULL);
/* don't register Thunderbolt eGPU with vga_switcheroo */
if (pci_is_thunderbolt_attached(pdev))
@@ -1425,7 +1425,7 @@ int radeon_device_init(struct radeon_device *rdev,
/* if we have > 1 VGA cards, then disable the radeon VGA resources */
/* this will fail for cards that aren't VGA class devices, just
* ignore it */
- vga_client_register(rdev->pdev, radeon_vga_set_decode);
+ vga_client_register(rdev->pdev, radeon_vga_set_decode, NULL);
if (rdev->flags & RADEON_IS_PX)
runtime = true;
@@ -53,6 +53,7 @@ struct vga_device {
bool bridge_has_one_vga;
bool is_firmware_default; /* device selected by firmware */
unsigned int (*set_decode)(struct pci_dev *pdev, bool decode);
+ bool (*be_primary)(struct pci_dev *pdev);
};
static LIST_HEAD(vga_list);
@@ -956,6 +957,10 @@ EXPORT_SYMBOL(vga_set_legacy_decoding);
* @set_decode callback: If a client can disable its GPU VGA resource, it
* will get a callback from this to set the encode/decode state.
*
+ * @be_primary callback: Callback to the device driver, query if a device
+ * want to be the primary display. This callback is optional, device drivers
+ * who have no special needs can simply pass a NULL.
+ *
* Rationale: we cannot disable VGA decode resources unconditionally some single
* GPU laptops seem to require ACPI or BIOS access to the VGA registers to
* control things like backlights etc. Hopefully newer multi-GPU laptops do
@@ -971,7 +976,8 @@ EXPORT_SYMBOL(vga_set_legacy_decoding);
* Returns: 0 on success, -1 on failure
*/
int vga_client_register(struct pci_dev *pdev,
- unsigned int (*set_decode)(struct pci_dev *pdev, bool decode))
+ unsigned int (*set_decode)(struct pci_dev *pdev, bool decode),
+ bool (*be_primary)(struct pci_dev *pdev))
{
int ret = -ENODEV;
struct vga_device *vgadev;
@@ -983,6 +989,7 @@ int vga_client_register(struct pci_dev *pdev,
goto bail;
vgadev->set_decode = set_decode;
+ vgadev->be_primary = be_primary;
ret = 0;
bail:
@@ -1493,6 +1500,21 @@ static void vga_arbiter_notify_clients(void)
spin_unlock_irqrestore(&vga_lock, flags);
}
+static void vga_arbiter_do_arbitration(struct pci_dev *pdev)
+{
+ struct vga_device *vgadev;
+
+ if (pdev == vga_default_device())
+ return;
+
+ vgadev = vgadev_find(pdev);
+ if (vgadev && vgadev->be_primary && vgadev->be_primary(pdev)) {
+ vga_set_default_device(pdev);
+
+ vgaarb_info(&pdev->dev, "Override as primary by driver\n");
+ }
+}
+
static int pci_notify(struct notifier_block *nb, unsigned long action,
void *data)
{
@@ -1505,13 +1527,24 @@ static int pci_notify(struct notifier_block *nb, unsigned long action,
/* For now we're only intereted in devices added and removed. I didn't
* test this thing here, so someone needs to double check for the
* cases of hotplugable vga cards. */
- if (action == BUS_NOTIFY_ADD_DEVICE)
+ switch (action) {
+ case BUS_NOTIFY_ADD_DEVICE:
notify = vga_arbiter_add_pci_device(pdev);
- else if (action == BUS_NOTIFY_DEL_DEVICE)
+ if (notify)
+ vga_arbiter_notify_clients();
+ break;
+ case BUS_NOTIFY_DEL_DEVICE:
notify = vga_arbiter_del_pci_device(pdev);
+ if (notify)
+ vga_arbiter_notify_clients();
+ break;
+ case BUS_NOTIFY_BOUND_DRIVER:
+ vga_arbiter_do_arbitration(pdev);
+ break;
+ default:
+ break;
+ }
- if (notify)
- vga_arbiter_notify_clients();
return 0;
}
@@ -2108,7 +2108,7 @@ static int vfio_pci_vga_init(struct vfio_pci_core_device *vdev)
if (ret)
return ret;
- ret = vga_client_register(pdev, vfio_pci_set_decode);
+ ret = vga_client_register(pdev, vfio_pci_set_decode, NULL);
if (ret)
return ret;
vga_set_legacy_decoding(pdev, vfio_pci_set_decode(pdev, false));
@@ -52,7 +52,8 @@ struct pci_dev *vga_default_device(void);
void vga_set_default_device(struct pci_dev *pdev);
int vga_remove_vgacon(struct pci_dev *pdev);
int vga_client_register(struct pci_dev *pdev,
- unsigned int (*set_decode)(struct pci_dev *pdev, bool state));
+ unsigned int (*set_decode)(struct pci_dev *pdev, bool state),
+ bool (*be_primary)(struct pci_dev *pdev));
#else /* CONFIG_VGA_ARB */
static inline void vga_set_legacy_decoding(struct pci_dev *pdev,
unsigned int decodes)
@@ -78,7 +79,8 @@ static inline int vga_remove_vgacon(struct pci_dev *pdev)
return 0;
}
static inline int vga_client_register(struct pci_dev *pdev,
- unsigned int (*set_decode)(struct pci_dev *pdev, bool state))
+ unsigned int (*set_decode)(struct pci_dev *pdev, bool state),
+ bool (*be_primary)(struct pci_dev *pdev))
{
return 0;
}
@@ -116,7 +118,7 @@ static inline int vga_get_uninterruptible(struct pci_dev *pdev,
static inline void vga_client_unregister(struct pci_dev *pdev)
{
- vga_client_register(pdev, NULL);
+ vga_client_register(pdev, NULL, NULL);
}
#endif /* LINUX_VGA_H */