Skip to content

Releases

egpu-switch 0.3.4: final release (security fixes, discontinued)

Choose a tag to compare

@TiPSilva TiPSilva released this 05 Oct 11:35

This is the last release of egpu-switch. The project continues as
Yby eGPU, which provides GPU switching
and safe eject without depending on all-ways-egpu, plus a desktop app and
additional controls. Its installer removes egpu-switch from Decky. Update
to 0.3.4 if you still use egpu-switch, then migrate to Yby eGPU.

Security fixes

  • High: a user-writable file was executed as root. The plugin runs as root
    and executed all-ways-egpu from ~/bin (and from any user's
    /home/*/bin) every few seconds. Any program running as a user could
    replace that file and gain root without a password. The plugin, and the
    shutdown hook in extras/, now only run all-ways-egpu when the file and
    every folder above it belong to root and nobody else can write to them.
    If yours is in ~/bin, the panel shows a command to install it
    for the whole system.
  • Medium: root followed a link when saving settings. settings.json
    lives in a folder the user owns; replacing it with a link made root
    overwrite arbitrary system files, and the settings screen could read any
    JSON file. Settings are now read and written without following links,
    through a temporary file, and only the two known options are kept.
  • Low: fixed file names in /tmp. The shutdown hook wrote its errors to
    predictable files in /tmp as root. It no longer uses /tmp.
  • Low: Deep rescan could pick a bridge in another PCI domain. On
    machines with more than one PCI domain it could reset the wrong bridge. It
    now matches the domain too.

These issues were identified during the review for the Yby eGPU release.

Português (Brasil)

Esta é a última versão do egpu-switch. O projeto continua como
Yby eGPU, que mantém a troca de GPU e
a ejeção segura, acrescenta um app do desktop e outros controles, e não
depende do all-ways-egpu. O instalador remove o egpu-switch do Decky durante
a migração. Se você ainda usa o plugin antigo, atualize para a 0.3.4 e
depois migre para o Yby eGPU.

  • Alta: o root executava um arquivo que o usuário podia alterar. O
    plugin roda como root e executava o all-ways-egpu de ~/bin (e do
    /home/*/bin de qualquer usuário) a cada poucos segundos. Qualquer
    programa do usuário podia substituir esse arquivo e obter privilégios de root sem senha.
    Agora o plugin e o gancho de desligamento em extras/ só executam o
    all-ways-egpu quando o arquivo e todas as pastas acima dele pertencem ao root e
    não permitem escrita por outros usuários. Se o seu estiver em ~/bin, o painel mostra
    o comando para instalar em um diretório do sistema.
  • Média: o root seguia um link ao salvar as configurações. O
    settings.json fica numa pasta do usuário; substituí-lo por um link simbólico fazia o
    root sobrescrever qualquer arquivo do sistema, e a tela de configurações
    podia ler qualquer arquivo JSON. Agora as configurações são lidas e
    gravadas sem seguir links simbólicos. A gravação usa um arquivo
    temporário, e apenas as duas opções reconhecidas são mantidas.
  • Baixa: nomes fixos em /tmp. O gancho de desligamento gravava erros
    em arquivos previsíveis no /tmp como root. Não usa mais o /tmp.
  • Baixa: a Busca profunda podia escolher uma ponte de outro domínio PCI.
    A busca agora também confere o domínio PCI.
Español

