Skip to content

appletbdrm fails to probe Touch Bar at boot with -ETIMEDOUT (-110) on kernel 7.1.2-1-t2-resolute #729

Description

@dkruyt

Summary

On Intel T2 MacBook Pro (T2, Touch Bar model) running the t2-resolute kernel on
Ubuntu 26.04, the appletbdrm driver reliably fails to probe the Touch Bar
display at boot with -ETIMEDOUT (-110), so /dev/dri/card* for the Touch Bar
is never created. This leaves tiny-dfr.service permanently dead (its
dev-tiny_dfr_display.device BindsTo target never appears), so the Touch Bar
never lights up after boot, even though tiny-dfr is correctly installed and
all relevant kernel modules (apple_bce, hid_appletb_kbd, hid_appletb_bl,
appletbdrm) load successfully.

A full unload/reload of the apple_bcehid_appletb_blhid_appletb_kbd
module stack with delays, followed by cycling the Touch Bar USB device's
bConfigurationValue (0 then 2) and restarting tiny-dfr, reliably recovers
the Touch Bar — but this has to be done manually (or via a custom boot-time
script) on every boot, since the initial probe at boot always loses the race.

Environment

  • Hardware: MacBook Pro with Intel T2 chip, Touch Bar model (USB 05ac:8302
    "Touch Bar Display", 05ac:8102 "Touch Bar Backlight")
  • OS: Ubuntu 26.04 LTS (Resolute Raccoon)
  • Kernel: 7.1.2-1-t2-resolute (t2-resolute flavor, #1 SMP PREEMPT_DYNAMIC)
  • tiny-dfr package: 0.3.7-4-resolute
  • Relevant loaded modules: apple_bce, appletbdrm, hid_appletb_kbd,
    hid_appletb_bl, hid_multitouch

Steps to reproduce

  1. Boot the machine normally (cold boot).
  2. Check systemctl status tiny-dfrinactive (dead), with:
    Dependency failed for tiny-dfr.service - Tiny Apple T2 and Silicon Macs Touch Bar daemon.
    Job tiny-dfr.service/start failed with result 'dependency'.
    
  3. Check systemctl status dev-tiny_dfr_display.device → never becomes active.
  4. Check kernel log:
    appletbdrm 7-6:2.1: [drm] *ERROR* Failed to send message (-110)
    appletbdrm 7-6:2.1: [drm] *ERROR* Failed to get display information
    appletbdrm 7-6:2.1: probe with driver appletbdrm failed with error -110
    usbcore: registered new interface driver appletbdrm
    
    This happens consistently ~15-17 seconds after the Touch Bar USB device
    first enumerates, on every cold boot.

Expected behavior

appletbdrm successfully probes the Touch Bar Display USB interface
(7-6:2.1 in this instance) at boot, creating a DRM card device, which makes
/dev/tiny_dfr_display appear and lets tiny-dfr.service start normally —
same as what happens after the manual recovery below.

Actual behavior

appletbdrm_probe() times out (-110/ETIMEDOUT) talking to the device over
the apple_bce/bce-vhci virtual USB layer, and never binds. Once this
happens, even rebinding the driver (rmmod/modprobe appletbdrm,
unbind/bind, or toggling authorized) does not recover it — the
bce-vhci channel itself appears to get wedged and stops responding even to
raw bConfigurationValue sysfs writes (which themselves then start returning
Connection timed out (os error 110)).

The only thing that reliably recovers it (without a full reboot) is unloading
the entire apple_bce module (which also tears down T2 audio, so any
process holding /dev/snd/* open — e.g. PipeWire/WirePlumber — must be
stopped first) and reloading the stack with explicit delays:

systemctl stop tiny-dfr
rmmod hid_appletb_kbd
rmmod hid_appletb_bl
rmmod appletbdrm
rmmod apple_bce

modprobe apple_bce
sleep 4
modprobe hid_appletb_bl
sleep 4
modprobe hid_appletb_kbd
sleep 2

echo 0 > /sys/bus/usb/devices/7-6/bConfigurationValue
sleep 1
echo 2 > /sys/bus/usb/devices/7-6/bConfigurationValue
sleep 3

systemctl restart tiny-dfr

After this sequence, dmesg shows:

[drm] Initialized appletbdrm 1.0.0 for 7-6:2.1 on minor 0
usbcore: registered new interface driver appletbdrm

and the Touch Bar comes up correctly.

Notes / related reports

  • This looks like the same class of regression discussed in
    t2linux/wiki#635 ("TouchBar
    appletbdrm the module reload functionality is broken, not the initial
    loading!"), reported as appearing around kernel 6.12.31+ and confirmed
    present on 7.0.5. Here it also affects initial boot-time loading, not
    just reload after suspend — possibly because by kernel 7.1.2 the race
    window has gotten consistently lost rather than only "sometimes."
  • A community workaround for the equivalent post-suspend/resume version of
    this race is documented in
    basecamp/omarchy#5862,
    using the same reload-with-delays + bConfigurationValue cycle pattern
    used above, via suspend-fix-t2.service/resume-fix-t2.service.
  • This is unrelated to
    basecamp/omarchy#3791,
    which is an Arch/Omarchy packaging issue (services not enabled, missing
    video group membership, Apple-Silicon-only systemd unit dependencies) —
    not a kernel-level probe failure.

Suggested fix direction

The race is most likely in appletbdrm_probe() (or in apple_bce's
bce-vhci virtual host controller setup) — the driver attempts to send its
"get display information" vendor message before the vhci channel for that
USB interface has finished settling after the device's bConfigurationValue
is switched by udev. A built-in retry (with backoff) around the initial
display-info request in appletbdrm_probe() would likely fix this without
requiring a full apple_bce reload.

Current workaround in use

A systemd oneshot unit (touchbar-boot-fix.service) running early at boot,
before display-manager.service and tiny-dfr.service, that performs the
reload-with-delays sequence above automatically. Adds roughly 14s to boot
(the deliberate sleeps, needed to give the bce-vhci channel time to
settle), but reliably brings the Touch Bar up on every cold boot.

Note: the script and unit must use systemctl --no-block for any
tiny-dfr.service start/stop calls. A blocking systemctl restart tiny-dfr from inside this script deadlocks against the unit's own
Before=tiny-dfr.service ordering (tiny-dfr can't start until the script
exits, but a blocking call would have the script wait on tiny-dfr to
start) — it doesn't fail loudly, it just hangs for the full
TimeoutStartSec and gets SIGTERM'd, costing an extra ~60s of boot time
before tiny-dfr is finally (correctly) started by udev anyway. Mentioning
this explicitly in case anyone building on this workaround hits the same
trap.

Install as /usr/local/sbin/touchbar-boot-fix.sh (root, chmod 755):

#!/bin/bash
# Works around a boot-time race where appletbdrm probes the T2 Touch Bar
# (USB 05ac:8302) before the apple-bce vhci channel is ready, failing with
# -ETIMEDOUT and leaving /dev/tiny_dfr_display (and tiny-dfr.service) dead.
# Reloading the whole apple_bce stack with delays clears the wedged channel.
set -u

log() { echo "touchbar-boot-fix: $*"; }

TBDEV=""
for d in /sys/bus/usb/devices/[0-9]*-[0-9]*; do
    [ -f "$d/idProduct" ] || continue
    if [ "$(cat "$d/idProduct" 2>/dev/null)" = "8302" ]; then
        TBDEV="$(basename "$d")"
        break
    fi
done

if [ -z "$TBDEV" ]; then
    log "no 05ac:8302 Touch Bar Display USB device found, nothing to do"
    exit 0
fi

for drv in /sys/bus/usb/devices/"$TBDEV":*/driver; do
    if [ "$(basename "$(readlink -f "$drv")" 2>/dev/null)" = "appletbdrm" ]; then
        log "appletbdrm already bound to $TBDEV, nothing to do"
        exit 0
    fi
done

log "reloading apple_bce/touchbar stack (device $TBDEV)"
# --no-block: this unit is ordered Before=tiny-dfr.service, so a blocking
# `systemctl restart` on tiny-dfr here would deadlock against that ordering
# (tiny-dfr can't start until we exit, but we'd be waiting on it to start).
systemctl --no-block stop tiny-dfr.service 2>/dev/null

log "rmmod hid_appletb_kbd hid_appletb_bl appletbdrm apple_bce"
rmmod hid_appletb_kbd 2>/dev/null
rmmod hid_appletb_bl 2>/dev/null
rmmod appletbdrm 2>/dev/null
sleep 1
timeout 15 rmmod apple_bce 2>/dev/null

log "modprobe apple_bce"
timeout 15 modprobe apple_bce
sleep 4
log "modprobe hid_appletb_bl"
modprobe hid_appletb_bl
sleep 4
log "modprobe hid_appletb_kbd"
modprobe hid_appletb_kbd
sleep 2

log "cycling bConfigurationValue on $TBDEV"
echo 0 > /sys/bus/usb/devices/"$TBDEV"/bConfigurationValue 2>/dev/null
sleep 1
echo 2 > /sys/bus/usb/devices/"$TBDEV"/bConfigurationValue 2>/dev/null
sleep 3

udevadm settle --timeout=10 2>/dev/null
# Non-blocking safety net: the udev rule's SYSTEMD_WANTS on the touchpad
# input device normally re-triggers tiny-dfr.service on its own once the
# device re-enumerates above; this is just a backstop.
systemctl --no-block restart tiny-dfr.service 2>/dev/null

log "done"
exit 0

Install as /etc/systemd/system/touchbar-boot-fix.service:

[Unit]
Description=Work around appletbdrm Touch Bar probe race at boot
DefaultDependencies=no
After=systemd-udev-settle.service local-fs.target
Before=display-manager.service tiny-dfr.service
Wants=systemd-udev-settle.service

[Service]
Type=oneshot
RemainAfterExit=yes
TimeoutStartSec=60
ExecStart=/usr/local/sbin/touchbar-boot-fix.sh

[Install]
WantedBy=sysinit.target

Enable with:

sudo chmod 755 /usr/local/sbin/touchbar-boot-fix.sh
sudo systemctl daemon-reload
sudo systemctl enable touchbar-boot-fix.service

The idProduct=8302 lookup makes the script independent of the USB bus
path (7-6 here, but this varies by machine/boot enumeration order), so it
should work unmodified on other T2 Touch Bar Macs.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions