!!!warning ""
    This was my try on implementing ROCm to the BC250. It is discontinued as of March 22th 2026 (Latest Commit).
    This Repository is a sanitized re-upload of my findings based off of [Dani's research](./_TestScripts/Danis%20ROCm%20Kernel%20Patch%20Research/) including the Patches that are now applyed to [project-ariel](https://github.com/cachenetics/project-ariel). This Repository is now a public Archive under the GPL-2.0 License and can be used as such.


# ROCm on AsRock BC-250 — Complete Installation Guide

**Hardware**: AsRock BC-250 (AMD Cyan Skillfish / gfx1013)  

**Target ROCm**: 7.2.0 | **OS**: CachyOS (Arch-based) | **Shell**: fish / bash

**Bootloader**: Limine | **Compiler**: Clang (LLVM)

**Author**: [Fabian](https://git.sudx.de/Fabian) | **Last Updated**: 2026-03-17

**Honorable Mention**: [Dani](https://git.sudx.de/Dani) (Creator of first KIQ Timeout fix)


# This is not working Standalone.

---

## Table of Contents

1. [Hardware Overview](#1-hardware-overview)
2. [Prerequisites](#2-prerequisites)
3. [Step 1 — Install ROCm Packages](#3-step-1--install-rocm-packages)
4. [Step 2 — User Group Configuration](#4-step-2--user-group-configuration)
5. [Step 3 — Environment Variables](#5-step-3--environment-variables)
6. [Step 4 — Kernel Boot Parameters](#6-step-4--kernel-boot-parameters)
7. [Step 5 — Modprobe Configuration](#7-step-5--modprobe-configuration)
8. [Step 6 — Build Patched amdgpu Kernel Module](#8-step-6--build-patched-amdgpu-kernel-module)
9. [Step 7 — Install Module & Reboot](#9-step-7--install-module--reboot)
10. [Step 8 — Post-Reboot Verification](#10-step-8--post-reboot-verification)
11. [Step 9 — HIP Compute Tests](#11-step-9--hip-compute-tests)
12. [Cyan Skillfish Governor (GPU Clock Management)](#12-cyan-skillfish-governor-gpu-clock-management)
13. [GPU Watchdog (Safety Monitor)](#13-gpu-watchdog-safety-monitor)
14. [HIP Programming Guidelines for BC-250](#14-hip-programming-guidelines-for-bc-250)
15. [Kernel Module Rebuild After Updates](#15-kernel-module-rebuild-after-updates)
16. [Technical Reference — Why This GPU Needs Patches](#16-technical-reference--why-this-gpu-needs-patches)
17. [Troubleshooting](#17-troubleshooting)
18. [File Inventory](#18-file-inventory)

---

## 1. Hardware Overview

```
GPU:              AMD BC-250 (Cyan Skillfish)
Device ID:        0x13FE (Vendor: 0x1002 AMD)
Architecture:     RDNA 1.5 (GFX 10.1.3 / gfx1013)
ROCm Target:      gfx10-1-generic (auto-mapped), runs as gfx1010 via override
Compute Units:    24 (reported by some tools as 12 due to SIMD config)
Wavefront Size:   32 (RDNA-style)
Memory:           ~14.75 GB shared system GDDR6 (NO dedicated VRAM)
Memory Type:      APU-style unified memory (system RAM shared with CPU)
PCIe:             Internal SoC fabric (Completion Timeout: Not Supported)
```

### Why This GPU Is Special

The BC-250 is a **cryptocurrency mining board repurposed as a compute accelerator**. It behaves
like an APU — there is **no dedicated VRAM**; all GPU memory operations use system RAM. This has
critical implications:

| Behavior | Explanation |
|----------|-------------|
| **No standard hipMalloc** | Standard device memory allocation targets non-existent VRAM |
| **hipMallocManaged required** | Unified memory works on shared RAM |
| **hipHostMalloc works** | Pinned host memory is safe for APU |
| **GPU reset = system crash** | Resetting the GPU corrupts shared system RAM |
| **SDMA engine unreliable** | Must disable via `HSA_ENABLE_SDMA=0` |
| **GFXOFF is fatal** | GPU enters power-save and can't wake — CPU hangs on MMIO read |
| **KIQ ring is broken** | KIQ commands cause fence timeouts → system hang |

---

## 2. Prerequisites

- CachyOS (or Arch-based distro) with a working internet connection
- `sudo` access for the installation user
- `paru` or another AUR helper (for the GPU governor)
- Sufficient disk space (~2 GB for kernel source + build artifacts)

Install base build dependencies:

```fish
sudo pacman -S --needed --noconfirm base-devel bc python
```

---

## 3. Step 1 — Install ROCm Packages

Install all 16 required ROCm 7.2.0 packages:

```fish
sudo pacman -S --needed --noconfirm \
  rocm-core hsa-rocr rocminfo rocm-smi-lib rocm-device-libs \
  rocm-llvm comgr hip-runtime-amd rocm-hip-runtime \
  rocm-opencl-runtime rocblas hipblas rocrand rocm-cmake \
  rocm-language-runtime hipblas-common
```

You can also run the provided script:
```fish
bash scripts/01_install_rocm_packages.sh
```

### Package List

| Package | Description |
|---------|-------------|
| `rocm-core` | ROCm core (version files) |
| `hsa-rocr` | HSA Runtime API |
| `rocminfo` | ROCm system info tool |
| `rocm-smi-lib` | ROCm SMI library |
| `rocm-device-libs` | ROCm device libraries |
| `rocm-llvm` | ROCm LLVM/Clang compiler (~4.5 GB) |
| `comgr` | AMDGPU Code Object Manager |
| `hip-runtime-amd` | HIP Runtime (AMD backend) |
| `rocm-hip-runtime` | Meta-package for HIP runtime |
| `rocm-opencl-runtime` | ROCm OpenCL runtime |
| `rocblas` | ROCm BLAS library |
| `hipblas` | ROCm BLAS marshalling library |
| `hipblas-common` | hipBLAS common files |
| `rocrand` | ROCm random number generator |
| `rocm-cmake` | ROCm CMake modules |
| `rocm-language-runtime` | ROCm language runtime meta |

---

## 4. Step 2 — User Group Configuration

Add your user to the `render` and `video` groups:

```fish
sudo usermod -aG render,video $USER
```

**You must log out and back in** (or reboot) for group changes to take effect.

Verify:
```fish
groups $USER
# Should include: render video
```

---

## 5. Step 3 — Environment Variables

The BC-250 requires specific environment variables for ROCm to function. With the v3 kernel
patches (Step 6), only a **minimal set** is needed.

### For fish shell

Add to `~/.config/fish/config.fish`:

```fish
# === ROCm Configuration for AMD BC-250 ===
set -gx PATH /opt/rocm/bin $PATH
set -gx LD_LIBRARY_PATH /opt/rocm/lib $LD_LIBRARY_PATH
set -gx ROCM_PATH /opt/rocm
set -gx HSA_OVERRIDE_GFX_VERSION 10.1.0
set -gx HIP_VISIBLE_DEVICES 0
set -gx HSA_ENABLE_SDMA 0
set -gx HSA_TOOLS_LIB ""
set -gx HSA_TOOLS_REPORT_LOAD_FAILURE 0
```

### For bash shell

Add to `~/.bashrc`:

```bash
# === ROCm Configuration for AMD BC-250 ===
export PATH="/opt/rocm/bin:$PATH"
export LD_LIBRARY_PATH="/opt/rocm/lib:$LD_LIBRARY_PATH"
export ROCM_PATH=/opt/rocm
export HSA_OVERRIDE_GFX_VERSION=10.1.0
export HIP_VISIBLE_DEVICES=0
export HSA_ENABLE_SDMA=0
export HSA_TOOLS_LIB=""
export HSA_TOOLS_REPORT_LOAD_FAILURE=0
```

You can also run the provided script:
```fish
bash scripts/02_configure_environment.sh
```

### Variable Reference

| Variable | Value | Why Required |
|----------|-------|--------------|
| `HSA_OVERRIDE_GFX_VERSION` | `10.1.0` | Maps gfx1013 → gfx1010 (closest supported target) |
| `HIP_VISIBLE_DEVICES` | `0` | Explicit GPU device selection |
| `HSA_ENABLE_SDMA` | `0` | SDMA engine is broken on gfx1013, use shader DMA |
| `HSA_TOOLS_LIB` | `""` | Prevent profiling tools from destabilizing GPU |
| `HSA_TOOLS_REPORT_LOAD_FAILURE` | `0` | Suppress tool load warnings |

### Variables You Must NOT Set

These were pre-v3 workarounds that **severely hurt performance**:

| Variable | Why It's Harmful |
|----------|------------------|
| `GPU_MAX_HW_QUEUES=1` | Serializes all GPU ops to 1 queue — severe slowdown |
| `HIP_LAUNCH_BLOCKING=1` | Forces synchronous kernel launches — prevents pipelining |
| `HSA_DISABLE_FRAGMENT_ALLOCATOR=1` | Not needed with v3 patches |

---

## 6. Step 4 — Kernel Boot Parameters

### Limine Bootloader

Edit `/etc/default/limine` and add these parameters to the `KERNEL_CMDLINE`:

```
amdgpu.gpu_recovery=1 amdgpu.noretry=0 amdgpu.dc=0 amdgpu.lockup_timeout=120000 amdgpu.ppfeaturemask=0xfff73ef7
```

Apply changes:
```fish
sudo limine-update
```

### GRUB Bootloader (if applicable)

Edit `/etc/default/grub` and add to `GRUB_CMDLINE_LINUX_DEFAULT`:

```
amdgpu.gpu_recovery=1 amdgpu.noretry=0 amdgpu.dc=0 amdgpu.lockup_timeout=120000 amdgpu.ppfeaturemask=0xfff73ef7
```

Apply changes:
```bash
sudo grub-mkconfig -o /boot/grub/grub.cfg
```

### Parameter Reference

| Parameter | Value | Purpose |
|-----------|-------|---------|
| `amdgpu.gpu_recovery=1` | Enabled | **CRITICAL**: Auto-recover from GPU hangs |
| `amdgpu.noretry=0` | Retry enabled | Allow page fault retry (required for shared memory) |
| `amdgpu.dc=0` | Display disabled | Disable display controller (headless — prevents IRQ errors) |
| `amdgpu.lockup_timeout=120000` | 120 seconds | Time before declaring GPU hung (allows heavy compute) |
| `amdgpu.ppfeaturemask=0xfff73ef7` | Custom mask | Disable GFXOFF + DeepSleep + ULV (see below) |

### ppfeaturemask Calculation

```
Default value:  0xfff7bfff
BC-250 value:   0xfff73ef7

Bits disabled:
  Bit 15 (0x8000) — PP_GFXOFF_MASK:          GPU enters unrecoverable power-save
  Bit  8 (0x0100) — PP_ULV_MASK:             Ultra-low voltage may destabilize GPU
  Bit  3 (0x0008) — PP_SCLK_DEEP_SLEEP_MASK: Deep clock sleep prevents GPU wake
```

---

## 7. Step 5 — Modprobe Configuration

Copy the provided config file:
```fish
sudo cp config/amdgpu.conf /etc/modprobe.d/amdgpu.conf
```

Or create manually — file `/etc/modprobe.d/amdgpu.conf`:

```
# AMD BC-250 (Cyan Skillfish / gfx1013) — ROCm Stability Parameters
# noretry=0              — Allow page fault retry (critical for shared memory / APU)
# gpu_recovery=1         — Enable GPU recovery on timeout
# sched_hw_submission=2  — Limit concurrent HW submissions (prevent queue overload)
# ppfeaturemask=0xfff73ef7 — Disable GFXOFF (bit 15), DeepSleep (bit 3), ULV (bit 8)
options amdgpu noretry=0 gpu_recovery=1 sched_hw_submission=2 ppfeaturemask=0xfff73ef7
```

---

## 8. Step 6 — Build Patched amdgpu Kernel Module

This is the most critical step. The BC-250 has a hardware/firmware bug where the KIQ (Kernel
Interface Queue) ring causes fatal GPU hangs. The v3 patch applies 8 surgical modifications
across 3 kernel source files to bypass KIQ and add dead-GPU detection.

### Why a Custom Module is Needed

The stock amdgpu driver routes TLB (Translation Lookaside Buffer) invalidation commands through
the KIQ ring. On the BC-250, this causes:

1. **KIQ fence timeouts** → GPU becomes unresponsive
2. **GFXOFF power-save** → GPU can't wake, CPU hangs on MMIO read (no PCIe timeout)
3. **System freeze** → No recovery possible, hard power-off required

The v3 patch has three protection layers:
- **Layer 1**: Disable GFXOFF for Cyan Skillfish (`gfx_v10_0.c`)
- **Layer 2**: KIQ bypass + dead-GPU detection (`gmc_v10_0.c`, `amdgpu_gmc.c`)
- **Layer 3**: Boot parameters disable GFXOFF/DeepSleep/ULV (Step 4)

### CRITICAL: Use CachyOS Kernel Source (Not Vanilla!)

**You MUST build from the CachyOS kernel source**, not vanilla kernel.org source. CachyOS patches
their kernel with struct layout changes that are incompatible with vanilla source headers. Building
from vanilla kernel source will produce a module that causes a **NULL pointer dereference** at boot
in `drm_vma_offset_add` during `gmc_v10_0_sw_init`.

### Build Process

#### Option A: Automated (Recommended)

The provided build script handles everything:

```fish
# Edit scripts/04_build_patched_module.sh and verify your kernel version first!
bash scripts/04_build_patched_module.sh
```

#### Option B: Manual Step-by-Step

##### 1. Identify Your Kernel Version

```fish
uname -r
# Example output: 6.19.6-2-cachyos
```

Note both the **kernel version** (e.g., `6.19.6`) and the **full string** (e.g., `6.19.6-2-cachyos`).

##### 2. Find the Matching CachyOS Source

Go to https://github.com/CachyOS/linux/releases and find the release matching your kernel.

For example, kernel `6.19.6-2-cachyos` → release `cachyos-6.19.6-1` or similar.

```fish
mkdir -p ~/kernel-build
cd ~/kernel-build

# Download (replace URL with your matching version)
curl -L -o cachyos-source.tar.gz \
  "https://github.com/CachyOS/linux/archive/refs/tags/YOUR_TAG.tar.gz"

# Extract
tar xf cachyos-source.tar.gz
cd linux-*  # or whatever the extracted directory is named
```

##### 3. Prepare Build Environment

```fish
set KVER (uname -r)

# Copy the running kernel's config and build files
cp /usr/lib/modules/$KVER/build/.config .
cp /usr/lib/modules/$KVER/build/Module.symvers .

# Copy localversion files (these set the kernel version string)
cp /usr/lib/modules/$KVER/build/localversion.* . 2>/dev/null

# Prepare the build system
make LLVM=1 olddefconfig
make LLVM=1 modules_prepare
```

> **Note**: `LLVM=1` is **mandatory** — CachyOS kernels are compiled with Clang, not GCC.
> Using GCC will produce an incompatible module.

##### 4. Apply the Patches

Copy the three patch scripts from this guide's `patches/` directory to the BC-250, then run them:

```fish
set AMDGPU_DIR (pwd)/drivers/gpu/drm/amd/amdgpu

python3 patches/patch1_gfxoff.py $AMDGPU_DIR
python3 patches/patch2_gmc.py $AMDGPU_DIR
python3 patches/patch3_amdgpu_gmc.py $AMDGPU_DIR
```

Verify the patches were applied:
```fish
grep -c "BC-250" $AMDGPU_DIR/gfx_v10_0.c    # Should be ≥ 4
grep -c "BC-250" $AMDGPU_DIR/gmc_v10_0.c     # Should be ≥ 14
grep -c "BC-250" $AMDGPU_DIR/amdgpu_gmc.c    # Should be ≥ 9
```

##### 5. Build the Module

```fish
make LLVM=1 -j(nproc) M=drivers/gpu/drm/amd/amdgpu modules
```

This takes 3-10 minutes depending on CPU. The output should end with:
```
LD [M]  drivers/gpu/drm/amd/amdgpu/amdgpu.ko
```

##### 6. Strip and Compress

```fish
# Strip debug symbols: ~600MB → ~30MB
strip --strip-debug drivers/gpu/drm/amd/amdgpu/amdgpu.ko

# Compress: ~30MB → ~4.5MB
zstd -19 -f drivers/gpu/drm/amd/amdgpu/amdgpu.ko
```

---

## 9. Step 7 — Install Module & Reboot

##### 1. Backup the Original Module

```fish
set KVER (uname -r)
set MODULE_DIR /usr/lib/modules/$KVER/kernel/drivers/gpu/drm/amd/amdgpu

sudo cp $MODULE_DIR/amdgpu.ko.zst $MODULE_DIR/amdgpu.ko.zst.original
```

##### 2. Install the Patched Module

```fish
sudo cp drivers/gpu/drm/amd/amdgpu/amdgpu.ko.zst $MODULE_DIR/amdgpu.ko.zst
sudo depmod -a
```

##### 3. Rebuild Initramfs

For Limine:
```fish
sudo limine-update
```

For GRUB/mkinitcpio:
```fish
sudo mkinitcpio -P
```

##### 4. Verify Before Reboot

```fish
# Check the installed module has all 9 BC-250 strings
zstd -d -c $MODULE_DIR/amdgpu.ko.zst | strings | grep "BC-250"
```

Expected output (9 strings):
```
BC-250: GFXOFF disabled to prevent GPU power-state hangs
BC-250: GPU unreachable (MMIO returned 0xFFFFFFFF)...
BC-250: GPU died during sem acquire (0xFFFFFFFF)
BC-250: GPU died during TLB flush ACK wait (0xFFFFFFFF)
BC-250: GPU unreachable in fw_reg_write_reg_wait...
BC-250: GPU died during reg_write_reg_wait (0xFFFFFFFF)
BC-250 KIQ bypass active
BC-250 KIQ bypass active in fw_reg_write_reg_wait
BC-250: MMIO reg write/wait timeout
```

##### 5. Reboot

```fish
sudo reboot
```

##### Emergency Rollback

If the system doesn't boot or the GPU crashes, restore the original module:

```fish
set KVER (uname -r)
set MODULE_DIR /usr/lib/modules/$KVER/kernel/drivers/gpu/drm/amd/amdgpu

sudo cp $MODULE_DIR/amdgpu.ko.zst.original $MODULE_DIR/amdgpu.ko.zst
sudo depmod -a
sudo limine-update  # or: sudo mkinitcpio -P
sudo reboot
```

---

## 10. Step 8 — Post-Reboot Verification

After reboot, run the verification script:

```fish
bash scripts/06_verify_installation.sh
```

Or check manually:

### Check dmesg for v3 Module

```fish
sudo dmesg | grep -E "BC-250|GFXOFF|out-of-tree"
```

Expected:
```
amdgpu: loading out-of-tree module taints kernel.
amdgpu 0000:01:00.0: amdgpu: BC-250: GFXOFF disabled to prevent GPU power-state hangs
```

### Check for Errors

```fish
# KIQ timeout errors (should be 0)
sudo dmesg | grep -ci "timeout waiting for kiq fence"

# GPU unreachable events (should be 0)
sudo dmesg | grep -ci "GPU unreachable\|GPU died"

# NULL pointer / BUG (should be 0)
sudo dmesg | grep -ci "BUG\|NULL pointer"
```

### Check Device Nodes

```fish
ls /dev/dri/
# Expected: card0  renderD128  (and by-path/)

ls /dev/kfd
# Expected: /dev/kfd (character device)
```

### Check ppfeaturemask

```fish
cat /sys/module/amdgpu/parameters/ppfeaturemask
# Expected: 0xfff73ef7
```

### Check rocminfo

```fish
rocminfo | grep -E "Name:|Marketing|gfx|Done"
```

Expected output includes:
```
  Name:                    gfx1010
  Marketing Name:          AMD BC-250
*** Done ***
```

---

## 11. Step 9 — HIP Compute Tests

Compile and run the provided HIP test programs:

### Compile Tests

```fish
cd tests/
hipcc --offload-arch=gfx1010 -o hip_probe hip_probe.cpp
hipcc --offload-arch=gfx1010 -o hip_minimal_test hip_minimal_test.cpp
hipcc --offload-arch=gfx1010 -o hip_vector_add hip_vector_add.cpp
```

### Run Tests (in order)

```fish
# Test 1: Device probe (no compute)
./hip_probe

# Test 2: Minimal kernel compute (32 values)
./hip_minimal_test

# Test 3: Full vector add with managed memory (65536 elements, sin²+cos²=1.0)
./hip_vector_add
```

### Sequential Stress Test

The critical test — on unpatched kernels, the **second** consecutive HIP run crashes the system:

```fish
for i in (seq 1 5)
    echo "=== Round $i ==="
    ./hip_minimal_test
    sleep 2
end
```

All 5 rounds should pass. If any round hangs or crashes, the module patch may not be applied
correctly.

You can also run the comprehensive test script:

```fish
bash scripts/07_run_hip_tests.sh
```

---

## 12. Cyan Skillfish Governor (GPU Clock Management)

The BC-250's GPU clock/voltage management is handled by the `cyan-skillfish-governor` service.
The kernel patches handle GFXOFF/power-state prevention; the governor handles DPM clock scaling.

### Installation

```fish
paru -S cyan-skillfish-governor
```

### Enable & Start

```fish
sudo systemctl enable --now cyan-skillfish-governor
```

### Verify

```fish
systemctl is-active cyan-skillfish-governor
# Expected: active

cat /sys/class/drm/card0/device/pp_dpm_sclk
# Expected: Shows clock levels with governor managing transitions
```

### Safe Operating Points

| Clock | Voltage | Use Case |
|-------|---------|----------|
| 1000 MHz | 700 mV | Idle |
| 1500 MHz | 900 mV | Light load |
| 2000 MHz | 1000 mV | Compute (max recommended) |

---

## 13. GPU Watchdog (Safety Monitor)

A safety watchdog script monitors kernel logs for KIQ timeouts and auto-kills GPU processes
before the timeout cascade crashes the system. The window to act is ~10 seconds after first timeout.

### Usage

```fish
# Monitor and auto-kill on KIQ timeout
bash scripts/gpu_watchdog.sh

# Monitor only (no kill)
bash scripts/gpu_watchdog.sh --dry-run

# Kill after 2 KIQ timeouts instead of 1
bash scripts/gpu_watchdog.sh --max-kiq 2
```

### Running as a Background Monitor

```fish
nohup bash scripts/gpu_watchdog.sh > /tmp/gpu_watchdog.log 2>&1 &
```

---

## 14. HIP Programming Guidelines for BC-250

### Memory Allocation

| Function | Safe? | Notes |
|----------|-------|-------|
| `hipMallocManaged()` | **YES** | Preferred — unified memory for APU |
| `hipHostMalloc()` | **YES** | Pinned host memory — safe |
| `hipHostMallocCoherent` | **YES** | Cache-coherent host memory |
| `hipMalloc()` | **CAUTION** | Works with v3 patches but may be slower |
| `hipMemcpy()` | **CAUTION** | Works with v3 patches |

### Critical Rules

1. **Never call `hipDeviceReset()`** — triggers KIQ queue teardown, crashes the system
2. **Use `_exit(0)` instead of `return 0`** in HIP programs — bypasses C++ static destructors
   that trigger HIP runtime cleanup, which can cause KIQ fence timeouts
3. **Never call `rocm-smi` repeatedly** — GPU management queries can destabilize the device
4. **Run a single long-lived daemon** for GPU workloads when possible — each process startup/exit
   cycles TLB flush paths

### Example: Safe HIP Program Exit

```cpp
#include <hip/hip_runtime.h>
#include <unistd.h>  // _exit()

int main() {
    // ... your HIP code ...

    // CRITICAL: Use _exit() to avoid HIP runtime destructor crash
    printf("Done\n");
    fflush(stdout);
    _exit(0);  // Bypasses C++ destructors and HIP cleanup
}
```

---

## 15. Kernel Module Rebuild After Updates

**Any CachyOS kernel update will replace your patched module.** After updating the kernel,
you must rebuild and reinstall the patched module.

### Quick Rebuild Steps

```fish
set OLD_KVER "6.19.6-2-cachyos"    # Previous kernel
set NEW_KVER (uname -r)             # New kernel after update

# If kernel version changed, download new CachyOS source and repeat Step 6
# If only pkgrel changed (e.g., -2-cachyos → -3-cachyos), you may be able to
# just copy the module and rebuild initramfs:

set MODULE_DIR /usr/lib/modules/$NEW_KVER/kernel/drivers/gpu/drm/amd/amdgpu
sudo cp /usr/lib/modules/$OLD_KVER/kernel/drivers/gpu/drm/amd/amdgpu/amdgpu.ko.zst $MODULE_DIR/
sudo depmod -a
sudo limine-update
```

> **Note**: This copy approach only works if the kernel ABI hasn't changed between versions.
> If the module fails to load, you must do a full rebuild from the new kernel source.

---

## 16. Technical Reference — Why This GPU Needs Patches

### The KIQ Problem

KIQ (Kernel Interface Queue) is a privileged ring buffer used by the amdgpu driver for TLB
invalidation and GPU management. On the BC-250, KIQ commands cause **fence timeouts** — the GPU
never acknowledges the command, and the CPU waits indefinitely.

There are exactly **4 code paths** that use the KIQ ring at runtime:

| # | Function | File | Patched? |
|---|----------|------|----------|
| 1 | `gmc_v10_0_flush_gpu_tlb()` | gmc_v10_0.c | **YES** — goto use_mmio |
| 2 | `amdgpu_gmc_flush_gpu_tlb_pasid()` | amdgpu_gmc.c | **YES** — direct callout |
| 3 | `amdgpu_gmc_fw_reg_write_reg_wait()` | amdgpu_gmc.c | **YES** — MMIO write+poll |
| 4 | `amdgpu_gfx_enable/disable_kcq()` | amdgpu_gfx.c | No (boot only, works fine) |

### The GFXOFF Problem

After a HIP process exits, the GPU enters GFXOFF (a power-saving state). When the next process
starts and triggers a TLB flush, the GPU is unresponsive. MMIO reads via `readl()` inside a
spinlock-protected loop hang the CPU indefinitely because the BC-250's internal PCIe fabric has
**no completion timeout** (`DevCap2: Completion Timeout: Not Supported`).

### The v3 Three-Layer Solution

| Layer | Mechanism | Purpose |
|-------|-----------|---------|
| 1 — GFXOFF Disable | `gfx_v10_0.c`: `PP_GFXOFF_MASK` cleared for IP 10.1.3 | Prevents GPU from entering unrecoverable power-save |
| 2 — KIQ Bypass + Dead-GPU | `gmc_v10_0.c` + `amdgpu_gmc.c`: MMIO instead of KIQ, 0xFFFFFFFF checks | Avoids KIQ ring entirely; detects dead GPU before hanging |
| 3 — Boot Parameters | `ppfeaturemask=0xfff73ef7` | Belt-and-suspenders: disables GFXOFF+DeepSleep+ULV at power management level |

### Patch Summary (8 modifications across 3 files)

| # | File | Function | Type | Purpose |
|---|------|----------|------|---------|
| 1 | `gfx_v10_0.c` | `gfx_v10_0_check_gfxoff_flag` | v3 | Disable GFXOFF for IP 10.1.3 |
| 2 | `gmc_v10_0.c` | `gmc_v10_0_flush_gpu_tlb` | v2 | KIQ bypass → `goto use_mmio` |
| 3 | `gmc_v10_0.c` | `gmc_v10_0_flush_gpu_tlb` | v3 | Pre-spinlock 0xFFFFFFFF health check |
| 4 | `gmc_v10_0.c` | `gmc_v10_0_flush_gpu_tlb` | v3 | Sem acquire loop dead-GPU bail |
| 5 | `gmc_v10_0.c` | `gmc_v10_0_flush_gpu_tlb` | v3 | ACK-wait loop dead-GPU bail |
| 6 | `gmc_v10_0.c` | `gmc_v10_0_hw_init` | v2 | `flush_pasid_uses_kiq = false` |
| 7 | `amdgpu_gmc.c` | `amdgpu_gmc_flush_gpu_tlb_pasid` | v2 | Direct MMIO TLB flush |
| 8 | `amdgpu_gmc.c` | `amdgpu_gmc_fw_reg_write_reg_wait` | v2+v3 | MMIO write+poll + dead-GPU detection |

### Why Mining OS (Kernel 5.10) Worked Without Patches

In kernel 5.10 + AMDGPU-PRO 22.20, TLB flush was simpler and more localized. The centralized
`amdgpu_gmc_flush_gpu_tlb_pasid()` in `amdgpu_gmc.c` and the deferred work
`amdgpu_vm_tlb_fence_work()` didn't exist yet. KIQ failures returned `-ETIME` gracefully instead
of cascading to GPU death. Modern kernels (6.x) refactored TLB flushing into a shared centralized
path that defaults to KIQ for all hardware — which breaks BC-250.

---

## 17. Troubleshooting

### System freezes after HIP program runs

**Cause**: v3 module not loaded, or initramfs not rebuilt after installation.

**Fix**: Boot from recovery, restore original module, verify initramfs was rebuilt:
```fish
sudo cp /usr/lib/modules/(uname -r)/kernel/drivers/gpu/drm/amd/amdgpu/amdgpu.ko.zst.original \
       /usr/lib/modules/(uname -r)/kernel/drivers/gpu/drm/amd/amdgpu/amdgpu.ko.zst
sudo depmod -a
sudo limine-update  # MUST rebuild initramfs!
sudo reboot
```

### NULL pointer dereference at boot (drm_vma_offset_add)

**Cause**: Module was built from vanilla kernel.org source instead of CachyOS source.

**Fix**: Rebuild from CachyOS-specific kernel source (see Step 6).

### `rocminfo` shows no GPU / "No HSA GPU agents found"

**Cause**: Environment variables not set, or `/dev/kfd` doesn't exist.

**Fix**:
```fish
# Check env vars
echo $HSA_OVERRIDE_GFX_VERSION  # Should be 10.1.0

# Check /dev/kfd exists
ls -la /dev/kfd

# Check user groups
groups  # Should include 'render'
```

### "KIQ timeout" messages in dmesg

**Cause**: Stock (unpatched) module is loaded instead of v3.

**Fix**: Verify the v3 module is installed:
```fish
zstd -d -c /usr/lib/modules/(uname -r)/kernel/drivers/gpu/drm/amd/amdgpu/amdgpu.ko.zst \
  | strings | grep "BC-250"
# Should show 9 BC-250 strings
```

### Module version mismatch after kernel update

**Cause**: CachyOS updated the kernel, replacing the patched module.

**Fix**: Rebuild the module from matching CachyOS source (see Section 15).

---

## 18. File Inventory

```
BC250_ROCm_Guide/
├── README.md                          ← This guide
├── config/
│   └── amdgpu.conf                   ← Modprobe configuration
├── patches/
│   ├── patch1_gfxoff.py              ← Layer 1: Disable GFXOFF
│   ├── patch2_gmc.py                 ← Layer 2: KIQ bypass + dead-GPU (gmc_v10_0.c)
│   └── patch3_amdgpu_gmc.py          ← Layer 2: KIQ bypass + dead-GPU (amdgpu_gmc.c)
├── scripts/
│   ├── 01_install_rocm_packages.sh   ← Package installation
│   ├── 02_configure_environment.sh   ← Environment variables + modprobe + boot params
│   ├── 04_build_patched_module.sh    ← Download source, patch, build module
│   ├── 05_install_module.sh          ← Install module + rebuild initramfs
│   ├── 06_verify_installation.sh     ← Post-reboot verification
│   ├── 07_run_hip_tests.sh           ← Compile and run HIP tests
│   └── gpu_watchdog.sh               ← KIQ timeout safety monitor
└── tests/
    ├── hip_probe.cpp                 ← Device diagnostic (6 steps)
    ├── hip_minimal_test.cpp          ← Minimal kernel compute test
    └── hip_vector_add.cpp            ← Full managed-memory vector add test
```

---

*Based on research and patches by Dani (2026-02-22), adapted and verified on CachyOS kernel
6.19.6-2-cachyos with ROCm 7.2.0.*
