On Tue, Aug 04, 2026 at 06:01:54AM +0000, Haram Choi wrote:
> I think I have found the commit. It is not in drivers/pci at all, and
> my previous suspicion of 94555ea9a048 was wrong. Apologies to Simon
> for the noise.
> 
> The regression is:
> 
>   cc6ed470caa2 ("drm/i915/vga: Avoid VGA arbiter during
>                  intel_vga_disable() for iGPUs")
>   Ville Syrjala <[email protected]>, 2025-12-08
> 
> I have added Ville, intel-gfx and dri-devel to Cc.
> 
> Two corrections to my earlier mail while I am at it:
> 
>   - 94555ea9a048 is not involved. My instrumented build shows
> pci_set_vga_state() returning 0, and no -EIO anywhere. The
> bookkeeping-mismatch theory was wrong.
> 
>   - The bit 4 (VGA 16-bit decode) "open question" from my last mail
> dissolves. The firmware default on this machine is BRIDGE_CONTROL =
> 0x0002, i.e. bit 4 clear, on working and broken kernels alike. Working
> kernels are fine only because bit 3 is never set. Bit 4 is not a
> second regression and the kernel indeed never writes it.
> 
> ## The mechanism: whoever touches the VGA arbiter first wins
> 
> The topology matters:
> 
>   00:02.0  i915    - directly on bus 0, no bridge above it
>   01:00.0 amdgpu   - behind pcieport 00:01.0
> 
> pci_set_vga_state() writes PCI_BRIDGE_CTL_VGA by walking the bridges
> above the device. For the iGPU that walk is empty and writes nothing.
> For the dGPU it writes 00:01.0.
> 
> vga_check_first_use() runs exactly once per boot, on the first
> vga_get()/vga_tryget(). Whichever GPU triggers it determines whether
> any bridge gets written at all. __vga_put() never calls
> pci_set_vga_state(), so once the bit is set it stays set until reboot.
> 
> Before cc6ed470caa2, intel_vga_disable() unconditionally called
> 
>   vga_get_uninterruptible(igpu_pdev, VGA_RSRC_LEGACY_IO);
> 
> during i915 probe. The iGPU therefore always won that race, and since
> it has no bridge above it, nothing was ever written.
> 
> After cc6ed470caa2 the iGPU takes the display->platform.dgfx == false
> path, bypasses the arbiter, and just sets PCI_COMMAND_IO by hand. The
> arbiter now has no user at all until X starts. X then opens
> /dev/vga_arbiter and targets vga_default_device(), which is the dGPU,
> and __vga_tryget() reaches enable_them: with
> PCI_VGA_STATE_CHANGE_BRIDGE set. That writes PCI_BRIDGE_CTL_VGA on 00:01.0.
> 
> The commit's stated intent was to stop the iGPU from clobbering the
> VGA routing of an external GPU. On this machine, removing the iGPU
> from the race had the opposite effect: it let the dGPU become the
> first user and turned bridge VGA forwarding on.
> 
> ## Evidence
> 
> I built v7.1.5 with a printk in pci_set_vga_state() and in the bridge
> walk, and did three boots with my workaround disabled.
> 
> 1) v7.1.5 + instrumentation, normal graphical boot (X running):
> 
>   [10.716117] pcieport 0000:00:01.0: BRIDGE_CONTROL=0x0002 VGA_en=0
>   [10.716695] i915   0000:00:02.0: set_vga_state decode=0 flags=0x1
>   [10.717607] amdgpu 0000:01:00.0: set_vga_state decode=1 flags=0x1
>   [10.718134] pcieport 0000:00:01.0: ctl 0x0002 -> wrote 0x000a
>                                      -> read 0x000a
> 
>   # setpci -s 00:01.0 BRIDGE_CONTROL
>   000a
>   # cat /sys/class/backlight/gmux_backlight/actual_brightness
>   16777215                                        <- broken
> 
> Note the write happens at 10.7s, which is when lightdm/Xorg starts,
> not during any driver probe.
> 
> 2) The same kernel booted with systemd.unit=multi-user.target, i.e. no
> display manager, no X. Measured twice, 60 seconds apart:
> 
>   [10.167675] i915 0000:00:02.0: vgaarb: VGA decodes changed:
>               olddecodes=io+mem,decodes=io:owns=io+mem
> 
> ... and that is the entire vgaarb log for the boot. No
> vga_arbiter_notify_clients(), no pci_set_vga_state(), no bridge write.
> That single line is vga_set_legacy_decoding() from intel_vga.c, which
> does not count as arbiter "first use", so vga_arbiter_used stays
> false.
> 
>   # setpci -s 00:01.0 BRIDGE_CONTROL
>   0002
>   # cat /sys/class/backlight/gmux_backlight/actual_brightness
>   808  <- works
> 
> 3) v6.18.41 (before the commit), normal graphical boot, X running:
> 
>   [9.160032] i915   0000:00:02.0: vgaarb: VGA decodes changed:
>              olddecodes=io+mem,decodes=none:owns=io+mem
>   [9.166861] amdgpu 0000:01:00.0: vgaarb: VGA decodes changed:
>              olddecodes=io+mem,decodes=none:owns=none
>   [10.053446] i915 0000:00:02.0: [drm] [ENCODER:105:DDI A/PHY A]
>               failed to retrieve link info, disabling eDP
> 
>   # setpci -s 00:01.0 BRIDGE_CONTROL
>   0002
>   # cat /sys/class/backlight/gmux_backlight/actual_brightness
>   808                                             <- works
> 
> Here arbiter first use happens at 9.16s, during i915 probe, well
> before X. By the time X calls vga_get() on the dGPU, vga_arbiter_used
> is already true and vga_check_first_use() is a no-op.
> 
> So: same X, same hardware, same userspace. On v6.18 the iGPU gets
> there first and nothing is written. On v7.1.5 the iGPU is no longer in
> the race and the dGPU's bridge gets PCI_BRIDGE_CTL_VGA set.
> 
> This also narrows the regression window to v6.18..v7.1, which is where
> cc6ed470caa2 landed.
> 
> Boot 2 is the clean control: identical kernel, identical firmware
> state, and the only variable is whether a graphical session starts.
> 
> ## Why that kills the backlight
> 
> Recapping from my previous mail, since the audience has grown:
> 
> MacBookPro13,3 has an apple-gmux at PNP resource 0x700-0x7fe using the
> indexed protocol:
> 
>   GMUX_PORT_READ         0x7d0
>   GMUX_PORT_WRITE        0x7d4
>   index magic            0x7cc / 0x7cd / 0x7ce
> 
> With PCI_BRIDGE_CTL_VGA set and 16-bit decode clear, the bridge
> decodes legacy VGA I/O with only 10 address bits, so 0x3c0-0x3df
> aliases onto 0x7c0-0x7df. Every gmux port above is inside that window.
> The bridge claims the cycles and forwards them to the dGPU, so every
> gmux read returns 0xff and every gmux write is swallowed.
> 
> apple_gmux has already probed successfully by then, so it reports no
> error. actual_brightness just starts reading 16777215 (0x00ffffff,
> which is GMUX_BRIGHTNESS_MASK applied to all-ones) and nothing
> controls the panel any more. brightnessctl, the Touch Bar keys and the
> desktop slider all go through this one backlight device, so all three
> fail.
> 
> ## Workaround
> 
>   # setpci -s 00:01.0 BRIDGE_CONTROL=0000:0008
>   # modprobe -r apple_gmux && modprobe apple_gmux
> 
> Since the bridge write happens exactly once per boot, doing this once
> after the graphical session is up is sufficient for that boot.
> 
> ## Where I think the fix belongs
> 
> I do not think reverting cc6ed470caa2 is the right answer, since it
> fixes a real problem for dGPU users. But I would note that the iGPU
> was previously acting as an unintentional guard: by always being the
> first arbiter user, it kept bridge VGA forwarding off on machines
> where nothing needs it.
> 
> Two things look wrong to me independently of that commit, and I would
> appreciate an opinion from the PCI side:
> 
> 1. __vga_put() never calls pci_set_vga_state(), so PCI_BRIDGE_CTL_VGA
> is set on first use and then never cleared, even after both devices
> have settled at decodes=none. On this machine the final arbiter state
> is decodes=none for both GPUs, yet the bridge is still forwarding
> legacy VGA. That seems like a leak rather than intended behaviour.
> 
> 2. vga_arbiter_notify_clients() drives both devices to decodes=none
> when vga_count > 1, and the bridge write happens as part of that same
> first-use path. Enabling forwarding on a bridge while simultaneously
> telling every client it decodes nothing seems contradictory.
> 
> Either fixing (1) or having the iGPU still participate in the
> arbiter's first-use accounting without doing the I/O grab would
> resolve this machine.
> 
> I am happy to test any patch on this hardware. I have an instrumented
> build set up and can turn a test around in a couple of hours.
> 
> On Mon, Aug 3, 2026 at 8:01 PM Haram Choi <[email protected]> wrote:
> >
> > Resending to linux-pci as requested.
> >
> > Since the first mail I have narrowed this down further, and in doing
> > so found that my original description of the root cause was partly
> > wrong. The corrected analysis is below. The short version:
> >
> >   - The regression is that PCI_BRIDGE_CTL_VGA (bit 3) on the root port
> > 00:01.0 is left SET after the VGA arbiter has settled with
> > decodes=none for both VGA devices. On 6.12 and 6.16 it ends CLEAR.
> >
> >   - The 16-bit decode bit (bit 4) is not the cause. The kernel never
> > writes it. It only determines whether a bridge that is already
> > forwarding legacy VGA does so with 10 or 16 address bits.
> >
> >   - The subject line therefore misattributes the cause. The aliasing
> > is a consequence, not the trigger. I have kept the subject unchanged
> > so the thread stays intact.
> >
> > I have a v7.1.5 build with instrumentation in drivers/pci/pci.c and
> > drivers/pci/vgaarb.c ready to boot; I will follow up in this thread
> > with the traces.
> >
> > ## Summary
> >
> > Since Linux 7.1 the backlight on a MacBookPro13,3 (15" 2016, Touch
> > Bar) cannot be controlled at all. apple_gmux still probes successfully
> > during boot, but the VGA arbiter leaves PCI_BRIDGE_CTL_VGA set on the
> > root port 00:01.0. With legacy VGA forwarding enabled and only 10
> > address bits decoded, 0x3c0-0x3df aliases onto 0x7c0-0x7df, which is
> > exactly where the gmux indexed protocol registers live. The bridge
> > claims those cycles and forwards them to the dGPU. Every gmux read
> > returns 0xff and every gmux write is swallowed.
> >
> > - Last known good: 6.16.10 (Arch linux 6.16.10.arch1-1)
> > - Also good:       6.12.51 (Arch linux-lts 6.12.51-1)
> > - Bad:             7.1.5   (Arch linux 7.1.5.arch1-2)
> >
> > ## Hardware
> >
> > DMI: Apple Inc. MacBookPro13,3/Mac-A5C67F76ED83108C,
> >      BIOS 529.120.1.0.0 03/14/2024
> >
> > 00:01.0 PCI bridge [0604]: Intel 6th-10th Gen Core Processor PCIe
> >         Controller (x16) [8086:1901] (rev 07)
> > 00:02.0 VGA compatible controller [0300]: Intel Skylake-H GT2
> >         [HD Graphics 530] [8086:191b] (rev 06)   -> i915
> > 01:00.0 VGA compatible controller [0300]: AMD Baffin
> >         [Radeon Pro 455] [1002:67ef] (rev c7)    -> amdgpu
> >
> > gmux: PNP HID APP000B, "Found gmux version 4.0.29 [indexed]"
> >       PNP resource 0x700-0x7fe
> >
> > Note that 00:02.0 (i915) is not behind 00:01.0, but 01:00.0 (amdgpu) is.
> >
> > ## Symptom
> >
> >   $ cat /sys/class/backlight/gmux_backlight/actual_brightness
> >   16777215
> >
> > 16777215 is 0x00ffffff, which is GMUX_BRIGHTNESS_MASK applied to an
> > all-ones I/O read. Writes to brightness have no effect. brightnessctl,
> > the Touch Bar brightness keys and the desktop brightness slider all
> > fail, because all three go through this single backlight device.
> >
> > ## Root cause
> >
> > PCI_BRIDGE_CONTROL (offset 0x3e) of 00:01.0, read after boot has settled:
> >
> >   6.12.51-lts   : 0x0012   SERR | VGA_16BIT,  VGA enable CLEAR  -> works
> >   7.1.5-arch1-2 : 0x000a   SERR | VGA enable, VGA_16BIT CLEAR   -> broken
> >
> > I originally read this as "VGA_16BIT was cleared". That is not what
> > matters. I tested all four combinations of bit 3 and bit 4 at runtime
> > on 7.1.5 via setpci, reading actual_brightness after each change:
> >
> >   bit3 VGA_en   bit4 16BIT   value    actual_brightness   result
> >   -----------   ----------   ------   -----------------   ------
> >        1             1       0x001a          808          works
> >        0             1       0x0012          808          works
> >        1             0       0x000a       16777215        BROKEN
> >        0             0       0x0002          808          works
> >
> > Only the single combination "VGA enable set, 16-bit decode clear"
> > breaks gmux, which is exactly what the PCI-to-PCI Bridge specification
> > predicts: bit 4 only has meaning while bit 3 is set. So the regression
> > is that bit 3 is left set, not that bit 4 is clear.

