████ ████ ████ █████ ███ ███ █████ ████ ███ █ █
█ █ █ █ █ █ ██ █ █ █ █ █ █ █ █ █
████ █ █████ ███ ████ █ █ █ █████ █ █████ ████ █ █ █
█ █ █ █ █ ██ █ █ █ █ █ █ █ █ █ █
████ ████ █████ ████ ███ █ █ █████ ████ ███ █ █
PS5 APU · 16 GB GDDR6 · 40 CUs · Ollama via Vulkan
As of 3 November 2026. A build guide for a local LLM box on the ASRock BC-250 (AMD “Cyan Skillfish”, the Sony PS5 APU) with Fedora Server and Ollama over Vulkan. Every number was measured on our own board; the sources are listed at the end. Our use case: a nightly security digest (classifying Wazuh events with an LLM) and a private chat AI.
0. Summary
| What | Result on our board |
|---|---|
| Board | ASRock BC-250, BIOS P3.00 (stock, untouched), 6C/12T, 16 GB GDDR6 |
| Usable GPU memory | 13.5 GiB (512 MB split + 13.3 GB GTT, no BIOS flash) |
| qwen3:14b Q4 (9.3 GB) | 27.8 tok/s with 24 CUs → 36.1 tok/s with 40 CUs |
| Prompt processing (2,426 tokens) | 197 → 253 tok/s |
| Power draw | ~50 W idle / ~120 W load (at the PSU, community measurement) |
| Cost | board €260 used (eBay, DE) + PSU ~€45 + NVMe + fan + printed case |
What the board is not: a replacement for a 24 GB card. 357 GB/s memory bandwidth (community measurement) versus 1,008 GB/s on an RTX 4090. Tokens per second are bandwidth-bound, and 27b dense models do not fit into 13 GiB. For the 14b class and MoE models it is very good.
The route in ten steps
[1] PSU wiring [2] Function test [3] Fedora Server [4] Split + GTT
measure 12.0 V ───▶ live USB, lspci ───▶ NVMe, grow LV ───▶ memcfg 512 MB
BIOS: IOMMU off dnf upgrade ttm.pages_limit
│ │
▼ ▼
[10] Operation [9] Measure [8] 40 CUs [5-7] Governor,
cron/WoL, digest ◀── tok/s, temps, ◀── umr + boot ◀── sensors, Ollama
monitoring stress test service (Vulkan, unit)
1. Hardware
1.1 Board
- ASRock BC-250: AMD APU “Cyan Skillfish” (gfx1013, an RDNA sibling of the PS5), Zen 2 with 6 cores/12 threads (8 present, 2 disabled), 24 of 40 compute units active, 16 GB GDDR6 unified memory, PCI ID 1002:13FE.
- Connectors: 1× 8-pin PCIe power (J1000, 12 V only), M.2 2280 (NVMe PCIe 2.0 ×2 or SATA), 1× RJ45 (Realtek RTL8111, WoL capable), DisplayPort, USB, CPU_FAN1 (4-pin PWM), front-panel header.
- No VCN (no hardware video decoder), so unsuitable for video/streaming.
- BIOS versions in circulation: P2.00, P3.00, P5.00. P3.00 is the community standard and is fine as is; a BIOS flash is NOT required for LLM use (see 4.1).
1.2 Power supply
- Mean Well LRS-350-12 (12 V / 29 A, screw terminals). Its fan is temperature-controlled: on above ~50 °C internally, off below 40 °C (datasheet, RTH3). Under sustained load it runs continuously and is loud; fine in a server room, not on a desk. Fanless alternative: Mean Well UHP-350-12 (different form factor, 220×62×31 mm).
- Wiring of the 8-pin PCIe plug (viewed from the cable side, latch on top): the row with the latch = 4× ground; the other row = 3× +12 V plus 1× ground at the end (the detachable “+2” pins are both ground). Ours: 3 wires on V+, 5 on V−.
8-pin PCIe plug, viewed from the cable side, latch on TOP
┌─────┬─────┬─────┬─────┐
│ GND │ GND │ GND │ GND │ ◀── row with the latch: 4× ground → V−
├─────┼─────┼─────┼─────┤
│ 12V │ 12V │ 12V │ GND │ ◀── lower row: 3× +12 V → V+ , 1× ground → V−
└─────┴─────┴─────┴─────┘
▲ the two detachable "+2" pins are BOTH ground
LRS-350-12 terminal block: L N ⏚ │ V− V− V+ V+
(230 V) │ 5 wires 3 wires
- IEC inlet with switch and fuse, 5×20 mm 4 A slow-blow; the centre, longer pin is earth (check continuity to the chassis), L runs through switch and fuse.
- Commissioning: power up without load first, measure at the plug (ours read 12.11 V, trimmed to 12.00 V with V-ADJ), then verify polarity at the plug against ground, and only then connect the board.
1.3 Cooling
- The stock heatsink stays; on top an ARCTIC P12 Pro PST (high static pressure, as intended by the case designer), 4-pin on CPU_FAN1 so the board controls it and the speed shows up in monitoring. Blowing onto the heatsink, not pulling.
↓↓↓ P12 Pro blows from above ONTO the heatsink ↓↓↓
┌──────────────────────────────────────────┐
│ ░░░░░░░░░░░░░░ 120 mm fan ░░░░░░░░░░░░░░░ │
└──────────────────────────────────────────┘
←── ║║║║║║║║║║║║║║ heatsink fins ║║║║║║║║║║║║║ ──→ exhaust sideways
╔══════════════════════════════════════════╗
║ APU · GDDR6 · BC-250 board ║
╚══════════════════════════════════════════╝
- Readings (40 CUs, qwen3:14b under load):
| makeshift fan (USB, unregulated) | ARCTIC P12 Pro on CPU_FAN1 | |
|---|---|---|
| Idle GPU / CPU | 47–55 °C / 50–55 °C | 45 °C / 51 °C |
| Load GPU / CPU | 71 °C / 83–85 °C | 63 °C / 77 °C |
| GPU clock at the end of the load run | ~1,420 MHz (throttled) | 1,850 MHz |
| Fan | – | 1,145 → 2,013 rpm, board-controlled |
With the controlled fan the throttling is gone; the value inside the closed case is still open.
- Without the governor (section 5.3) the GPU sits at a fixed 1,500 MHz and idles above 60 °C.
1.4 Case
- MakerWorld “AMD BC-250 Industrial Style Compute Case v1.0” (nyacom), 3D printed; designed around the stock heatsink and the LRS-350. Screws: self-tapping for the print, M3/#6-32 for the board, 2× M4×8 for the PSU.
1.5 Storage
- Samsung 980 Pro 1 TB (firmware 5B2QGXA7; the older 3B2QGXA7 had a
drive-killing bug — check with
cat /sys/class/nvme/nvme0/firmware_rev). The slot runs PCIe 2.0 ×2 (~1 GB/s), irrelevant for models. 250 GB is enough (OS 10 GB, a 14b model 9 GB).
1.6 Parts list (Amazon.de numbers checked on 27 Oct 2026)
| Part | Product | ASIN / source |
|---|---|---|
| Board | ASRock BC-250, used (unused leftover stock, stock BIOS) | eBay, German seller, €260 |
| PSU | Mean Well LRS-350-12 (see the lesson in section 8: fanless next time) | B07F2939RR |
| Fan | ARCTIC P12 Pro PST LN, 120 mm, 4-pin PWM | B0FVXTP7P6 |
| Mains inlet | IEC C14 inlet with switch and fuse holder | B0H7X6NK2Z |
| Board power cable | PCIe 8-pin extension (cut at the PSU end and wired to the terminals) | B07RW7FQZN |
| Ferrules | assortment with crimp tool | B09P8B19VB |
| Mains cord | C13, 1.8 m | B07Y1V1HB2 |
| Case screws | self-tapping screw assortment for the 3D print | B0CG673MS3 |
| Board screws | PC screw set #6-32 / M3 | B0DFMG3F8K |
| Lid magnets | neodymium 8×1 mm (for the case lid) | B0BBMY4QNX |
| NVMe | 2280, 250 GB is enough (ours: a Samsung 980 Pro 1 TB from stock) | e.g. B09F4CT8LV |
| Tool | long PH2 screwdriver (PSU terminals sit behind the board) | B000ZEFON4 |
| Optional | CH341A programmer with SOIC8 clip, only for BIOS backup/flash. NOT needed for LLM use (split via memcfg). Caution: black CH341A boards put 5 V on the 3.3 V flash | B0H9SKVSBW |
| From the workshop | 5×20 mm 4 A slow-blow fuse, 2× M4×8 for the PSU, cable ties | – |
Case: the MakerWorld model (section 1.4) on your own or a friend’s 3D printer. No affiliate links.
2. Function test before anything else (return window!)
- Fan on the heatsink (any 12 V fan), CPU_FAN1, monitor on DP, keyboard, live USB (Fedora Workstation Live, a release, not a beta).
- Power on,
Del→ BIOS: read the version (P3.00), under Advanced set IOMMU → Disabled (docs: MUST be disabled), SVM does not matter (leave it off). There is no “Chipset” menu in the stock BIOS; that is normal. F11→ boot from the stick. In the live terminal:
lspci -nn | grep -iE 'vga|display' # expected: Cyan Skillfish [BC-250] [1002:13fe]
free -g # ~7 GiB with the stock 8/8 split
cat /sys/class/drm/card*/device/mem_info_vram_total # 8589934592 with 8/8
journalctl -k | grep -iE 'amdgpu.*(SMU|VRAM|Display Core)'
Expected: SMU is initialized successfully, Display Core … initialized,
8192M of VRAM. Two WARNING … dal_irq_service lines during display init and
one ACPI FADT warning are known and harmless.
3. Installation
- Fedora Server (44 in our case), set a hostname, a user with sudo, root locked, disk “automatic”, remove existing partitions.
- Installer-default trap: the root LV is only 15 GiB, the rest sits unused in the VG:
sudo lvextend -l +100%FREE /dev/fedora_localhost-live/root
sudo xfs_growfs /
- Update and tools:
sudo dnf -y upgrade --refresh
sudo dnf -y install git gcc gcc-c++ make vulkan-tools mesa-vulkan-drivers lm_sensors nvme-cli pciutils zstd umr
vulkaninfo --summarymust showAMD BC-250 (RADV GFX1013)(Mesa ≥ 25.1; ours is 26.2.5). No ROCm: the board runs on Vulkan/RADV.
4. Memory split and GTT (the part that matters)
16 GB GDDR6, ONE memory for CPU and GPU (unified)
Stock (UMA 8192): ├──────── 8 GB VRAM fixed ───────┼──── 8 GB RAM ────┤
GPU sees 8 GB OS gets 7.5 GB
memcfg UMA 512 ├─┬────────────── GTT 13.3 GB ──────────────┬────────┤
+ ttm.pages_limit: │512 MB GPU may allocate up to here │ OS rest │
VRAM (Ollama reports 13.5 GiB) ~1.5 GB
4.1 Split WITHOUT a BIOS flash: bc250_memcfg
The stock BIOS hides the UMA setting (fixed 8/8 or 4/12). People used to flash a
modified BIOS for this; that is obsolete: bc250_memcfg (fanoush) writes the
value into battery-backed CMOS, no flash, rollback = CMOS clear (jumper/battery)
or UMA_SIZE 8192. Source reviewed: 259 lines of C, only I/O ports 0x72/0x73,
offsets 0x90–0xAB.
git clone https://github.com/fanoush/bc250_memcfg && cd bc250_memcfg && make
sudo ./bc250memcfg # read only: UMA_SIZE=8192 on stock
sudo ./bc250memcfg UMA_SIZE 512 # "512 MB" = dynamic, the GPU can use almost everything
sudo reboot
After the reboot: free -h ≈ 14 GiB, mem_info_vram_total = 536870912.
4.2 Raise the GTT cap (otherwise the GPU only sees ~7.5 GB)
sudo grubby --update-kernel=ALL --args="ttm.pages_limit=3407872 ttm.page_pool_size=3407872"
sudo reboot
sudo dmesg | grep "GTT memory" # expected: 13312M of GTT memory ready
(3407872 pages × 4 KiB = 13 GiB.) Community trap: systemd-tmpfiles can
overwrite /sys/module/ttm/..., hence the kernel argument rather than sysfs.
5. OS tuning
5.1 Sensors (nct6683, read only)
echo nct6683 | sudo tee /etc/modules-load.d/99-sensors.conf
echo "options nct6683 force=true" | sudo tee /etc/modprobe.d/options-sensors.conf
sudo modprobe nct6683 && sensors
Gives you the thermistors, the AMD TSI temperature and the fan tachos (fan1–5).
5.2 IOMMU
Disabled in the BIOS (section 2). Proof in the kernel: dmesg | grep -c AMD-Vi = 0.
5.3 GPU governor (mandatory)
Without a governor the GPU is pinned at 1,500 MHz. Recommended (community since
03/2026): cyan-skillfish-governor-smu, which controls clocks through the SMU
firmware, no kernel patch. Source reviewed (Rust, unsafe_code = deny, SMU
mailbox via the host bridge PCI config space, no network).
sudo dnf copr enable filippor/bazzite
sudo dnf install cyan-skillfish-governor-smu
sudo systemctl enable --now cyan-skillfish-governor-smu
cat /sys/class/drm/card1/device/pp_dpm_sclk # idle: 1000Mhz *
Config: /etc/cyan-skillfish-governor-smu/config.toml (voltage curve; only
touch after measuring, see 8).
5.4 Wake-on-LAN
The NIC supports magic packets; enable it in the OS and save in the BIOS (in our case WoL only worked after a BIOS save):
sudo nmcli con modify "<connection name>" 802-3-ethernet.wake-on-lan magic
sudo ethtool enp4s0 | grep Wake-on # expected: g
In our setup the firewall (OPNsense, os-wol plugin) wakes the box every morning by cron; at night it is powered off.
6. Ollama over Vulkan
Not curl | sh but the tarball with checksum:
V=v0.40.13; B=https://github.com/ollama/ollama/releases/download/$V
curl -sSL -o ollama-linux-amd64.tar.zst $B/ollama-linux-amd64.tar.zst
curl -sSL -o sha256sum.txt $B/sha256sum.txt
grep ollama-linux-amd64.tar.zst sha256sum.txt # compare with: sha256sum ollama-linux-amd64.tar.zst
sudo tar --zstd -xf ollama-linux-amd64.tar.zst -C /usr/local
sudo useradd -r -s /sbin/nologin -U -m -d /usr/share/ollama ollama
sudo usermod -a -G render,video ollama
Unit /etc/systemd/system/ollama.service; the three lines that make the
difference are commented:
[Unit]
Description=Ollama Service
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/local/bin/ollama serve
User=ollama
Group=ollama
Restart=always
RestartSec=3
Environment="PATH=/usr/local/bin:/usr/bin:/bin"
Environment="OLLAMA_HOST=0.0.0.0:11434"
# without this the iGPU is discarded ("dropping integrated GPU")
Environment="OLLAMA_IGPU_ENABLE=1"
# prompt cache OFF: on the BC-250, RAM *is* GPU memory (GTT); llama-server's
# 8 GiB default fills the RAM and the runner dies with an OOM kill
Environment="LLAMA_ARG_CACHE_RAM=0"
# flash attention + KV cache q8_0: same generation speed, less memory per context
Environment="OLLAMA_FLASH_ATTENTION=1"
Environment="OLLAMA_KV_CACHE_TYPE=q8_0"
# Vulkan needs CAP_PERFMON to query VRAM (Ollama docs)
AmbientCapabilities=CAP_PERFMON
CapabilityBoundingSet=CAP_PERFMON
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload && sudo systemctl enable --now ollama
sudo firewall-cmd --permanent --add-port=11434/tcp && sudo firewall-cmd --reload
journalctl -u ollama | grep "inference compute"
# expected: library=Vulkan … description="AMD BC-250 (RADV GFX1013)" … total="13.5 GiB"
ollama pull qwen3:14b
ollama run qwen3:14b --verbose "Answer in one sentence: what is a SIEM?"
OOM trap (hit us after 28 digest requests): journalctl -u ollama shows
Failed with result 'oom-kill', dmesg names llama-server. The cause is the
prompt cache (srv load_model: use --cache-ram 0 to disable the prompt cache).
The fix is the LLAMA_ARG_CACHE_RAM=0 line above.
7. Enabling all 40 compute units (no flash, no kernel patch)
The chip has 40 CUs, the driver enables 24. Two routes: a patched amdgpu module
(duggasco, must be rebuilt after every kernel update) or at runtime via umr
(WinnieLV/bc250-cu-live-manager). We use the latter: reversible by reboot, no
kernel surgery.
Shader engines of Cyan Skillfish — 5 WGPs of 2 CUs per row
WGP0 WGP1 WGP2 WGP3 WGP4
SE0.SH0 [ ██ ] [ ██ ] [ ██ ] [ ░░ ] [ ░░ ]
SE0.SH1 [ ██ ] [ ██ ] [ ██ ] [ ░░ ] [ ░░ ] ██ = active from the factory (24 CUs)
SE1.SH0 [ ██ ] [ ██ ] [ ██ ] [ ░░ ] [ ░░ ] ░░ = routed via umr (+16)
SE1.SH1 [ ██ ] [ ██ ] [ ██ ] [ ░░ ] [ ░░ ]
mask per row: 0x07 → 0x1f
sudo dnf install umr # AMD's register tool, shipped by Fedora
sudo install -D -m 0755 bc250-cu-live-manager.sh /opt/bc250-cu-live-manager/bc250-cu-live-manager.sh
cd /opt/bc250-cu-live-manager
sudo ./bc250-cu-live-manager.sh status # CUs active & routed : 24/40
sudo ./bc250-cu-live-manager.sh enable all --yes
sudo ./bc250-cu-live-manager.sh status # 40/40
# persistent across boots (systemd oneshot, config /etc/bc250-cu-live-manager.conf):
sudo ./bc250-cu-live-manager.sh write-service-table --yes
sudo ./bc250-cu-live-manager.sh install-service --yes
# rollback: sudo ./bc250-cu-live-manager.sh uninstall-service --yes (or stock-dispatch)
Notes:
vulkaninfokeeps reportingnum_cu = 24(it reads the driver’s boot map). The proof isstatusshowing 40/40 plus the measurement.- Disabled CUs can be defective: after the unlock run sustained load and
check
dmesgforamdgpu … reset|fault|timeout. Ours: an 80-request replay (550 s, 80 requests) without a single new log entry. - More heat: +3 °C on the CPU under load; with stock cooling the GPU throttles at 2 GHz, the docs recommend 1,500 MHz as the operating point.
Our measurement (qwen3:14b Q4, Ollama, identical prompts):
| 24 CU | 40 CU | |
|---|---|---|
| Generation | 27.8 tok/s | 36.1 tok/s |
| Prompt, 2,426 tokens | 197 tok/s | 253 tok/s |
| 80 digest requests (~1,000 prompt tokens each, one-line answer) | 610 s | 550 s |
7.2 Comparison with a PS5 (same chip, same model)
A colleague runs the same model on a PS5 with llama.cpp (b11327, flash attention, KV cache q8_0, 36 CUs, 2.23 GHz). Re-measured on our board with Qwen3.5-9B Q4_K_M, Ollama, 40 CUs, still with the makeshift fan:
| Qwen3.5-9B Q4_K_M | PS5 (llama.cpp) | BC-250 (Ollama) |
|---|---|---|
| Generation, short prompt | 45–50 tok/s | 50.0 tok/s |
| Generation, ~4.8k-token prompt | ~40–50 tok/s | 47.5 tok/s |
| Prompt processing, clean context | 340–370 tok/s | 507 tok/s |
Tokens per second depend almost entirely on model size (bandwidth): the 14B model runs at 36 tok/s, the 9B at 50. The PS5 is not ahead of the board.
7.1 The two disabled CPU cores (not done)
They can be enabled via an SMU message without a BIOS flash
(rw-r-r-0644/bc250-core-unlock, also available as cpu-unlock in the
cu-live-manager): core mask 0x77 → 0xFF. Volatile until the next cold boot;
permanent only via a BIOS DXE mod (boot-block flash, the highest-risk option).
The cores may be disabled for a reason (several hours of stress-ng, check dmesg
for MCEs). Known side effect: pp_dpm_sclk reports wrong values afterwards. For
GPU inference they add nothing, so we deliberately left them off.
8. What is still open on our side (in this order)
- Thermals inside the closed case (open; with the P12 Pro the throttling is gone).
- Voltage curve in the governor (docs: 1,500 MHz @ ~900 mV), only with measurements.
- Benchmark llama.cpp directly against Ollama (community: up to ~2× on Vulkan).
- Not planned: memory timings/clock (silent errors),
mitigations=off. - Lesson for the next build: a different PSU. The LRS-350 is technically fine, but its fan runs continuously under load and is loud. Next time fanless (Mean Well UHP-350-12) or a semi-passive SFX unit with a native PCIe plug, and design the case around it from the start.
9. Sources
- BC-250 community docs (elektricM): https://elektricm.github.io/amd-bc250-docs/ — VRAM: …/bios/vram · flashing: …/bios/flashing · governor: …/system/governor/ · 40 CU: …/system/40cu-unlock/ · Fedora: …/linux/fedora/
- bc250-documentation (mothenjoyer69): https://github.com/mothenjoyer69/bc250-documentation
- bc250_memcfg (fanoush): https://github.com/fanoush/bc250_memcfg
- cyan-skillfish-governor (filippor, branch smu): https://github.com/filippor/cyan-skillfish-governor/tree/smu — COPR filippor/bazzite
- bc250-cu-live-manager (WinnieLV): https://github.com/WinnieLV/bc250-cu-live-manager
- 40-CU driver patch and measurements (duggasco): https://github.com/duggasco/bc250-40cu-unlock
- CPU core unlock via SMU (rw-r-r-0644): https://github.com/rw-r-r-0644/bc250-core-unlock
- Ollama GPU docs (Vulkan): https://github.com/ollama/ollama/blob/main/docs/gpu.mdx
- Ollama 0.12.11 brought Vulkan (Phoronix): https://www.phoronix.com/news/ollama-0.12.11-Vulkan
- BC-250 cluster experience, RPC over 1 GbE (Tecce): https://ciroluciotecce.it/en/posts/bc250-cluster-inferenza-locale/
- Reference Ollama measurements on the BC-250 (akandr): https://github.com/akandr/bc250
- Mean Well LRS-350 datasheet: https://www.meanwellaustralia.com.au/sites/default/files/2025-05/MEAN%20WELL%20LRS-350%20DATA%20SHEET.pdf
- Case (nyacom, MakerWorld): https://makerworld.com/de/models/2780951
- Video (not evaluated, pointer only): ETA Prime “$100 Steam Machine GPU Unlocked” https://www.youtube.com/watch?v=3GQuZFEjckw