mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2] PCI: vgaarb: Include 0x0380 devices in boot VGA selection
@ 2026-06-22  6:13 Aaron Ma
  2026-06-22 16:09 ` Mario Limonciello
  0 siblings, 1 reply; 4+ messages in thread
From: Aaron Ma @ 2026-06-22  6:13 UTC (permalink / raw)
  To: Bjorn Helgaas, linux-pci, linux-kernel; +Cc: mario.limonciello

Some firmware boot displays use PCI class 0x0380
(PCI_CLASS_DISPLAY_OTHER). vgaarb only registers pci_is_vga()
devices, so those devices are skipped by vga_is_firmware_default()
and cannot become vga_default_device().

On hybrid systems this can leave a discrete VGA GPU as
vga_default_device() even when the firmware framebuffer is on the
0x0380 device. That makes boot_vga point at the wrong GPU and can
make boot_display report multiple devices through different paths.

Register legacy VGA and 0x0380 display devices for default selection
and boot_vga visibility. Keep legacy VGA decode ownership limited to
pci_is_vga() devices so 0x0380 devices are not treated as legacy VGA
decoders.

Signed-off-by: Aaron Ma <aaron.ma@canonical.com>
---
Changes in v2:
- Keep legacy VGA decodes and owns limited to pci_is_vga() devices.
- Keep 0x0380 devices eligible for firmware/default selection and
  boot_vga visibility without treating them as legacy VGA decoders.
- Update the commit message to describe the boot_vga compatibility goal.

 drivers/pci/pci-sysfs.c |  3 ++-
 drivers/pci/vgaarb.c    | 27 +++++++++++++++------------
 include/linux/pci.h     | 14 ++++++++++++++
 3 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index d37860841260c..843d83ec9550a 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -1717,7 +1717,8 @@ static umode_t pci_dev_attrs_are_visible(struct kobject *kobj,
 	struct device *dev = kobj_to_dev(kobj);
 	struct pci_dev *pdev = to_pci_dev(dev);
 
-	if (a == &dev_attr_boot_vga.attr && pci_is_vga(pdev))
+	if (a == &dev_attr_boot_vga.attr &&
+	    pci_is_vga_or_other_display(pdev))
 		return a->mode;
 
 	if (a == &dev_attr_serial_number.attr && pci_get_dsn(pdev))
diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c
index c360eee11dd9e..56a86779e6d28 100644
--- a/drivers/pci/vgaarb.c
+++ b/drivers/pci/vgaarb.c
@@ -741,6 +741,7 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
 	unsigned long flags;
 	struct pci_bus *bus;
 	struct pci_dev *bridge;
+	bool legacy_vga = pci_is_vga(pdev);
 	u16 cmd;
 
 	/* Allocate structure */
@@ -762,21 +763,23 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
 	}
 	vgadev->pdev = pdev;
 
-	/* By default, assume we decode everything */
-	vgadev->decodes = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
-			  VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+	/* By default, assume VGA devices decode everything */
+	vgadev->decodes = VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
+	if (legacy_vga)
+		vgadev->decodes |= VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
 
-	/* By default, mark it as decoding */
-	vga_decode_count++;
+	/* By default, mark legacy VGA devices as decoding */
+	if (vgadev->decodes & VGA_RSRC_LEGACY_MASK)
+		vga_decode_count++;
 
 	/*
 	 * Mark that we "own" resources based on our enables, we will
 	 * clear that below if the bridge isn't forwarding.
 	 */
 	pci_read_config_word(pdev, PCI_COMMAND, &cmd);
-	if (cmd & PCI_COMMAND_IO)
+	if (legacy_vga && (cmd & PCI_COMMAND_IO))
 		vgadev->owns |= VGA_RSRC_LEGACY_IO;
-	if (cmd & PCI_COMMAND_MEMORY)
+	if (legacy_vga && (cmd & PCI_COMMAND_MEMORY))
 		vgadev->owns |= VGA_RSRC_LEGACY_MEM;
 
 	/* Check if VGA cycles can get down to us */
@@ -796,7 +799,7 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
 	}
 
 	if (vga_is_boot_device(vgadev)) {
-		vgaarb_info(&pdev->dev, "setting as boot VGA device%s\n",
+		vgaarb_info(&pdev->dev, "setting as boot display device%s\n",
 			    vga_default_device() ?
 			    " (overriding previous)" : "");
 		vga_set_default_device(pdev);
@@ -1483,8 +1486,8 @@ static int pci_notify(struct notifier_block *nb, unsigned long action,
 
 	vgaarb_dbg(dev, "%s\n", __func__);
 
-	/* Only deal with VGA class devices */
-	if (!pci_is_vga(pdev))
+	/* Only deal with legacy VGA and other display controller devices */
+	if (!pci_is_vga_or_other_display(pdev))
 		return 0;
 
 	/*
@@ -1530,12 +1533,12 @@ static int __init vga_arb_device_init(void)
 
 	bus_register_notifier(&pci_bus_type, &pci_notifier);
 
-	/* Add all VGA class PCI devices by default */
+	/* Add legacy VGA and other display controller PCI devices by default */
 	pdev = NULL;
 	while ((pdev =
 		pci_get_subsys(PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
 			       PCI_ANY_ID, pdev)) != NULL) {
-		if (pci_is_vga(pdev))
+		if (pci_is_vga_or_other_display(pdev))
 			vga_arbiter_add_pci_device(pdev);
 	}
 
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 2c4454583c115..195ec1bdac863 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -792,6 +792,20 @@ static inline bool pci_is_vga(struct pci_dev *pdev)
 	return false;
 }
 
+/**
+ * pci_is_vga_or_other_display - check if the PCI device is VGA or 0x0380
+ * @pdev: PCI device
+ *
+ * Return true for legacy VGA-compatible devices and for "other display
+ * controller" devices.  Some firmware-selected boot display devices expose
+ * class 0x0380 instead of PCI_CLASS_DISPLAY_VGA.
+ */
+static inline bool pci_is_vga_or_other_display(struct pci_dev *pdev)
+{
+	return pci_is_vga(pdev) ||
+		(pdev->class >> 8) == PCI_CLASS_DISPLAY_OTHER;
+}
+
 /**
  * pci_is_display - check if the PCI device is a display controller
  * @pdev: PCI device
-- 
2.43.0

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-06-23 14:16 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-22  6:13 [PATCH v2] PCI: vgaarb: Include 0x0380 devices in boot VGA selection Aaron Ma
2026-06-22 16:09 ` Mario Limonciello
2026-06-23  7:32   ` Thomas Zimmermann
2026-06-23 14:16     ` Mario Limonciello

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox