Intel Arc Pro B70 on Linux over Thunderbolt 5: full 32 GB BAR, fan control, VRAM overclock and a VRAM clock readout
I put an Intel Arc Pro B70 in a Thunderbolt 5 eGPU dock next to my MS-02 Ultra and wanted it fully usable under Debian, with Secure Boot on. That took more than plugging it in. The short version: the card now gets its full 32 GB BAR, runs a custom fan curve, has its VRAM at 21000 Mbps instead of 19000, and shows its VRAM clock in btop. That gave +3.2% decode on a local LLM over a true stock run, and the card runs 15 C cooler at the same speed. At 22000 Mbps the GPU died and took the whole host with it. Everything I built is on GitHub: synman/arc-pro-b70-linux.
This writes undocumented GPU firmware settings. Read the caveats before you copy any of it.

Full system specs
| Part | Detail |
|---|---|
| GPU | ASRock Intel Arc Pro B70 Creator, 32 GB GDDR6, Battlemage BMG-G31, PCI 8086:e223, subsystem 1849:6025 |
| Dock | Sparkle Studio-G Ultra 850, Thunderbolt 5, its own 850 W PSU |
| Host | Minisforum MS-02 Ultra, Intel Core Ultra 9 285HX, JHL9580 Thunderbolt 5 host |
| Other GPUs | Arrow Lake iGPU, NVIDIA RTX PRO 4000 Blackwell SFF |
| OS | Debian 13, kernel 7.2.11 from trixie-backports, Secure Boot ON with kernel lockdown |
| Driver | In-kernel xe, patched (see below), signed with my own Machine Owner Key |
| Userspace | Mesa 26 (Vulkan), llama.cpp Vulkan |
| Test model | Qwen3.6-35B-A3B Q5_K_M, 262K context, q8_0 KV cache, batch and ubatch 2048 |
Getting it working at all
Small BAR. Out of the box the card got a 256 MiB BAR. Resizing it failed with -ENOSPC. The dock’s bridges were sized at hotplug, and its empty downstream ports held most of the window. Removing those ports didn’t help either, because kernel 7.2 never moves a bridge’s own BAR. The fix was to let the firmware build the Thunderbolt tunnel at boot: thunderbolt.host_reset=0 on the kernel command line, with the dock powered before the host starts. The card then got the full 32 GB BAR. The cost is that the Linux Thunderbolt driver no longer manages the host router, so hot-unplug is off the table until the next reboot.
Vulkan. Debian trixie’s Mesa 25.0 reports no Vulkan device on the B70. Mesa 26 drives it, so my containers use a newer userland, and the host now runs Mesa 26.1 from backports.
Compute. Intel’s compute runtime (OpenCL and Level Zero) refuses a discrete card without a large BAR. That is why it only appeared after the BAR fix. Vulkan through Mesa doesn’t care.
Device names move. The BAR fix renumbered the DRM nodes. Pin containers by /dev/dri/by-path/pci-…-render, never by renderD128.
What I did, in order
- Built a patched
xe. Intel’s fan-control series 168027 adds manual fan curves. exzile’sxe_gt_ocadds the voltage-frequency curve, VRAM speed and a temperature limit. I built both into the Debian kernel’s ownxesource in a throwaway container. Stockxehas neither. - Signed it and loaded it from my own path. It’s signed with my enrolled MOK, so lockdown accepts it. It loads with
insmodfrom outside/lib/modules, so every reboot starts on stockxeand any failure leaves a working card. The swap stops everything that holds the card, unbinds it, swaps the module and checks it. Anything wrong rolls back to stock. - Fan curve. The card’s own table let it run warm. A 10-point curve built from my load logs keeps it near 47 C at idle and about 80% fan at a 270 W memory test.
- Voltage-frequency curve. My card accepts VF writes. At −25 mV it ran the same speed at 168 W instead of 178 W, with VRAM 8 C cooler. I didn’t keep it.
- VRAM speed. I stepped from Intel’s stock 19000 Mbps in 500 Mbps steps, with every GPU user stopped. Each step got memtest_vulkan, a fixed-prompt coherence check and the LLM bench.
- Two patches of my own. One logs every PCODE mailbox failure with its raw status. The stock code instead pretended an unknown VRAM speed was 19000. The other caches the VRAM rate and exposes it as a hwmon device named
xe_oc:freq1_inputin Hz, labelledmclk, the same convention amdgpu uses. Monitors can read it for free. The same patch caps the speed at 21500, so the driver refuses the value that killed my card. - btop readout. My btop fork reads
xe_oc, so the console shows the B70’s VRAM clock: 2625 MHz at 21000 Mbps. - Persist it. A boot unit loads the patched driver and applies the settings. It falls back to stock on any failure, and it has come up clean on two reboots.
- Kernel 7.2.11. I rebuilt the driver for the new kernel before rebooting into it, so the first boot came up patched. Debian’s backports carry several kernel source versions at once, so the build now takes the exact one the kernel names.
Benchmark
Each run is six completions against the live llama.cpp server: three with about 2K prompt tokens and three with about 7.4K, 256 generated tokens each, temperature 0, no prompt cache. I report the median. A 1 Hz sampler recorded clocks, power and temperatures. Nothing throttled in any run.
VRAM speed, one boot, one driver, only the memory changed

