chore: moved the newly added article to the correct directory and removed the draft parameter
Build and Publish / build (push) Successful in 1m38s

This commit is contained in:
2026-11-08 16:01:25 +01:00
parent e693645bb9
commit 44a3f6ae5f
19 changed files with 2 additions and 6 deletions
@@ -0,0 +1,523 @@
+++
title = "BC-Zero - Board Testing"
summary = "From an old mining board to a console and AI server"
date = "2026-11-08"
tags = ["BC-250", "PS5", "Unlock", "BIOS", "CPU", "GPU"]
categories = ["Projects"]
series = ["BC-Zero"]
series_order = 1
+++
On February 5th, [Soffio](https://t.me/Soffioo), a friend and fellow
[LUGMan](https://lugman.org/) member, made me discover a peculiar board: the
**BC-250**.
The BC-250 is a board that comes from an [ASRock cryptocurrency mining
rig](https://www.tomshardware.com/news/twelve-ps5-apus-power-asrocks-new-cryptomining-rig),
which housed twelve of them.
Inside each of these boards there's a *binned* chip derived from the AMD APU of
the PlayStation 5, with 6 of the 8 CPU cores and 24 of the 36 GPU CUs enabled,
along with 16GB of GDDR6 RAM **unified** between CPU and GPU, an M.2 slot (PCIe
2.0x2 or SATA III), and just a few ports: two USB 2.0, two USB 3.0, one Gigabit
Ethernet, and one DisplayPort. Power is supplied through an 8-pin PCIe
connector.
At first I wasn't really convinced, especially seeing a third of the CUs cut off
and knowing that it's a board with a custom, partially locked chip (on top of
the locked cores, some features like video encoding/decoding are missing),
coming from cryptocurrency mining and with no support or community behind it.
But the price was definitely interesting, and apparently this board has a very
active community that works hard to squeeze 100% of its potential out of it on
Linux.
![Soffio: "If you want I can give you one, I bought it without the coupon and I
was planning to resell it😂" "So technically I'm getting two😂" Me: "Nah, no
worries" "I wouldn't know what to do with it"](images/01-not-fully-convinced.png
"Me, not fully convinced<br><br>**Translation**:<br>*Soffio*: \"If you want I
can give you one, I bought it without the coupon and I was planning to resell
it😂\" \"So technically I'm getting two😂\"<br>*Me*: \"Nah, no worries\" \"I
wouldn't know what to do with it\"")
Things changed when, on the morning of May 30th, I got this message:
![Soffio: "They managed to unlock all the CUs, went from 24 to 40. Now they're
looking into unlocking the 8 cores😂🌚👌"](images/02-40cu-unlocked-news.png
"<br>**Translation**:<br>*Soffio*: \"They managed to unlock all the CUs, went
from 24 to 40. Now they're looking into unlocking the 8 cores😂🌚👌\"")
And good old Soffio also pointed out that the AliExpress sales were about to
start. Intrigued by the whole thing, I asked him if he could lend me his board
for a few days, just to try it out and see what could be done.
And *oh boy*, did this board convince me.
## Step 0: Preparation
One downside of the BC-250 is that it's not exactly *plug-and-play*. At the very
least, you need to:
1. Find a power supply that can ***really*** deliver at least 300W on the +12V
rail, with cables that can handle all those amperes;
2. Have a monitor with DisplayPort (or buy an adapter);
3. Find a way to cool the damn thing;
4. Flash the BIOS.
My test setup was:
1. The first "*el cheapo*" power supply I could find lying around (which "will
surely be fine, it says 500W");
2. A passive DP ➜ HDMI adapter;
3. A portable air conditioner for cooling (it was summer and it was starting to
get hot);
4. A CH341 SPI programmer (which I already had).
![Home setup](images/03-initial-setup.png "If you look closely, the PS_ON ➜ GND
bridge was made with a jumper wire and all the power goes through a SATA ➜ PCIe
adapter. Don't try this at home")
Not exactly the best setup for testing the board, but you work with what you
have.
## Step 1: Flashing the BIOS
The [first step in the community
documentation](https://elektricm.github.io/amd-bc250-docs/getting-started/quick-start/#step-1-bios-flash-critical)
is flashing the BIOS. Without a custom BIOS you don't get essential features
like dynamic VRAM allocation (remember, the 16GB of RAM are shared) and proper
fan control.
At first I installed the one recommended by the guide, the one by
[TuxThePenguin0](https://gitlab.com/TuxThePenguin0/bc250-bios), but later on I
discovered another BIOS, the one by [Forbidden
Darkness](https://github.com/Forbidden-Darkness/AMD-BC-250-UEFI-v2.2-Firmware-Menu-Script),
which, on top of unlocking the dynamic allocation menu, offers a selection of
custom splash images and, most importantly, **unlocks all 8 CPU cores**.
"*Wait, weren't they locked down?*" Apparently not enough.
The APU has all cores on the silicon, they're just disabled via firmware. A
similar principle also applies to the GPU CUs, but we'll get to that later.
---
The installation is even simpler and doesn't require a BIOS flasher: just copy
the files from the `.7z` archive in the releases to a USB stick formatted in
FAT32 and boot from it. The installer asks which splash image we want (the
[`07`](https://github.com/user-attachments/assets/ca23ce6c-08ab-4293-9a70-0e55f66dc93c)
is the best one, *imho*) and proceeds with the flashing.
![Flashing the BIOS](images/04-bios-flashing.png "Flashing the BIOS")
{{< alert icon="triangle-exclamation" cardColor="#e6d237" iconColor="#1d3557"
textColor="#1d3557" >}}
Flashing the BIOS is a dangerous operation. Make sure the board doesn't turn
off.
{{< /alert >}}
Once the flashing is done, you need to reset all the BIOS settings. To do that,
just unplug the power and bridge pin 2 and 3 of the `CLRCMOS1` header for a few
seconds. Once that's done, we can put the header back on pins 1 and 2 and plug
the power back in. By entering the BIOS with the `Del` key at boot we'll see a
lot more options.
![New boot logo](images/05-new-boot-logo.png "New boot logo")
![New entries in the "Advanced" menu](images/06-new-advanced-menu.png "New
entries in the \"Advanced\" menu")
First, let's make the VRAM allocation automatic. To do that, we need to go to
`Chipset` > `GFX Configuration` > `GFX Configuration` and set `Integrated
Graphics Controller` to `Forces`, then `UMA Mode` to `UMA_SPECIFIED`, and
finally `UMA Frame buffer size` to `512M`.
![The correct UMA configuration](images/07-uma-512m.png "The correct UMA
configuration")
Then in `NB Configuration` disable the IOMMU (it doesn't seem to work on this
board).
Finally, we enable all the cores by going to `Advanced` > `MeiMeiDXEv3 Menu` and
enabling everything.
![The configuration to enable all 8 cores](images/08-8-core-unlock.png "The
configuration to enable all 8 cores")
{{< alert icon="triangle-exclamation" cardColor="#e6d237" iconColor="#1d3557"
textColor="#1d3557" >}}
There's no guarantee that all the cores will work. Damaged cores could cause
sudden crashes.
To avoid that, we'll run a stress test on all the cores and check that no
`Machine Check Exception` shows up in the kernel logs before enabling this
setting in production.
{{< /alert >}}
Once the BIOS is properly configured, we're ready to install an operating system
and test this board for real.
## Step 2: Installing a OS for testing
To do some CPU stress testing and run some tests on the GPU, I'll install Arch
Linux.
It won't be the final distro I'll install, but the choice isn't random:
development for this board is bleeding-edge, and for now almost all the scripts
assume you're running Arch or Fedora, so you have the latest package versions.
![The archinstall configuration I'll use](images/09-archinstall.png "The
archinstall configuration I'll use")
![The installed system](images/10-fastfetch.png "The installed system. As you
can see, all 16 threads already show up")
### Testing the 8 cores
First of all, let's test whether all 8 cores work as they should. To do that,
install the `stress-ng` package and run a stress test:
```sh
stress-ng --cpu 16 --cpu-method all --verify --timeout 2h --metrics
```
Then we check that there were no errors with:
```sh
sudo dmesg | grep -iE "mce|machine check|hardware error"
```
If the kernel doesn't report any errors, we've just gone from 6 to 8 cores for
free. If there is an error you can change which cores to enable from the BIOS.
### Stress-testing the GPU
Next, let's stress test the GPU to get a performance baseline before installing
the governor or enabling all the CUs. To do that, I installed Furmark and ran
the 1080p test.
![Furmark (68 FPS)](images/11-baseline-furmark.png)
I'd say 70 FPS isn't *that* bad for the board *out-of-the-box*, but we can
definitely do better, much better.
---
A small note I feel I should add: if during the stress test the screen goes
black and the board doesn't respond in any way, check your power supply. The
little foreshadowing I did in step 0 about the power supply is because during my
tests I ran Ollama and completely fried the PSU since (apparently) it couldn't
really handle the whole load on the +12V rail. I then bought the PSU recommended
by the community on AliExpress, along with the board, the [Metalfish 500W
FlexATX](https://elektricm.github.io/amd-bc250-docs/hardware/power#option-2-flexatx-psu-500w),
and I haven't had any problems since.
![Deceased PSU](images/12-dead-psu.jpg "Rest in peace, soldier 🫡")
### Installing the GPU Governor
By default the GPU always runs at 1500MHz: a governor lets you raise the clock
when the GPU is under load and lower it when it isn't, to save power.
We'll install `cyan-skillfish-governor-smu`, a community project that talks
directly to the board's System Management Unit. It's also already packaged in
the AUR, so to install it you just need to run:
```sh
paru -S cyan-skillfish-governor-smu
systemctl enable --now cyan-skillfish-governor-smu
```
We can check that it works with:
```
$ cat /sys/class/drm/card1/device/pp_dpm_sclk # If it doesn't work, try card0
0: 1000Mhz *
1: 1500Mhz
2: 2000Mhz
```
The first and last lines are, respectively, the minimum and maximum GPU
frequency, while the middle line can change. The asterisk marks the frequency
currently in use. An example under load:
```
$ cat /sys/class/drm/card1/device/pp_dpm_sclk
0: 1000Mhz
1: 1850Mhz *
2: 2000Mhz
```
We should see the GPU automatically use a higher frequency under load and a
lower one when idle.
---
**Small note**: unlocking the 8 cores affects how the SMU values are read. It's
a known issue and we'll fix it later on, when we'll deal with the operating
system. Without any fix, the frequency values are wrong, for example:
```
$ cat /sys/class/drm/card1/device/pp_dpm_sclk
0: 1000Mhz *
1: 4575Mhz
2: 2000Mhz
# Not a bad overclock for a chip that tops out at 2230MHz
```
With that said, let's run a stress test now, with the governor installed.
![Furmark (83 FPS)](images/13-furmark-governor.png)
Now that we can scale up to 1850MHz, our GPU manages to reach 83 FPS at 1080p,
not bad!
1850MHz is by no means the most this chip can handle, but for now we'll settle
for it. For the curious, the frequency and voltage curves are fully customizable
and live in `/etc/cyan-skillfish-governor-smu/config.toml`. With a bit of trial
and error you can push the hardware to its limits while minimizing power draw,
but we'll do that when we set up the final operating system.
### Unlocking the 40 CUs
As we said at the beginning, this board only exposes 24 CUs to the kernel, even
though the PS5 has 36 and there are actually 40 on the silicon. We can verify
this with:
```
$ sudo dmesg | grep active_cu_number
[ 6.882856] amdgpu 0000:01:00.0: SE 2, SH per SE 2, CU per SH 10, active_cu_number 24
```
To test and then unlock all the CUs, we'll use [duggasco's
repository](https://github.com/duggasco/bc250-40cu-unlock). The mechanism is
similar to the core unlock: here too you just need to change a few values,
because the CUs aren't locked at the hardware level, they're just disabled by
the firmware.
Two registers in the GPU decide how many CUs are active. What this script does
is patch the `amdgpu` driver and write the right values into those registers
while the driver starts up, waking up the disabled CUs.
```
$ git clone https://github.com/duggasco/bc250-40cu-unlock.git
$ cd bc250-40cu-unlock/
$ sudo pacman -S linux-headers vulkan-headers
$ sudo scripts/bc250-enable-40cu-arch.sh build
# Wait for the `amdgpu` module to be recompiled
$ sudo scripts/bc250-enable-40cu-arch.sh enable
```
Once the BC-250 has rebooted, we can check that the patch worked using the same
command as before:
```
$ sudo dmesg | grep active_cu_number
[ 8.004012] amdgpu 0000:01:00.0: SE 2, SH per SE 2, CU per SH 10, active_cu_number 24
```
Apparently the script doesn't load the custom module automatically. That's not a
problem: let's regenerate the initramfs and reboot manually:
```
$ sudo mkinitcpio -P
$ reboot
# Once it has rebooted
$ sudo dmesg | grep active_cu_number
[ 8.058999] amdgpu 0000:01:00.0: SE 2, SH per SE 2, CU per SH 10, active_cu_number 40
```
Much better!
---
Once the custom module is installed, we can move on to testing the CUs:
```
$ sudo scripts/bc250-cu-health-test.sh start
```
During the test the PC will automatically reboot twenty times. Once the PC stops
rebooting on its own, we can see the test results with:
```
$ scripts/cu_map.sh
BC-250 CU Map + Health
SE0 SH0: ■■■■■■■■■■
SE0 SH1: ■■■■■■■■■■
SE1 SH0: ■■■■■■■■■■
SE1 SH1: ■■■■■■■■■■
40/40 CUs active, 0 harvested
BC-250 CU Map + Health
SE0 SH0: ■■■■■■✓✓✓✓
SE0 SH1: ■■■■■■✓✓✓✓
SE1 SH0: ■■■■■■✓✓✓✓
SE1 SH1: ■■■■■■✓✓✓✓
40/40 CUs usable (0 defective, masked)
```
Apparently I won the silicon lottery and have 8 cores and 40 working CUs.
Hurray! 🎉
If there had been any defective CUs I could have masked them using the
`bc250-cu-mask.sh` script.
---
Running the last stress test with Furmark:
![Furmark (128 FPS)](images/14-furmark-40cu.png)
We went from the bare board, without any additional software, running at an
average of 70 FPS, to having a governor and all the CUs unlocked, with peaks of
138 FPS, twice as much!
Of course, this approach to unlocking the 40 CUs has a pretty obvious problem,
especially on rolling distributions like Arch: you have to recompile the module
every time you update the kernel. This is another problem we'll solve later on,
when we stop using a test OS, but if after an update the GPU isn't as fast as
before, it might be worth taking a look.
### Sensors and Other Essential Configurations
Once the essentials like CPU and GPU are sorted out, there are still a few small
things to take care of, such as sensor management, fans, swap, VRAM split,
etc...
I could go on about it for hours, but I'll point you to the [community
documentation](https://elektricm.github.io/amd-bc250-docs/), which is very
thorough.
What I'd like to do now is point out one thing: using the `sensors` command, we
get very little data OOTB:
```
$ sensors
amdgpu-pci-0100
Adapter: PCI adapter
vddgfx: 799.00 mV
vddnb: 799.00 mV
edge: +39.0°C
PPT: 41.41 W (avg = 40.85 W)
sclk: 1000 MHz
k10temp-pci-00c3
Adapter: PCI adapter
Tctl: +41.6°C
```
To get more data we need the `nct6683` module (read-only) or `nct6687` (you can
create custom curves with it, but it's *out of tree*). Since `nct6683` is
already available, we can enable it with:
```
$ echo 'options nct6683 force=true' | sudo tee /etc/modprobe.d/sensors.conf
$ echo 'nct6683' | sudo tee /etc/modules-load.d/99-sensors.conf
$ sudo mkinitcpio -P
$ reboot
```
After rebooting we'll see a lot more data:
```
$ sensors
k10temp-pci-00c3
Adapter: PCI adapter
Tctl: +46.9°C
amdgpu-pci-0100
Adapter: PCI adapter
vddgfx: 799.00 mV
vddnb: 799.00 mV
edge: +41.0°C
PPT: 42.61 W (avg = 40.75 W)
sclk: 1000 MHz
nct6686-isa-0a20
Adapter: ISA adapter
VIN0: 800.00 mV (min = +0.00 V, max = +0.00 V)
VIN1: 1.01 V (min = +0.00 V, max = +0.00 V)
VIN2: 992.00 mV (min = +0.00 V, max = +0.00 V)
VIN6: 1.39 V (min = +0.00 V, max = +0.00 V)
VIN7: 800.00 mV (min = +0.00 V, max = +0.00 V)
VIN16: 896.00 mV (min = +0.00 V, max = +0.00 V)
fan1: 0 RPM (min = 0 RPM)
fan2: 1709 RPM (min = 0 RPM)
fan3: 0 RPM (min = 0 RPM)
fan4: 0 RPM (min = 0 RPM)
fan5: 0 RPM (min = 0 RPM)
AMD TSI Addr 98h: +47.0°C (low = +0.0°C)
(high = +0.0°C, hyst = +0.0°C)
(crit = +0.0°C) sensor = AMD AMDSI
Thermistor 14: +37.0°C (low = +0.0°C)
(high = +0.0°C, hyst = +0.0°C)
(crit = +0.0°C) sensor = thermistor
Thermistor 15: +37.0°C (low = +0.0°C)
(high = +0.0°C, hyst = +0.0°C)
(crit = +0.0°C) sensor = thermistor
pwm1: 64%
pwm2: 64%
pwm3: 64%
pwm4: 64%
pwm5: 64%
intrusion0: OK
beep_enable: disabled
```
## Step 3: Hardware Mods
I want to remind you that for all these tests I was using Soffio's BC-250, just
to see whether it was something I'd be interested in. And since I found myself
pretty hooked I decided to get everything I needed from AliExpress.
Luckily with the sales and also using TopCashback I managed to bring home
everything I needed for less than €200. I then bought a couple of Arctic P12
Pros from Amazon.
Everything arrived on June 24th, so it was time to get to work on:
* Replacing the thermal paste and pads;
* Installing heatsinks on the back panel, to cool the GDDR6;
* Removing the metal bracket and the I/O shield (they're only needed if the
board is mounted in the rig);
* Re-running the test suite mentioned above to see if I had won the silicon
lottery a second time (luckily I did);
* Modding the heatsink.
The heatsink mod let me solve one of the problems I was having with the board:
how do I get rid of 200W of heat? So far I had the portable AC, but I couldn't
keep using a heat pump to cool a single board.
When they're in the mining rig, the BC-250 all have their heatsinks laid out
lengthwise, so a single array of fans is enough to cool all 12 boards at once.
If you want to use one of these boards on its own, you need to get a bit more
creative to get rid of the heat.
The most common solution in the community is the [heatsink
mod](https://reddit.com/r/BC250Gaming/comments/1rjc3io/), which consists of
literally cutting open the heatsink in the section above the APU to make room
for a fan.
It's a somewhat long and tedious job, but it's not impossible to do. It's also a
pretty repetitive task, so once you get the hang of it, it goes by farely
quickly. In the end all it took was a pair of scissors, some good music, and an
hour of my time.
![Before the heatsink mod](images/15-before-heatsink-mod.jpg "The BC-250 as it
comes out of the box, with the metal bracket and I/O shield removed")
![After the heatsink mod](images/16-after-heatsink-mod.jpg "The heatsink after
the mod")
It's a bit *rough around the edges* (*literally*), but it works. And the hole is
big exactly as a 120mm fan, so one of the two fans can blow directly onto the
APU.
---
Since this article has gotten pretty long, I've decided to split it into
multiple parts. In the next one, we'll design a custom case for my needs.