Esta es la última versión de egpu-switch. El proyecto continúa como
Yby eGPU, que mantiene el cambio de GPU y
la expulsión segura, añade una app de escritorio y otros controles, y no
depende de all-ways-egpu. Su instalador retira egpu-switch de Decky. Si aún
usas el plugin antiguo, actualiza a la 0.3.4 y después migra a Yby eGPU.

  • Alta: root ejecutaba un archivo que el usuario podía cambiar. El
    plugin se ejecuta como root y ejecutaba all-ways-egpu desde ~/bin (y
    desde el /home/*/bin de cualquier usuario) cada pocos segundos.
    Cualquier programa del usuario podía sustituir ese archivo y obtener root
    sin contraseña. Ahora el plugin y el gancho de apagado de extras/ solo
    ejecutan all-ways-egpu cuando el archivo y todas las carpetas por encima
    pertenecen a root y nadie más puede modificarlos. Si el tuyo está en
    ~/bin, el panel muestra el comando para instalarlo en un directorio del
    sistema.
  • Media: root seguía un enlace al guardar los ajustes. settings.json
    está en una carpeta del usuario; sustituirlo por un enlace hacía que root
    sobrescribiera cualquier archivo del sistema, y la pantalla de ajustes
    podía leer cualquier archivo JSON. Ahora los ajustes se leen y escriben sin
    seguir enlaces, mediante un archivo temporal, y solo se conservan las dos
    opciones conocidas.
  • Baja: nombres fijos en /tmp. El gancho de apagado escribía errores
    en archivos predecibles de /tmp como root. Ya no usa /tmp.
  • Baja: la búsqueda profunda podía elegir un puente de otro dominio PCI.
    Ahora comprueba también el dominio.
简体中文

这是 egpu-switch 的最后一个版本。 项目以
Yby eGPU 的形式继续,它保留了
egpu-switch 的 GPU 切换和安全弹出功能,增加了桌面应用等功能,并且不再依赖
all-ways-egpu。安装程序会把
egpu-switch 移出 Decky。正在使用 egpu-switch 的用户请立即更新到 0.3.4,并迁移
到 Yby eGPU。

  • 高危:root 会执行用户可修改的文件。 插件以 root 身份运行,每隔几秒就会从
    ~/bin(以及任意用户的 /home/*/bin)执行 all-ways-egpu。任何以用户身份
    运行的程序都能替换该文件并无需密码获得 root 权限。现在插件以及 extras/ 中的
    关机钩子,只有在该文件及其所有上级目录都属于 root 且他人无法写入时才会执行
    all-ways-egpu。如果你的文件在 ~/bin,面板会显示将其安装到系统范围的命令。
  • 中危:root 保存设置时会跟随链接。 settings.json 位于用户拥有的目录中;
    将其替换为链接会让 root 覆盖系统中的任意文件,设置界面也能读取任意 JSON
    文件。现在读写设置时不跟随链接,通过临时文件写入,并且只保留两个已知选项。
  • 低危:/tmp 中的固定文件名。 关机钩子以 root 身份把错误写入 /tmp 中
    可预测的文件。现在不再使用 /tmp。
  • 低危:深度重新扫描可能选中其他 PCI 域的桥。 现在也会核对域。
Français

