From: Mario Limonciello <superm1@kernel.org>
To: Daniel Dadap <ddadap@nvidia.com>
Cc: Lukas Wunner <lukas@wunner.de>,
Bjorn Helgaas <helgaas@kernel.org>,
Alex Williamson <alex.williamson@redhat.com>,
mario.limonciello@amd.com, bhelgaas@google.com,
Thomas Zimmermann <tzimmermann@suse.de>,
linux-pci@vger.kernel.org, Hans de Goede <hansg@kernel.org>
Subject: Re: [PATCH] PCI/VGA: Look at all PCI display devices in VGA arbiter
Date: Tue, 17 Jun 2025 12:01:37 -0500 [thread overview]
Message-ID: <794844d0-6cc6-4efe-b91f-8b0af8251d80@kernel.org> (raw)
In-Reply-To: <aFGZhIS4IPxyjPCE@ddadap-lakeline.nvidia.com>
On 6/17/25 11:36 AM, Daniel Dadap wrote:
> On Tue, Jun 17, 2025 at 11:06:00AM -0500, Mario Limonciello wrote:
>> On 6/17/25 10:53 AM, Daniel Dadap wrote:
>>> On Mon, Jun 16, 2025 at 09:14:04PM +0200, Lukas Wunner wrote:
>>>> On Mon, Jun 16, 2025 at 10:05:48AM -0500, Daniel Dadap wrote:
>>>>> On Sat, Jun 14, 2025 at 09:04:52AM +0200, Lukas Wunner wrote:
>>>>>> On Fri, Jun 13, 2025 at 04:47:20PM -0500, Daniel Dadap wrote:
>>>>>>> Ideally we'd be able to actually query which GPU is connected to
>>>>>>> the panel at the time we're making this determination, but I don't
>>>>>>> think there's a uniform way to do this at the moment. Selecting the
>>>>>>> integrated GPU seems like a reasonable heuristic, since I'm not
>>>>>>> aware of any systems where the internal panel defaults to dGPU
>>>>>>> connection, since that would defeat the purpose of having a hybrid
>>>>>>> GPU system in the first place
>>>>>>
>>>>>> Intel-based dual-GPU MacBook Pros boot with the panel switched to the
>>>>>> dGPU by default. This is done for Windows compatibility because Apple
>>>>>> never bothered to implement dynamic GPU switching on Windows.
>>>>>>
>>>>>> The boot firmware can be told to switch the panel to the iGPU via an
>>>>>> EFI variable, but that's not something the kernel can or should depend on.
>>>>>>
>>>>>> MacBook Pros introduced since 2013/2014 hide the iGPU if the panel is
>>>>>> switched to the dGPU on boot, but the kernel is now unhiding it since
>>>>>> 71e49eccdca6.
>>>>>
>>>>> This is good to know. Is vga_switcheroo initialized by the time the code
>>>>> in this patch runs? If so, maybe we should query switcheroo to determine
>>>>> the GPU which is connected to the panel and favor that one, then fall
>>>>> back to the "iGPU is probably right" heuristic otherwise.
>>>>
>>>> Right now vga_switcheroo doesn't seem to provide a function to query the
>>>> current mux state.
>>>>
>>>> The driver for the mux on MacBook Pros, apple_gmux.c, can be modular,
>>>> so may be loaded fairly late.
>>>
>>> Yeah, that's what I was afraid of.
>>>
>>>>
>>>> Personally I'm booting my MacBook Pro via EFI, so the GPU in use is
>>>> whatever efifb is talking to. However it is possible to boot these
>>>> machines in a legacy CSM mode and I don't know what the situation
>>>> looks like in that case.
>>>>
>>>
>>> Skimming through the code, this seems like the sort of thing that the
>>> existing check in vga_is_firmware_default() is testing. I'm not familiar
>>> enough with the relevant code to intuitively know whether it is supposed
>>> to work for UEFI or legacy VGA or both (I think both?).
>>>
>>> Mario, on the affected system, what does vga_is_firmware_default() return
>>> on each of the GPUs? (I'd expect it to return true for the iGPU and false
>>> for the dGPU, but I think the (boot_vga && boot_vga->is_firmware_default)
>>> test would cause vga_is_boot_device() to return false if the vga_default
>>> is passed into it a second time. That made sense for the way that the
>>> function was originally called, to test if the passed-in vgadev is any
>>> "better" than vga_default, and from a quick skim it doesn't seem like it
>>> would get called multiple times in the new code either, but I worry that
>>> if someone else decides they need to call vga_is_boot_device() a second
>>> time in the future it might return a false result for vga_default.)
>>>
>>
>> Right "now" on an unpatched kernel it won't run 'at all' because
>> vga_arb_device_init() only matches VGA class devices.
>>
>> Both GPUs are not VGA compatible, which is what lead to the patch in this
>> thread starting to match display class devices too.
>>
>>
>
> Sure, I was curious what vga_is_firmware_default() returns for each of
> the GPUs when run, regardless of whether or not it's currently being run
> in the existing code - I'm wondering if vga_is_firmware_default() can be
> a better tie breaker (or at least a first line tie breaker) than the one
> you have now which tests for iGPU. I kind of went off on a tangent about
> vga_is_boot_device() being possibly unreliable for a second time caller
> when I was checking the callers of vga_is_firmware_default().
>
That's actually a really good point. Here's the diff I tried.
diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c
index 78748e8d2dba..b4e085806544 100644
--- a/drivers/pci/vgaarb.c
+++ b/drivers/pci/vgaarb.c
@@ -816,6 +816,8 @@ static bool vga_arbiter_add_pci_device(struct
pci_dev *pdev)
bus = bus->parent;
}
+ pci_info(pdev, "is firmware default: %d\n",
vga_is_firmware_default(pdev));
+
if (vga_is_boot_device(vgadev)) {
vgaarb_info(&pdev->dev, "setting as boot VGA device%s\n",
vga_default_device() ?
@@ -1500,7 +1502,7 @@ 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))
+ if (!pci_is_display(pdev))
return 0;
/*
@@ -1551,7 +1553,7 @@ static int __init vga_arb_device_init(void)
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_display(pdev))
vga_arbiter_add_pci_device(pdev);
}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 05e68f35f392..077e90a2af37 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -744,6 +744,22 @@ static inline bool pci_is_vga(struct pci_dev *pdev)
return false;
}
+
+/**
+ * pci_is_display - Check if a PCI device is a display controller
+ * @pdev: Pointer to the PCI device structure
+ *
+ * This function determines whether the given PCI device corresponds
+ * to a display controller. Display controllers are typically used
+ * for graphical output and are identified based on their class code.
+ *
+ * Return: true if the PCI device is a display controller, false otherwise.
+ */
+static inline bool pci_is_display(struct pci_dev *pdev)
+{
+ return (pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY;
+}
+
#define for_each_pci_bridge(dev, bus) \
list_for_each_entry(dev, &bus->devices, bus_list) \
if (!pci_is_bridge(dev)) {} else
On 6.16-rc2 with that applied:
$ lspci | grep "\[03"
c6:00.0 3D controller [0302]: NVIDIA Corporation Device (rev a1)
c7:00.0 Display controller [0380]: Advanced Micro Devices, Inc.
[AMD/ATI] Device (rev d1)
$ sudo dmesg | grep "firmware default"
[ 0.379664] pci 0000:c6:00.0: is firmware default: 0
[ 0.379664] pci 0000:c7:00.0: is firmware default: 1
Which actually means that the existing code when making a second pass
the correct GPU *is* getting set using that as a tie breaker.
$ sudo dmesg | grep arb
[ 0.379664] pci 0000:c6:00.0: vgaarb: setting as boot VGA device
[ 0.379664] pci 0000:c6:00.0: vgaarb: bridge control possible
[ 0.379664] pci 0000:c6:00.0: vgaarb: VGA device added:
decodes=io+mem,owns=none,locks=none
[ 0.379664] pci 0000:c7:00.0: vgaarb: setting as boot VGA device
(overriding previous)
[ 0.379664] pci 0000:c7:00.0: vgaarb: bridge control possible
[ 0.379664] pci 0000:c7:00.0: vgaarb: VGA device added:
decodes=io+mem,owns=none,locks=none
[ 0.379664] vgaarb: loaded
[ 4.108302] amdgpu 0000:c7:00.0: vgaarb: deactivate vga console
IE if changing pci_dev_attrs_are_visible() to show for all display
devices it /should/ work without the logic changes I had.
next prev parent reply other threads:[~2025-06-17 17:01 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-06-13 3:12 [PATCH] PCI/VGA: Look at all PCI display devices in VGA arbiter Mario Limonciello
2025-06-13 19:07 ` Bjorn Helgaas
2025-06-13 19:31 ` Mario Limonciello
2025-06-13 20:31 ` Bjorn Helgaas
2025-06-13 20:56 ` Mario Limonciello
2025-06-13 21:47 ` Daniel Dadap
2025-06-14 7:04 ` Lukas Wunner
2025-06-16 15:05 ` Daniel Dadap
2025-06-16 19:14 ` Lukas Wunner
2025-06-17 15:53 ` Daniel Dadap
2025-06-17 16:06 ` Mario Limonciello
2025-06-17 16:36 ` Daniel Dadap
2025-06-17 17:01 ` Mario Limonciello [this message]
2025-06-13 21:19 ` Alex Williamson
2025-06-13 21:29 ` Mario Limonciello
2025-06-16 6:42 ` Thomas Zimmermann
2025-06-16 6:50 ` David Airlie
2025-06-16 7:21 ` Thomas Zimmermann
2025-06-16 7:24 ` David Airlie
2025-06-16 9:11 ` Gerd Hoffmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=794844d0-6cc6-4efe-b91f-8b0af8251d80@kernel.org \
--to=superm1@kernel.org \
--cc=alex.williamson@redhat.com \
--cc=bhelgaas@google.com \
--cc=ddadap@nvidia.com \
--cc=hansg@kernel.org \
--cc=helgaas@kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=lukas@wunner.de \
--cc=mario.limonciello@amd.com \
--cc=tzimmermann@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).