Sounds to me like the best fix would be to explicitly enable
16 bit decoding on the bridges on these machines. That would
guarantee that apple-gmux works regardless of which GPU
drivers are loaded, and in which order.

> >
> > This also matches the code. PCI_BRIDGE_CTL_VGA_16BIT does not appear
> > anywhere in the v7.1.5 tree; it is not even defined in
> > include/uapi/linux/pci_regs.h, where the bit list goes straight from
> > PCI_BRIDGE_CTL_VGA (0x08) to PCI_BRIDGE_CTL_MASTER_ABORT (0x20). The
> > kernel never reads or writes bit 4, so bit 4 cannot be the regression.
> >
> > PCI_BRIDGE_CTL_VGA is written in exactly one place,
> > pci_set_vga_state() in drivers/pci/pci.c, which has exactly two
> > callers, both in drivers/pci/vgaarb.c.
> >
> > With bit 3 set and bit 4 clear, address bits [15:10] are ignored for
> > legacy VGA I/O, so:
> >
> >   0x3b0-0x3bb  ->  0x7b0-0x7bb
> >   0x3c0-0x3df  ->  0x7c0-0x7df
> >
> > apple-gmux uses these ports on this machine:
> >
> >   GMUX_PORT_READ         0x7d0     (aliases 0x3d0)
> >   GMUX_PORT_WRITE        0x7d4     (aliases 0x3d4)
> >   index magic sequence   0x7cc     (aliases 0x3cc)
> >                          0x7cd     (aliases 0x3cd)
> >                          0x7ce     (aliases 0x3ce)
> >
> > All of them fall inside the aliased window, so the bridge steals them.
> >
> > ## Direct verification via /dev/port on 7.1.5
> >
> > Before:
> >
> >   inb(0x7cc) = ff   inb(0x7cd) = ff   inb(0x7ce) = ff
> >   inb(0x7d0) = ff   inb(0x7d4) = ff
> >
> > Clearing VGA enable, or setting 16-bit decode, either one is sufficient:
> >
> >   # setpci -s 00:01.0 BRIDGE_CONTROL=0000:0008    # clear bit 3
> >   or
> >   # setpci -s 00:01.0 BRIDGE_CONTROL=0010:0010    # set bit 4
> >
> > After (gmux_is_indexed() magic sequence, write 0xaa/0x55/0x00 then read 
> > back):
> >
> >   outb(0x7cc, 0xaa); outb(0x7cd, 0x55); outb(0x7ce, 0x00)
> >   inb(0x7cc) = aa   inb(0x7cd) = 55        -> gmux responds
> >
> > Then:
> >
> >   # modprobe -r apple_gmux && modprobe apple_gmux
> >   apple_gmux: Found gmux version 4.0.29 [indexed]
> >
> >   # cat /sys/class/backlight/gmux_backlight/actual_brightness
> >   118
> >
> > 118 is the value the panel had actually been stuck at the whole time,
> > which confirms that no write had ever reached the hardware. Writing
> > 100 / 400 / 700 / 1023 afterwards changes the panel brightness,
> > visually confirmed.
> >
> > ## Boot timeline
> >
> > 7.1.5-arch1-2 (broken):
> >
> >   [  7.947] pci 0000:00:02.0: vgaarb: setting as boot VGA device
> >   [  7.947] pci 0000:00:02.0: vgaarb: VGA device added:
> >                                decodes=io+mem,owns=io+mem,locks=none
> >   [  7.947] pci 0000:01:00.0: vgaarb: setting as boot VGA device
> >                                (overriding previous)
> >   [  7.948] pci 0000:01:00.0: vgaarb: VGA device added:
> >                                decodes=io+mem,owns=none,locks=none
> >   [  8.005] amdgpu 0000:01:00.0: vgaarb: deactivate vga console
> >   [  9.494] apple_gmux: Found gmux version 4.0.29 [indexed]
> >   [ 10.059] i915 0000:00:02.0: vgaarb: VGA decodes changed:
> >                                olddecodes=io+mem,decodes=io:owns=io+mem
> >   [ 11.150] i915 0000:00:02.0: vgaarb: VGA decodes changed:
> >                                olddecodes=io,decodes=none:owns=io+mem
> >   [ 11.150] amdgpu 0000:01:00.0: vgaarb: VGA decodes changed:
> >                                olddecodes=io+mem,decodes=none:owns=none
> >
> > 6.16.10-arch1-1 (good):
> >
> >   [  6.785] pci 0000:00:02.0: vgaarb: VGA device added:
> >                                decodes=io+mem,owns=io+mem,locks=none
> >   [  6.785] pci 0000:01:00.0: vgaarb: setting as boot VGA device
> >                                (overriding previous)
> >   [  6.785] pci 0000:01:00.0: vgaarb: VGA device added:
> >                                decodes=io+mem,owns=none,locks=none
> >   [  6.839] amdgpu 0000:01:00.0: vgaarb: deactivate vga console
> >   [  8.339] apple_gmux: Found gmux version 4.0.29 [indexed]
> >   [  8.348] i915 0000:00:02.0: vgaarb: VGA decodes changed:
> >                                olddecodes=io+mem,decodes=none:owns=io+mem
> >   [  8.349] amdgpu 0000:01:00.0: vgaarb: VGA decodes changed:
> >                                olddecodes=io+mem,decodes=none:owns=none
> >
> > 6.12.51-lts (good):
> >
> >   [  8.480] apple_gmux: Found gmux version 4.0.29 [indexed]
> >   [  8.487] i915 0000:00:02.0: vgaarb: VGA decodes changed:
> >                                olddecodes=io+mem,decodes=none:owns=io+mem
> >   [  8.489] amdgpu 0000:01:00.0: vgaarb: VGA decodes changed:
> >                                olddecodes=io+mem,decodes=none:owns=none
> >
> > Two differences stand out:
> >
> > 1. On 7.1.5, 00:02.0 gets "setting as boot VGA device". On 6.16 it
> > does not, even though 01:00.0 still says "(overriding previous)" in
> > both.
> >
> > 2. On 6.12 and 6.16 the i915 legacy decode goes io+mem -> none in a
> > single step. On 7.1.5 it goes io+mem -> io, and then about 1.1 seconds
> > later io -> none.
> >
> > The final arbiter state is decodes=none for both devices on all three
> > kernels, yet only on 7.1.5 does the bridge end up with
> > PCI_BRIDGE_CTL_VGA set.
> >
> > ## Suspected commit
> >
> > Of the commits you listed for v6.16..v7.1 in drivers/pci/vgaarb.c, the
> > one that best fits is:
> >
> >   94555ea9a048 ("PCI/VGA: Pass errors from pci_set_vga_state() up")
> >
> > pci_set_vga_state() writes PCI_BRIDGE_CONTROL on each bridge in the
> > path and only afterwards reads the register back, returning -EIO if
> > VGA enable did not stick. It returns from inside the walk, so bridges
> > further up the path are left unprocessed and the ones already written
> > stay written.
> >
> > That error used to be discarded by __vga_tryget(). After 94555ea9a048
> > it aborts the function:
> >
> >     err = pci_set_vga_state(vgadev->pdev, true, pci_bits, flags);
> >     if (err)
> >         return ERR_PTR(err);
> >
> >     vgadev->owns |= wants;          /* now skipped on error */
> >
> > and likewise for the conflict path, where "conflict->owns &= ~match"
> > is skipped. Either way the arbiter's bookkeeping stops matching what
> > was actually programmed into the bridge, so the later transition to
> > decodes=none never issues the matching pci_set_vga_state(..., false,
> > ...) that would clear PCI_BRIDGE_CTL_VGA. The bridge stays enabled.
> >
> > The two-step i915 decode transition on 7.1.5 is consistent with an
> > operation that aborted partway and was retried.
> >
> > Two other candidates I have not excluded, both of which change which
> > device is selected as the boot VGA device and could explain difference
> > (1) above:
> >
> >   337bf13aa9dd ("PCI/VGA: Replace vga_is_firmware_default() with a
> >                  screen info check")
> >   fd390ff14451 ("PCI/VGA: Don't assume the only VGA device on a system
> >                  is boot_vga")
> >
> > I believe 2a93c9851b2b ("PCI/VGA: Pass vga_get_uninterruptible()
> > errors to userspace") can be excluded, since it only changes the
> > /dev/vga_arbiter write path, which is not used on this KMS-only
> > system.
> >
> > ## Workaround
> >
> >   # setpci -s 00:01.0 BRIDGE_CONTROL=0000:0008
> >   # modprobe -r apple_gmux && modprobe apple_gmux
> >
> > Clearing VGA enable is enough, and is what 6.12 and 6.16 end up with
> > anyway. This machine is KMS only and "amdgpu: vgaarb: deactivate vga
> > console" has already happened, so nothing depends on legacy VGA
> > forwarding here.
> >
> > (I had previously been using BRIDGE_CONTROL=0010:0010, setting 16-bit
> > decode. That also works, but it masks the symptom rather than
> > restoring the pre-7.1 state.)
> >
> > ## Open question
> >
> > I cannot explain why bit 4 reads as 1 on 6.12 and 0 on 7.1.5, given
> > that the kernel never writes it. The only full-register overwrites of
> > PCI_BRIDGE_CONTROL I can find are drivers/pci/setup-bus.c:907
> > (bus->bridge_ctl) and drivers/pci/probe.c:1571, neither of which
> > tracks bit 4. This does not affect the analysis above, since bit 4 is
> > harmless while bit 3 is clear, but it may be of interest.
> >
> > ## Notes
> >
> > - The breakage happens after apple_gmux has already probed, so the
> > driver reports no error. The failure is silent.
> > - drivers/platform/x86/apple-gmux.c only received cosmetic changes
> > during the 7.1 cycle, so this looks like a PCI / vgaarb side issue
> > rather than a driver bug.
> > - A machine with a discrete GPU behind 00:01.0 and gmux at 0x700-0x7fe
> > is the affected shape. MacBookPro13,1 and 13,2 have no dGPU and no
> > bridge in the path, so they are presumably unaffected.
> >
> > I am happy to test patches or revert candidates on this machine.
> >
> >
> > 2026년 8월 3일 (월) 오후 6:01, Bjorn Helgaas <[email protected]>님이 작성:
> > >
> > > Thanks for the report.  It does look like vgaarb.c is the most likely 
> > > culprit.  There are only a few commits to that file between v6.16 and 
> > > v7.1.  If you have time, it would be helpful to identify the specific one 
> > > that broke this.  Here's what git log v6.16..v7.1 said:
> > >
> > > 94555ea9a048 PCI/VGA: Pass errors from pci_set_vga_state() up
> > > 2a93c9851b2b PCI/VGA: Pass vga_get_uninterruptible() errors to userspace
> > > bf4afc53b77a Convert 'alloc_obj' family to use the new default GFP_KERNEL 
> > > argument
> > > 69050f8d6d07 treewide: Replace kmalloc with kmalloc_obj for non-scalar 
> > > types
> > > 0c61526621ec Merge tag 'efi-next-for-v7.0' of 
> > > git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi
> > > fd390ff14451 PCI/VGA: Don't assume the only VGA device on a system is 
> > > boot_vga
> > > a41e0ab394e4 sysfb: Replace screen_info with sysfb_primary_display
> > > a78835b86a44 PCI/VGA: Select SCREEN_INFO on X86
> > > 337bf13aa9dd PCI/VGA: Replace vga_is_firmware_default() with a screen 
> > > info check
> > >
> > > I think the convert, treewide, and merge commits are unlikely.
> > >
> > > Can you please resend this report to [email protected]?
> > >
> > > On Fri, Jul 31, 2026 at 5:57 PM Haram Choi <[email protected]> wrote:
> > >>
> > >> # [REGRESSION] 7.1: apple-gmux backlight dead on MacBookPro13,3 - PCI 
> > >> bridge left with VGA enable set and VGA 16-bit decode cleared, aliasing 
> > >> legacy VGA I/O over the gmux ports
> > >>
> > >> ## Summary
> > >>
> > >> Since Linux 7.1 the backlight on a MacBookPro13,3 (15" 2016, Touch Bar) 
> > >> cannot be controlled at all. `apple_gmux` still probes successfully 
> > >> during boot, but a few hundred milliseconds later the VGA arbiter 
> > >> reprograms `PCI_BRIDGE_CONTROL` of the root port `00:01.0` into a state 
> > >> where the bridge decodes legacy VGA I/O with only 10 address bits. 
> > >> `0x3c0-0x3df` then aliases onto `0x7c0-0x7df`, which is exactly where 
> > >> the gmux "indexed" protocol registers live, so the bridge claims those 
> > >> cycles and forwards them to the dGPU. Every gmux read returns `0xff` and 
> > >> every gmux write is swallowed.
> > >>
> > >> - Last known good: 6.16.10 (Arch `linux` 6.16.10.arch1-1)
> > >> - Also good: 6.12.51 (Arch `linux-lts` 6.12.51-1)
> > >> - Bad: 7.1.5 (Arch `linux` 7.1.5.arch1-2)
> > >>
> > >> ## Hardware
> > >>
> > >> ```
> > >> DMI: Apple Inc. MacBookPro13,3/Mac-A5C67F76ED83108C, BIOS 529.120.1.0.0 
> > >> 03/14/2024
> > >>
> > >> 00:01.0 PCI bridge [0604]: Intel 6th-10th Gen Core Processor PCIe 
> > >> Controller (x16) [8086:1901] (rev 07)
> > >> 00:02.0 VGA compatible controller [0300]: Intel Skylake-H GT2 [HD 
> > >> Graphics 530] [8086:191b] (rev 06)   -> i915
> > >> 01:00.0 VGA compatible controller [0300]: AMD Baffin [Radeon Pro 455] 
> > >> [1002:67ef] (rev c7)             -> amdgpu
> > >>
> > >> gmux: PNP HID APP000B, "Found gmux version 4.0.29 [indexed]"
> > >> ```
> > >>
> > >> ## Symptom
> > >>
> > >> ```
> > >> $ cat /sys/class/backlight/gmux_backlight/actual_brightness
> > >> 16777215
> > >> ```
> > >>
> > >> 16777215 is `0x00ffffff`, which is `GMUX_BRIGHTNESS_MASK` applied to an 
> > >> all-ones I/O read. Writes to `brightness` have no effect. 
> > >> `brightnessctl`, the Touch Bar brightness keys and the desktop 
> > >> brightness slider all fail, because all three go through this single 
> > >> backlight device.
> > >>
> > >> ## Root cause
> > >>
> > >> `PCI_BRIDGE_CONTROL` (offset 0x3e) of `00:01.0`, read after boot has 
> > >> settled:
> > >>
> > >> ```
> > >> 6.12.51-lts   : 0x0012   bit1 SERR, bit4 VGA_16BIT set, bit3 VGA enable 
> > >> clear   -> works
> > >> 6.16.10-arch1 : (not read at register level, but backlight works)
> > >> 7.1.5-arch1-2 : 0x000a   bit1 SERR, bit3 VGA enable set, bit4 VGA_16BIT 
> > >> clear   -> broken
> > >> ```
> > >>
> > >> With `PCI_BRIDGE_CTL_VGA` set and `PCI_BRIDGE_CTL_VGA_16BIT` clear, the 
> > >> bridge ignores address bits [15:10] for legacy VGA I/O, so the ranges 
> > >> alias:
> > >>
> > >> ```
> > >> 0x3b0-0x3bb  ->  0x7b0-0x7bb
> > >> 0x3c0-0x3df  ->  0x7c0-0x7df
> > >> ```
> > >>
> > >> apple-gmux uses the following ports on this machine (PNP resource 
> > >> `0x700-0x7fe`):
> > >>
> > >> ```
> > >> GMUX_PORT_READ         0x7d0
> > >> GMUX_PORT_WRITE        0x7d4
> > >> index magic sequence   0x7cc / 0x7cd / 0x7ce
> > >> ```
> > >>
> > >> All of them fall inside the aliased window, so the bridge steals them.
> > >>
> > >> ## Direct verification via /dev/port on 7.1.5
> > >>
> > >> Before:
> > >>
> > >> ```
> > >> inb(0x7cc) = ff   inb(0x7cd) = ff   inb(0x7ce) = ff
> > >> inb(0x7d0) = ff   inb(0x7d4) = ff
> > >> ```
> > >>
> > >> Set only the 16-bit decode bit, nothing else:
> > >>
> > >> ```
> > >> # setpci -s 00:01.0 BRIDGE_CONTROL=0010:0010
> > >> ```
> > >>
> > >> After (gmux_is_indexed() magic sequence, write 0xaa/0x55/0x00 then read 
> > >> back):
> > >>
> > >> ```
> > >> outb(0x7cc, 0xaa); outb(0x7cd, 0x55); outb(0x7ce, 0x00)
> > >> inb(0x7cc) = aa   inb(0x7cd) = 55        -> gmux responds
> > >> ```
> > >>
> > >> Then:
> > >>
> > >> ```
> > >> # modprobe -r apple_gmux && modprobe apple_gmux
> > >> apple_gmux: Found gmux version 4.0.29 [indexed]
> > >>
> > >> # cat /sys/class/backlight/gmux_backlight/actual_brightness
> > >> 118
> > >> ```
> > >>
> > >> 118 is the value the panel had actually been stuck at the whole time, 
> > >> which confirms that no write had ever reached the hardware. Writing 100 
> > >> / 400 / 700 / 1023 afterwards changes the panel brightness, visually 
> > >> confirmed.
> > >>
> > >> ## Boot timeline
> > >>
> > >> 7.1.5-arch1-2 (broken):
> > >>
> > >> ```
> > >> [  7.947] pci 0000:00:02.0: vgaarb: setting as boot VGA device
> > >> [  7.947] pci 0000:00:02.0: vgaarb: VGA device added: 
> > >> decodes=io+mem,owns=io+mem,locks=none
> > >> [  7.947] pci 0000:01:00.0: vgaarb: setting as boot VGA device 
> > >> (overriding previous)
> > >> [  7.948] pci 0000:01:00.0: vgaarb: VGA device added: 
> > >> decodes=io+mem,owns=none,locks=none
> > >> [  8.005] amdgpu 0000:01:00.0: vgaarb: deactivate vga console
> > >> [  9.494] apple_gmux: Found gmux version 4.0.29 [indexed]          <-- 
> > >> probe still OK
> > >> [ 10.059] i915 0000:00:02.0: vgaarb: VGA decodes changed: 
> > >> olddecodes=io+mem,decodes=io:owns=io+mem
> > >> [ 11.150] i915 0000:00:02.0: vgaarb: VGA decodes changed: 
> > >> olddecodes=io,decodes=none:owns=io+mem
> > >> [ 11.150] amdgpu 0000:01:00.0: vgaarb: VGA decodes changed: 
> > >> olddecodes=io+mem,decodes=none:owns=none
> > >> ```
> > >>
> > >> 6.16.10-arch1-1 (good):
> > >>
> > >> ```
> > >> [  6.785] pci 0000:00:02.0: vgaarb: VGA device added: 
> > >> decodes=io+mem,owns=io+mem,locks=none
> > >> [  6.785] pci 0000:01:00.0: vgaarb: setting as boot VGA device 
> > >> (overriding previous)
> > >> [  6.785] pci 0000:01:00.0: vgaarb: VGA device added: 
> > >> decodes=io+mem,owns=none,locks=none
> > >> [  6.839] amdgpu 0000:01:00.0: vgaarb: deactivate vga console
> > >> [  8.339] apple_gmux: Found gmux version 4.0.29 [indexed]
> > >> [  8.348] i915 0000:00:02.0: vgaarb: VGA decodes changed: 
> > >> olddecodes=io+mem,decodes=none:owns=io+mem
> > >> [  8.349] amdgpu 0000:01:00.0: vgaarb: VGA decodes changed: 
> > >> olddecodes=io+mem,decodes=none:owns=none
> > >> ```
> > >>
> > >> 6.12.51-lts (good):
> > >>
> > >> ```
> > >> [  8.480] apple_gmux: Found gmux version 4.0.29 [indexed]
> > >> [  8.487] i915 0000:00:02.0: vgaarb: VGA decodes changed: 
> > >> olddecodes=io+mem,decodes=none:owns=io+mem
> > >> [  8.489] amdgpu 0000:01:00.0: vgaarb: VGA decodes changed: 
> > >> olddecodes=io+mem,decodes=none:owns=none
> > >> ```
> > >>
> > >> The relevant difference: on 6.12 and 6.16 the i915 legacy decode goes
> > >> `io+mem -> none` in a single step. On 7.1.5 it goes `io+mem -> io` and 
> > >> then, about 1.1 seconds later, `io -> none`. The final arbiter state is 
> > >> `decodes=none` for both devices on all three kernels, yet only on 7.1.5 
> > >> does the bridge end up with `PCI_BRIDGE_CTL_VGA` set and 
> > >> `PCI_BRIDGE_CTL_VGA_16BIT` cleared. The intermediate `decodes=io` state 
> > >> appears to leave the bridge in the 10-bit aliasing configuration and the 
> > >> subsequent transition to `none` does not undo it.
> > >>
> > >> `drivers/platform/x86/apple-gmux.c` only received cosmetic changes 
> > >> during the 7.1 cycle, so this looks like a PCI / vgaarb side change 
> > >> rather than a driver bug.
> > >>
> > >> ## Workaround
> > >>
> > >> ```
> > >> # setpci -s 00:01.0 BRIDGE_CONTROL=0010:0010
> > >> # modprobe -r apple_gmux && modprobe apple_gmux
> > >> ```
> > >>
> > >> Setting the 16-bit decode bit is enough. This machine is KMS only and
> > >> `amdgpu: vgaarb: deactivate vga console` has already happened, so 
> > >> nothing depends on 10-bit legacy VGA I/O aliasing here.
> > >>
> > >> ## Notes
> > >>
> > >> - The breakage happens after `apple_gmux` has already probed, so the 
> > >> driver reports no error. The failure is silent.
> > >> - A machine with a discrete GPU behind `00:01.0` and gmux at 
> > >> `0x700-0x7fe` is the affected shape. MacBookPro13,1 and 13,2 have no 
> > >> dGPU and no bridge in the path, so they are presumably unaffected.
> > >>
> > >> #regzbot introduced: v6.16..v7.1
> > >>

-- 
Ville Syrjälä
Intel

Reply via email to