jjenksNC
9/4/2019 - 12:15 AM

Script to reset the XHCI of a Thunderbolt connection in case the kernel stops it

Script to reset the XHCI of a Thunderbolt connection in case the kernel stops it

#!/bin/bash
# As described in https://bugs.launchpad.net/bugs/1766076
### Installation Instructions:
# 1. Install file into `/usr/local/bin/reset-tb`
#
# 2. Optional: allow password less sudo by creating a file `/etc/sudoers.d/allow-reset-tb` with the following content:
# ----8<-----
# <your username> ALL = NOPASSWD: /usr/local/bin/reset-tb
# ----8<-----
# 
# 3. Optional: allow easy access from the menu by creating a file `$HOME/.local/share/applications/Reset Thunderbolt.desktop`
# with the following content:
# ----8<-----
# [Desktop Entry]
# Exec=bash -c 'sudo -S /usr/local/bin/reset-tb'
# Icon=amarok_playlist_refresh
# Name=Reset Thunderbolt
# NoDisplay=false
# StartupNotify=false
# ----8<-----
#
# 4. Optional: run a service to automatically trigger the reset and send you an email when "unknown event type 15" error
# is detected, by setting your email in this file below, then creating a file `/etc/systemd/system/auto-reset-tb.service`
# with the following content:
# ----8<-----
# [Unit]
# Description=Automatically reset XHCI USB bus when detecting a Thunderbolt dock error
# [Service]
# ExecStart=/usr/local/bin/reset-tb -l
# [Install]
# WantedBy=multi-user.target
# ----8<-----
# Then run:
# ```
# sudo systemctl daemon-reload
# sudo systemctl enable auto-reset-tb
# sudo systemctl start auto-reset-tb
# ```

EMAIL=oded@geek.co.il
SUBJECT="Detected Thunderbolt error in your system"
MESSAGE="
Check the logs, please.
"

function do_reset() {
        tbtid="$(ls /sys/bus/pci/drivers/xhci_hcd/ | grep '[0-9]')"
        echo "Resetting thunderbolt bus">&2
        for id in $tbtid; do
                echo -n $id > /sys/bus/pci/drivers/xhci_hcd/unbind
        done
        sleep 1
        for id in $tbtid; do
                echo -n $id > /sys/bus/pci/drivers/xhci_hcd/bind
        done
        echo "Done resetting thunderbolt bus" >&2
}

function listen_for_reset() {
        dmesg -w | while read line; do
                [[ "$line" =~ "ERROR unknown event type 15" ]] || continue
                (
                        sleep 15 # let the busses settle
                        do_reset
                )&
                mail -s "$SUBJECT" $EMAIL <<< "$MESSAGE"
        done
}

[ "$1" == "-l" ] && listen_for_reset || do_reset