| VRAM (Mbps) | memtest_vulkan | Decode ~2K (tok/s) | Decode ~7.4K (tok/s) | Prefill ~2K (tok/s) | Busy power |
|---|---|---|---|---|---|
| 19000 (stock) | pass | 73.12 | 61.43 | 1696 | 180 W |
| 19500 | pass | 73.76 | 62.05 | 1708 | 182 W |
| 20500 | pass | 74.51 | 62.69 | 1712 | 184 W |
| 21000 | pass | 74.74 | 62.79 | 1708 | 185 W |
| 21500 | pass | 75.15 | 63.19 | 1720 | 186 W |
| 22000 | GPU died, host locked | — | — | — | — |
Stock against my kept setup
The stock rows are three runs after a reboot with everything removed: stock xe, firmware fan table, default VRAM speed.
| Setup | Decode ~2K | Decode ~7.4K | Prefill ~2K | GPU package | VRAM |
|---|---|---|---|---|---|
| Stock (median of 3, within 0.1 tok/s of each other) | 73.15 | 61.75 | 1702 | 70 C | 66-70 C |
| Kept: 21000 Mbps + fan curve + clock pin | 75.51 | 63.36 | 1718 | 55 C | 52 C |
That is +3.2% decode at 2K, +2.6% at 7.4K and +0.9% prefill. All of it came from the memory speed. Pinning the clock at 2800 MHz, keeping VRAM out of D3cold and forcing runtime PM on changed nothing measurable.
Speech-to-text on the B70
I used the B70 to finish a speech-to-text backlog: whisper.cpp with ggml-medium.en on Vulkan, transcribing a 600 s clip with 4 threads.
| Device | Wall time | Speed vs realtime |
|---|---|---|
| Arrow Lake iGPU, 1 worker | 181.6 s | 3.3x |
| B70, 1 worker | 31 s | 19x |
| B70, 2 workers | 51 s | 23.5x |
| B70, 3 workers | 68 s | 26.5x |
| B70, 4 workers | 87 s | 27.6x |
One B70 worker is about 6x the iGPU, and three workers nearly saturate the card. The real run cleared its last 16 shards, about 2.6 GB of audio, in 5 h 13 min.
What I learned
- This MoE model is only partly bandwidth-bound. +13% memory speed bought +2.8% decode. The card’s clock, power and fan settings bought nothing. Memory speed is the only knob that moved it.
- The failure at 22000 was violent. The commit succeeded. About 31 s later, at the first memory test, the GPU’s forcewake stopped answering. Then the card and its dock bridges fell off the PCIe bus and the host locked up hard. The chips are rated for 20 Gbps, Intel ships them at 19, and my card held 21.5. The driver now refuses anything above 21500.
- Change VRAM speed only with the GPU idle. One write under LLM load wedged the card. Every write with the users stopped was clean.
- Never reload the driver on a wedged card. Tearing down the wedged device once took the whole host down. Reboot instead. My load script now refuses to run after a wedge.
- A second hwmon device trips scripts. With my patch the card has two,
xeandxe_oc. Anything that grabs the firsthwmon*directory can land on the wrong one. Pick it by name. - A kernel update silently drops hand-built drivers. It caught me twice in one jump: the patched B70 driver and the patched NVIDIA modules behind my RTX power mod both stayed on the old kernel. The NVIDIA one quietly fell back to stock 70 W. Rebuild both before you reboot.
- Take a true stock baseline. My first morning’s numbers were about 9% low for a reason I never found. A clean stock run after a reboot showed it, and every gain above is measured against that run.
The caveats (please read)
- Fan, VF and VRAM control use PCODE mailbox commands Intel doesn’t document. A blind scan of PCODE commands has wedged other Arc cards. Never enumerate them.
- These are one card’s results, mostly one run per step. Your board may differ, so measure your own.
- 21000 Mbps is past the memory’s 20 Gbps rating. I check output coherence after every change, but silent memory errors are possible.
- Intel doesn’t support Arc in eGPU setups. The 32 GB BAR depends on the dock and the firmware building the tunnel at boot.
- If you try this, you own the risk. Keep a hard-reset path handy, and keep the stock driver one reboot away.
Sources and credit
- exzile’s toolkit, which packages the fan control and adds
xe_gt_oc: https://github.com/exzile/intel-arc-pro-fan-control - Intel’s fan-control series 168027 by Karthik Poosa: https://patchwork.freedesktop.org/series/168027/
- The series’ CachyOS rebase by PerkyZZ999: https://github.com/PerkyZZ999/XeDriver_FanPatch
- My patches, build, scripts and full findings: https://github.com/synman/arc-pro-b70-linux
- My btop fork with the B70 readout, branch
arrowlake: https://github.com/synman/btop - The MS-02 Ultra Thunderbolt eGPU issue, whose comments include a B70 getting the full 32 GB BAR: https://github.com/minisforum-docs/MS-02-Ultra/issues/32
- memtest_vulkan: https://github.com/GpuZelenograd/memtest_vulkan
- llama.cpp: https://github.com/ggml-org/llama.cpp
Questions welcome.