Ceci est la dernière version d'egpu-switch. Le projet continue sous le
nom Yby eGPU, qui conserve le basculement
de GPU et l'éjection sûre, ajoute une application de bureau et d'autres
commandes, sans dépendre d'all-ways-egpu. Son installateur retire
egpu-switch de Decky. Si vous utilisez egpu-switch, mettez à jour vers la
0.3.4 maintenant, puis passez à Yby eGPU.

  • Élevée : root exécutait un fichier modifiable par l'utilisateur. Le
    plugin tourne en root et exécutait all-ways-egpu depuis ~/bin (et
    depuis le /home/*/bin de n'importe quel utilisateur) toutes les quelques
    secondes. N'importe quel programme de l'utilisateur pouvait remplacer ce
    fichier et obtenir root sans mot de passe. Le plugin et le hook
    d'extinction dans extras/ n'exécutent désormais all-ways-egpu que si le
    fichier et tous les dossiers au-dessus appartiennent à root et que
    personne d'autre ne peut les modifier. Si le vôtre est dans ~/bin, le
    panneau affiche la commande pour l'installer dans un répertoire système.
  • Moyenne : root suivait un lien en enregistrant les paramètres.
    settings.json se trouve dans un dossier de l'utilisateur ; le remplacer
    par un lien faisait écraser par root n'importe quel fichier du système, et
    l'écran des paramètres pouvait lire n'importe quel fichier JSON. Les
    paramètres sont désormais lus et écrits sans suivre de lien, via un
    fichier temporaire, et seules les deux options connues sont conservées.
  • Faible : noms de fichiers fixes dans /tmp. Le hook d'extinction
    écrivait ses erreurs dans des fichiers prévisibles de /tmp en root. Il
    n'utilise plus /tmp.
  • Faible : la recherche approfondie pouvait choisir un pont d'un autre
    domaine PCI.
    Elle vérifie désormais aussi le domaine.

Download: egpu-switch.zip below (Decky: Settings, Developer, Install Plugin from ZIP File).

eGPU Switch v0.3.3 (stable)

Choose a tag to compare

@TiPSilva TiPSilva released this 28 Jul 22:32

First stable release since v0.1.0, with everything learned from real hardware testing on an AyaNeo (AMD Ryzen 7840U) and an ROG Ally X folded in.

Highlights since v0.1.0

  • Safe eject flow: unloads NVIDIA modules and removes the eGPU from the PCI bus before you disconnect the Thunderbolt cable, instead of only switching boot VGA.
  • Deep Rescan option for cases where a plain PCI rescan does not bring the eGPU back after reconnecting.
  • Automatic HDMI audio rebind after a rescan re-adds the eGPU, gated on actual ELD health instead of a fixed sleep.
  • Connection diagnostics panel: connection type (Thunderbolt or PCIe), link speed and width, Thunderbolt controller and peripheral names, and boot/sleep freeze fix status.
  • Friendly GPU and Thunderbolt controller names parsed from machine-readable lspci and boltctl output, picking the authorized peripheral instead of just the first one listed.
  • Settings persistence for the auto-eject and deep rescan toggles.
  • Documented fix for AMD platforms that freeze on boot or sleep/wake with the eGPU connected (thunderbolt.host_reset=0 kernel argument).
  • Standalone shutdown-eject hook, distributed separately from the plugin, for systems that freeze on shutdown/reboot with the eGPU still attached.
  • Dependency-free self-check test suite covering the pure parsing and decision functions.

Installation

Download egpu-switch.zip below and install via Decky Loader: Settings -> Developer -> Install Plugin from ZIP File. Requires all-ways-egpu to be installed and configured first (see README).

v0.3.3 (dev, unstable)

Pre-release

Choose a tag to compare

@TiPSilva TiPSilva released this 26 Jul 06:42

Unstable dev-branch build, not the recommended release for most users (use v0.1.0 for that). Published specifically so testers on different hardware can try recent fixes and new options.

Changed since v0.3.2

  • Fixed a real audio bug: eject the eGPU, then click Switch to eGPU directly (without a manual Rescan first) could bring video back on the TV with no audio, and restarting the display manager didn't help. The plugin used to decide whether to repair audio based on whether a rescan had been "needed" for the video side, which is the wrong signal: automatic Thunderbolt hotplug can re-add the eGPU (video and audio both) before you press anything, so the video side already looked fine while the audio codec was still broken from that same re-enumeration. It now checks the ALSA card's own ELD state directly and repairs audio whenever it's actually broken, regardless of what triggered the reconnect. Confirmed fixed on hardware, and it's cheap: when audio is already fine, the check is a couple of instant file reads with no added delay.
  • New doc: if the whole system hangs on boot with the eGPU already connected, or on wake from sleep with it active, see the README section on thunderbolt.host_reset=0. Confirmed on hardware (AMD Ryzen 7840U) to fix both outright, not just work around them. Includes the rpm-ostree kargs commands for Bazzite/SteamOS-style atomic systems.

Install

Same as the stable release: Desktop Mode → download the zip below → Game Mode → Decky Developer Mode → Install Plugin from ZIP File.

v0.3.2 (dev, unstable)

Pre-release

Choose a tag to compare

@TiPSilva TiPSilva released this 26 Jul 05:18

Unstable dev-branch build, not the recommended release for most users (use v0.1.0 for that). Published specifically so testers on different hardware can try recent fixes and new options.

Changed since v0.3.1

  • Data loss guard: nothing previously checked for mounted storage before detaching PCI devices. Some NVIDIA boards expose their own USB-C controller as a sibling function, and Deep rescan removes an entire parent bridge, so an enclosure carrying an NVMe or a USB storage controller next to the GPU was one eject away from losing it mid-write. Eject and Deep rescan now refuse upfront (before the display manager is even touched) when mounted storage sits behind the target.
  • Concurrency fix: rescan_pci now takes the same operation lock as every other action. It had grown from a single, safe sysfs write into an operation that can remove a PCI bridge, reauthorize a Thunderbolt tunnel and rebind a driver, while still running unserialized, so closing and reopening the QAM mid-operation could let two mutating calls run at once. Confirmed on hardware after the fix: a real concurrent request was caught and rejected, and a retry right after ran cleanly.
  • Lock rejections are now logged, naming which action was rejected, instead of being silently swallowed.
  • Frontend polling now pauses during an operation, instead of hammering all-ways-egpu status as root every 5 seconds while a multi-minute operation is racing that same state.
  • _unload now restarts the display manager if a Decky-initiated reload lands mid-operation, instead of leaving the session stopped with no code left running to bring it back.
  • Thunderbolt tunnel reauthorization fix: the experimental logic added to work around a reported reconnect issue had an anchored regex that could never match boltctl list's actual output (a silent no-op), and it authorized every unauthorized device it found rather than only ones the user had previously approved. Both fixed.
  • Audio rebind now waits for a real display connection (a DRM connector reporting "connected") instead of a blind timed sleep, so it can only ever land later than the timing already validated on hardware, never earlier.
  • Added tests/selfcheck.py, a dependency-free self-check for the three pieces of logic where being wrong is expensive: the storage guard, the Thunderbolt authorization parser, and the all-ways-egpu status parsing everything else reads from.
  • Packaging: committed the pnpm-lock.yaml the plugin store's build requires, and added the publish metadata block to plugin.json.

Install

Same as the stable release: Desktop Mode → download the zip below → Game Mode → Decky Developer Mode → Install Plugin from ZIP File.

v0.3.1 (dev, unstable)

Pre-release

Choose a tag to compare

@TiPSilva TiPSilva released this 14 Jul 21:58

Unstable dev-branch build, not the recommended release for most users (use v0.1.0 for that). Published specifically so testers on different hardware can try recent fixes and new options.

Changed since v0.3.0

  • Fixed the Deep rescan safety check. Tester logs (Strix Halo / CachyOS Handheld) showed that after an eject, the system can automatically re-add the eGPU as a broken, half-initialized device: it exists on the PCI bus but is not actually usable (no working boot_vga, the same bridge window ... can't assign; no space allocation issue). The previous check saw "device exists" and skipped the deep path exactly when it was needed, which also made Switch to eGPU give up without doing anything. Deep rescan now triggers whenever all-ways-egpu does not report the eGPU as connected and no driver is bound to it, covering both "missing from the bus" and "re-added broken".
  • With that fix, the expected recovery flow after a disconnect (or after waking from sleep with the eGPU previously ejected) is: Rescan for eGPU, then Switch to eGPU, all without leaving Game Mode and without rebooting. Log lines to look for in journalctl -u plugin_loader | grep -i "deep rescan": remove bridge ... ok=True (deep path ran), eGPU connected and functional, skipping bridge removal (nothing to fix), or functions still driver-bound (...), skipping bridge removal (safety stop).

Install

Same as the stable release: Desktop Mode → download the zip below → Game Mode → Decky Developer Mode → Install Plugin from ZIP File.

v0.3.0 (dev, unstable)

Pre-release

Choose a tag to compare

@TiPSilva TiPSilva released this 13 Jul 14:56

Unstable dev-branch build, not the recommended release for most users (use v0.1.0 for that). Published specifically so testers on different hardware can try recent fixes and new options.

Changed since v0.2.0

  • New "Deep rescan (experimental)" toggle under Advanced, off by default. On some platforms the eGPU's PCI bridge (the Thunderbolt/USB4 tunnel's downstream port) gets sized too small at boot for the eGPU to fit once hot-added, so a plain rescan can never bring it back after an eject or disconnect: dmesg shows bridge window ...: can't assign; no space (reported on a ROG Xbox Ally X + Strix Halo running CachyOS Handheld). When enabled, both Rescan for eGPU and the automatic pre-rescan in Switch to eGPU first remove and re-add that parent bridge (discovered dynamically from the configured bus ID, nothing hardcoded) so the kernel recomputes the window. The bridge removal only runs when the eGPU is actually absent from the PCI bus; with the card present it falls back to a plain rescan, since removing the bridge under a live, driver-bound GPU was confirmed on hardware to fail (NVRM: ... non-zero usage count) and wedge the operation.
  • The session now always comes back after a failed eject. If a module unload or PCI remove stalls inside the kernel (seen on hardware when the nvidia driver was already in a bad state from an earlier failure), the operation now times out after 90s, restarts the display manager regardless, and reports a clear "reboot required" error. Previously this could leave the screen black with no recovery.
  • The UI can no longer get permanently stuck on a wedged operation: every action now has a 150s timeout that re-enables the buttons and shows a recovery hint, instead of leaving them disabled forever.
  • Documented a known limitation: after eject + reconnect, the eGPU's HDMI audio can re-probe as non-operational (snd_hda_intel ... please add a quirk to driver_denylist) until a reboot. This is a kernel limitation with re-hotplugged GPU audio; video is unaffected.

Install

Same as the stable release: Desktop Mode → download the zip below → Game Mode → Decky Developer Mode → Install Plugin from ZIP File.

If you're the tester with the "no space" bridge issue: enable Advanced → Deep rescan (experimental) and try the flow that previously failed (eject → disconnect → reconnect → Rescan/Switch to eGPU). journalctl -u plugin_loader will show either Deep rescan: remove bridge ... or ... skipping bridge removal depending on the state, and that log output is exactly what we'd like to see either way.

v0.2.0 (dev, unstable)

Pre-release

Choose a tag to compare

@TiPSilva TiPSilva released this 10 Jul 14:24

Unstable dev-branch build, not the recommended release for most users (use v0.1.0 for that). Published specifically so testers on different hardware can try recent fixes and new options.

Changed since v0.1.0

  • Clearer safety indicator: the "Thunderbolt cable" badge now distinguishes "Not safe (in use)" (eGPU actively driving the display) from "Not safe (not ejected)" (eGPU connected but idle, never activated or already switched away from), each with a short explanation. Previously both cases just showed a bare "Not safe" with no context, which was confusing if you'd never activated the eGPU yet, it's still correct that it's not safe (gamescope keeps GPU device nodes open regardless of which one is active), but the reason wasn't visible before.
  • New collapsed "Advanced" section: an Automatic eject (experimental) toggle, off by default. When enabled, "Switch to iGPU" also ejects the eGPU automatically in the same operation. Off by default because that longer operation can occasionally collide with Decky Loader's own plugin-reload grace period; see the README for details.
  • New collapsed "Connection" section: shows negotiated PCIe link speed/width (works for OCuLink too, not Thunderbolt-specific) plus Thunderbolt generation/tunnel speed/controller name when available via boltctl.
  • Fixed a bug where all-ways-egpu's own internal retry messages could be misread as a failure, silently skipping the display manager restart.
  • Retries modprobe -r on a transient "module in use" failure seen right after the display manager stops.
  • "Switch to eGPU" now always triggers a PCI rescan first, so it can find an eGPU that was just ejected without a separate manual rescan step.

Install

Same as the stable release: Desktop Mode → download the zip below → Game Mode → Decky Developer Mode → Install Plugin from ZIP File.

v0.1.0

v0.1.0 Pre-release
Pre-release

Choose a tag to compare

@TiPSilva TiPSilva released this 09 Jul 21:17

Early, experimental release of eGPU Switch, a Decky Loader plugin that automates all-ways-egpu from Deck Mode.

Marked as a prerelease (0.x per SemVer): validated on one specific hardware/OS combination so far, behavior may still change. See the README's Compatibility section for what is tested vs. expected-but-unconfirmed.

Install

The handheld itself is all you need, no second computer or SSH required:

  1. Switch to Desktop Mode and download egpu-switch.zip below with a browser.
  2. Switch back to Game Mode.
  3. In Decky, enable Developer Mode (Settings, General) if not already on.
  4. Settings, Developer, Install Plugin from ZIP File, Browse, pick the ZIP from Downloads.

See the README for the SSH-based deploy alternative (useful for development) and full usage/safety notes.

Features

  • Switch to eGPU / Switch to iGPU: toggles boot VGA and restarts the display manager. Switching to iGPU also safely ejects the eGPU (unloads NVIDIA kernel modules, detaches it from the PCI bus) in the same operation.
  • Eject eGPU: standalone safe-eject action for the edge case where iGPU is already active but the eGPU was never ejected.
  • Restart Display Manager and Rescan for eGPU: recovery actions.
  • Always-visible Safe/Not safe indicator showing whether it is currently safe to disconnect the Thunderbolt cable.

Why the eject step exists

The proprietary NVIDIA driver does not support surprise PCIe hot-unplug. Disconnecting the Thunderbolt cable while the kernel modules are still loaded can crash the graphical session with a kernel BUG(), confirmed via dmesg during development. Ejecting first (unload modules, detach PCI functions) avoids this.