# [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

Reply via email to