Since the issue only occurs in around 1 out of 3 times, I’ve added a poor mans detection of the issue to my script during resume, so that when the host controller did not die, it is also not forced to re-initialize everything:
#!/usr/bin/env bash
time_check="$(date --iso-8601=seconds -d '-30 seconds')"
quirks_enabled="$(sed -n -E 's/^QUIRKS_ENABLED\s*=\s*(true|false).*/\1/p' /etc/default/framework-quirks 2>/dev/null)"
[ -n "${quirks_enabled}" ] || quirks_enabled="true"
log() {
printf "[FrameworkDesktop] %s: %s\n" "$1" "$2"
}
if [ "${quirks_enabled}" != "true" ]; then
log "config" "quirks disabled"
exit 0
fi
device_path="$(sed -n -E 's/^DEVICE_PATH\s*=\s*(.+)/\1/p' /etc/default/framework-quirks 2>/dev/null)"
[ -n "${device_path}" ] || device_path="c2:00.4"
suspend() {
# log "suspend" "unbind xHCI start"
log "suspend" "no action"
}
resume() {
sleep 1
xhci_dead="$(journalctl --output cat --no-pager -b -k --since "${time_check}" --grep "${device_path}" -n 5 | grep -F 'xHCI host controller not responding')"
if [ -n "${xhci_dead}" ]; then
log "resume" "rebind xHCI"
echo -n "0000:${device_path}" > /sys/bus/pci/drivers/xhci_hcd/unbind
sleep 2
echo -n "0000:${device_path}" > /sys/bus/pci/drivers/xhci_hcd/bind
else
log "resume" "xHCI rebind not needed"
fi
}
case "$1" in
pre)
suspend "$2"
;;
post)
resume "$2"
;;
esac
These are my recent sleep cycles where you can see that also the duration of sleep does not matter:
2025-12-25T16:02:31+00:00 purgatori systemd-sleep[170008]: [FrameworkDesktop] suspend: no action
2025-12-25T22:56:30+00:00 purgatori systemd-sleep[170091]: [FrameworkDesktop] resume: rebind xHCI
2025-12-25T23:06:08+00:00 purgatori systemd-sleep[171096]: [FrameworkDesktop] suspend: no action
2025-12-25T23:06:38+00:00 purgatori systemd-sleep[171193]: [FrameworkDesktop] resume: rebind xHCI
2025-12-25T23:17:03+00:00 purgatori systemd-sleep[172069]: [FrameworkDesktop] suspend: no action
2025-12-25T23:17:13+00:00 purgatori systemd-sleep[172145]: [FrameworkDesktop] resume: xHCI rebind not needed
2025-12-25T23:19:09+00:00 purgatori systemd-sleep[172500]: [FrameworkDesktop] suspend: no action
2025-12-25T23:19:31+00:00 purgatori systemd-sleep[172553]: [FrameworkDesktop] resume: rebind xHCI
2025-12-25T23:25:27+00:00 purgatori systemd-sleep[173257]: [FrameworkDesktop] suspend: no action
2025-12-25T23:25:42+00:00 purgatori systemd-sleep[173311]: [FrameworkDesktop] resume: xHCI rebind not needed
2025-12-25T23:26:36+00:00 purgatori systemd-sleep[173598]: [FrameworkDesktop] suspend: no action
2025-12-25T23:26:50+00:00 purgatori systemd-sleep[173658]: [FrameworkDesktop] resume: xHCI rebind not needed
2025-12-25T23:27:08+00:00 purgatori systemd-sleep[173867]: [FrameworkDesktop] suspend: no action
2025-12-25T23:27:31+00:00 purgatori systemd-sleep[173921]: [FrameworkDesktop] resume: rebind xHCI
2025-12-25T23:46:03+00:00 purgatori systemd-sleep[175212]: [FrameworkDesktop] suspend: no action
2025-12-26T08:25:25+00:00 purgatori systemd-sleep[175290]: [FrameworkDesktop] resume: xHCI rebind not needed
2025-12-26T09:44:36+00:00 purgatori systemd-sleep[182267]: [FrameworkDesktop] suspend: no action
2025-12-26T20:05:10+00:00 purgatori systemd-sleep[182364]: [FrameworkDesktop] resume: xHCI rebind not needed
2025-12-26T20:23:32+00:00 purgatori systemd-sleep[183781]: [FrameworkDesktop] suspend: no action
2025-12-26T20:40:44+00:00 purgatori systemd-sleep[183892]: [FrameworkDesktop] resume: rebind xHCI
2025-12-27T00:24:15+00:00 purgatori systemd-sleep[206115]: [FrameworkDesktop] suspend: no action
2025-12-27T09:43:07+00:00 purgatori systemd-sleep[206177]: [FrameworkDesktop] resume: xHCI rebind not needed
2025-12-27T11:13:57+00:00 purgatori systemd-sleep[216089]: [FrameworkDesktop] suspend: no action
2025-12-27T11:14:40+00:00 purgatori systemd-sleep[216100]: [FrameworkDesktop] resume: xHCI rebind not needed
2025-12-27T11:17:17+00:00 purgatori systemd-sleep[216584]: [FrameworkDesktop] suspend: no action
2025-12-27T11:17:28+00:00 purgatori systemd-sleep[216640]: [FrameworkDesktop] resume: xHCI rebind not needed
I wish there was a way to actually listen on that kernel event and trigger the quirk on-demand.