+++ title = "BC-Zero - Testing della scheda" summary = "Da vecchia scheda da mining a console e server AI" date = "2038-01-19" tags = ["BC-250", "PS5", "Sblocco", "BIOS", "CPU", "GPU"] categories = ["Progetti"] series = ["BC-Zero"] series_order = 1 draft = true +++ Il 5 febbraio [Soffio](https://t.me/Soffioo), amico e socio [LUGMan](https://lugman.org/), mi ha fatto scoprire una scheda particolare: la **BC-250**. La BC-250 è una scheda proveniente da un [rig per il mining di criptovalute di ASRock](https://www.tomshardware.com/news/twelve-ps5-apus-power-asrocks-new-cryptomining-rig), che ne ospitava dodici. Dentro ognuna di queste schede c'è un chip *binned* derivato dall'APU AMD della PlayStation 5, con 6 degli 8 core CPU e 24 delle 36 CU GPU attivi, insieme a 16GB di RAM GDDR6 **unificati** tra CPU e GPU, uno slot M.2 (PCIe 2.0x2 o SATA III) e poche porte: due USB 2.0, due USB 3.0, una Ethernet Gigabit e una DisplayPort. L'alimentazione è fornita da un connettore PCIe a 8 pin. All'inizio non ero proprio convinto, soprattutto nel vedere un terzo delle CU tagliate via così e nel sapere che è una scheda con un chip custom, parzialmente bloccato (oltre ai core bloccati, alcune funzionalità come l'enconding/decoding video non sono presenti), derivante dal mining e senza alcun tipo di supporto o community dietro. Ma il prezzo era decisamente interessante, e a quanto pare questa scheda ha una community molto attiva che si impegna per tirarne fuori il 100% del potenziale su Linux. ![Soffio: "Oh se vuoi te ne do una, perché l'avevo presa senza coupon e avevo intenzione di rivenderla😂" "Quindi tecnicamente me ne arrivano due😂" Io: "Ma no tranqui" "Non saprei che farmene"](images/01-not-fully-convinced.png "Io non pienamente convinto") Le cose cambiano però quando la mattina del 30 maggio ricevo questo messaggio: ![Soffio: "Sono riusciti a sbloccare tutte le CU, passato da 24 a 40. Adesso stanno guardando per sbloccare gli 8 core😂🌚👌"](images/02-40cu-unlocked-news.png) E sempre il caro Soffio mi fa presente che da li a breve sarebbero iniziati i super sconti AliExpress. Incuriosito dalla faccenda gli chiedo se può prestarmi la sua scheda per un po' di giorni, giusto per provarla e vedere cosa si può fare. E *oh boy* se questa scheda mi ha convinto. ## Step 0: Preparazione Una pecca della BC-250 è che non è proprio *plug-and-play*. Bisogna come minimo: 1. Trovare un alimentatore in grado di fornire ***realmente*** almeno 300W sul rail +12V e con dei cavi che sappiano gestire tutti quegli ampere; 2. Avere un monitor con DisplayPort (o comprare un adattatore); 3. Trovare un modo per raffreddare la maledetta; 4. Flashare il BIOS. Il mio setup di prova era: 1. Il primo alimentatore marchiato "*el cheapo*" che ho trovato sottomano (che "sicuramente andrà bene, c'è scritto 500W"); 2. Adattatore passivo DP ➜ HDMI; 3. Climatizzatore portatile per il raffreddamento (era estate e iniziava a fare caldo); 4. Programmatore SPI CH341 (che avevo già). ![Setup casalingo](images/03-initial-setup.png "Se guardate attentamente, il bridge PS_ON ➜ GND è stato fatto con un cavetto e tutta la potenza passa per un convertitore SATA ➜ PCIe. Non fatelo a casa") Non proprio il setup migliore per testare la scheda, ma si lavora con quello che si ha. ## Step 1: Flashare il BIOS Il [primo punto sulla documentazione della community](https://elektricm.github.io/amd-bc250-docs/getting-started/quick-start/#step-1-bios-flash-critical) è il flashing del BIOS. Senza un BIOS custom non si hanno funzionalità essenziali come l'allocazione dinamica della VRAM (voglio ricordare che i 16GB di RAM sono condivisi) e una corretta gestione delle ventole. All'inizio ho installato quello consigliato dalla guida, quello di [TuxThePenguin0](https://gitlab.com/TuxThePenguin0/bc250-bios), ma più avanti ho scoperto un altro BIOS, quello di [Forbidden Darkness](https://github.com/Forbidden-Darkness/AMD-BC-250-UEFI-v2.2-Firmware-Menu-Script) che, oltre allo sblocco del menù per l'allocazione dinamica offre una selezioni di immagini di splash custom e, soprattutto, **lo sblocco di tutti gli 8 core CPU**. "*Ma come, non erano bloccati?*" A quanto pare non abbastanza. L'APU ha tutti i core presenti sul silicio, sono solo disattivati via firmware. Un principio simile vale anche per le CU della GPU, ma lo vedremo dopo. --- L'installazione è anche più semplice e non richiede un flasher BIOS: basta copiare i file contenuti nell'archivio `.7z` delle release in una chiavetta formattata in FAT32 e farci il boot. L'installer chiede che splash image vogliamo (la [`07`](https://github.com/user-attachments/assets/ca23ce6c-08ab-4293-9a70-0e55f66dc93c) è la migliore *imho*) e procede a flashare. ![Flashing del BIOS](images/04-bios-flashing.png "Flashing del BIOS") {{< alert icon="triangle-exclamation" cardColor="#e6d237" iconColor="#1d3557" textColor="#1d3557" >}} Il flashing del BIOS è un operazione pericolosa. Assicuratevi che la scheda non si spenga nel mentre. {{< /alert >}} Una volta terminato il flashing bisogna resettare tutte le impostazioni del BIOS. Per farlo basta staccare l'alimentazione e bridgare i pin 2 e 3 dell'header `CLRCMOS1` per qualche secondo. Una volta fatto possiamo ripristinare l'header sui pin 1 e 2, ricollegare l'alimentazione ed entrando nel BIOS premendo `Canc` all'avvio vedremo molte più opzioni. ![Nuovo logo al boot](images/05-new-boot-logo.png "Nuovo logo al boot") ![Nuove entry nel menù "Advanced"](images/06-new-advanced-menu.png "Nuove entry nel menù \"Advanced\"") Per prima cosa facciamo in modo che l'allocazione di VRAM sia automatica. Per farlo dobbiamo andare nella sezione `Chipset` > `GFX Configuration` > `GFX Configuration` e impostare `Integrated Graphics Controller` a `Forces`, poi `UMA Mode` a `UMA_SPECIFIED` e infine `UMA Frame buffer size` a `512M`. ![La configurazione corretta per l'UMA](images/07-uma-512m.png "La configurazione corretta per l'UMA") Poi in `NB Configuration` disabilitiamo l'IOMMU (su questa scheda sembra non essere funzionante) Infine abilitiamo tutti i core andando nella sezione `Advanced` > `MeiMeiDXEv3 Menu` e abilitando tutto. ![La configurazione per l'attivazione degli 8 core](images/08-8-core-unlock.png "La configurazione per l'attivazione degli 8 core") {{< alert icon="triangle-exclamation" cardColor="#e6d237" iconColor="#1d3557" textColor="#1d3557" >}} Nulla garantisce che i tutti core siano funzionanti. Core danneggiati potrebbero causare crash improvvisi. Per evitare ciò faremo uno stress-test su tutti i core e controlleremo che nei log del kernel non appaia nessun `Machine Check Exception` prima di abilitare questa impostazione in produzione {{< /alert >}} Una volta che abbiamo configurato correttamente il BIOS siamo pronti per installare un sistema operativo e testare per bene questa scheda. ## Step 2: Installazione di un OS di prova Per fare un po' di stress testing CPU e per fare dei test con la GPU installerò Arch Linux. Non sarà la distro finale che andrò ad installare, ma la scelta non è casuale: lo sviluppo di questa scheda è bleeding-edge e per ora quasi tutti gli script assumono che sia installato Arch o Fedora per avere le ultime versioni dei pacchetti. ![La configurazione di archinstall che userò](images/09-archinstall.png "La configurazione di archinstall che userò") ![Il sistema installato](images/10-fastfetch.png "Il sistema installato. Come vedete si possono già vedere i 16 thread") ### Test degli 8 core Per prima cosa testiamo se tutti gli 8 core funzionano come dovrebbero. Per farlo installiamo il pacchetto `stress-ng` e facciamo uno stress test: ```sh stress-ng --cpu 16 --cpu-method all --verify --timeout 2h --metrics ``` Verifichiamo poi che non ci siano stati errori con: ```sh sudo dmesg | grep -iE "mce|machine check|hardware error" ``` Se il kernel non segnala alcun errore siamo appena passati da 6 a 8 core gratuitamente. In caso di errore invece è possibile modificare quali core attivare e quali no dal BIOS. ### Stress-testing della GPU Facciamo poi uno stress testing della GPU per avere una baseline delle performance prima di installare il governor o abilitare tutte le CU. Per farlo ho installato Furmark e ho fatto il test 1080p ![Furmark (68 FPS)](images/11-baseline-furmark.png) Direi che 70 FPS non sono *così* male per la scheda *out-of-the-box*, ma si può sicuramente fare di meglio, molto meglio. --- Piccola nota che mi sento di aggiungere: se durante lo stess test lo schermo diventa nero e la scheda non risponde in alcun modo, controllate l'alimentazione. Il piccolo *foreshadowing* che ho fatto nello step 0 riguardo all'alimentatore riguarda il fatto che durante i miei test ho fatto girare Ollama e ho completamente bruciato la power supply dato che (a quanto pare) non riusciva a gestire davvero tutto il carico sul rail +12V. Ho successivamente comprato su AliExpress, insieme alla scheda, il PSU consigliato dalla community, il [Metalfish 500W FlexATX](https://elektricm.github.io/amd-bc250-docs/hardware/power#option-2-flexatx-psu-500w) e da li non ho più avuto problemi. ![PSU deceduta](images/12-dead-psu.jpg "Riposa in pace, soldato 🫡") ### Installazione del Governor GPU Di default la GPU gira sempre a 1500MHz: un governor permette di alzare il clock quando la GPU è sotto carico e di abbassarlo quando non lo è per consumare meno. Installeremo `cyan-skillfish-governor-smu`, progetto della community che comunica direttamente con la System Management Unit della scheda. È anche già pacchettizzato nella AUR, quindi per installarlo basta lanciare un: ```sh paru -S cyan-skillfish-governor-smu systemctl enable --now cyan-skillfish-governor-smu ``` Possiamo contollare che funzioni con: ``` $ cat /sys/class/drm/card1/device/pp_dpm_sclk # Se non funziona prova con card0 0: 1000Mhz * 1: 1500Mhz 2: 2000Mhz ``` La prima e l'ultima riga sono rispettivamente la frequenza minima e massima della GPU, mentre il valore centrale è variabile. L'asterisco indica la frequenza attualmente in uso. Un esempio sotto sforzo: ``` $ cat /sys/class/drm/card1/device/pp_dpm_sclk 0: 1000Mhz 1: 1850Mhz * 2: 2000Mhz ``` Dovremmo vedere che la GPU usa automaticamente una frequenza più alta sotto sforzo e più bassa a riposo. --- **Piccola nota**: lo sblocco degli 8 core influisce sulla lettura dei valori dell'SMU. È un problema noto ed andremo a risolverlo più avanti, quando ci preoccuperemo del sistema operativo. Senza alcun fix i valori di frequenza risultano sbagliati, ad esempio: ``` $ cat /sys/class/drm/card1/device/pp_dpm_sclk 0: 1000Mhz * 1: 4575Mhz 2: 2000Mhz # Per un chip che può andare al massimo a 2230MHz non è male come overclock ``` Detto ciò facciamo uno stress test adesso, con il governor installato. ![Furmark (83 FPS)](images/13-furmark-governor.png) Adesso che riusciamo a scalare fino a 1850MHz la nostra GPU riesce ad arrivare a 83 FPS in 1080p, niente male! 1850MHz non è assolutamente il massimo che questo chip può gestire, ma per adesso ci accontenteremo di questo. Per i più curiosi la curva delle frequenze e delle tensioni è completamente personalizzabile e si trova in `/etc/cyan-skillfish-governor-smu/config.toml`. Con un po' di prove si può spingere al massimo l'hardware minimizzando i consumi, ma lo faremo sempre quando andremo a configurare il sistema operativo definitivo. ### Sblocco delle 40 CU Come abbiamo detto all'inizio questa scheda presenta al kernel solamente 24 CU, nonostante nella PS5 ce ne siano 36 e sul silicio ce ne siano effettivamente 40. Possiamo verificarlo con: ``` $ 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 ``` Per testare e successivamente sbloccare tutte le CU useremo il [repository di duggasco](https://github.com/duggasco/bc250-40cu-unlock). Il meccanismo è simile a quello dello sblocco dei core: anche qui basta cambiare qualche valore, perché le CU non sono bloccate a livello hardware, ma solo disattivate dal firmware. A decidere quante CU sono attive sono due registri della GPU. Quello che fa questo script è patchare il driver `amdgpu` e scrivere i valori giusti nei registri mentre il driver si avvia, avviando le CU spente. ``` $ 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 # Attendi la ricompilazione del modulo `amdgpu` $ sudo scripts/bc250-enable-40cu-arch.sh enable ``` Una volta che la BC-250 si sarà riavviata possiamo verificare che la patch ha funzionato usando sempre il comando di prima: ``` $ 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 ``` A quanto pare il modulo custom non viene caricato in automatico dallo script. Non è un problema: rigeneriamo l'initramfs e riavviamo a mano: ``` $ sudo mkinitcpio -P $ reboot # Una volta che si è riavviato $ 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 ``` Molto meglio! --- Una volta installato il modulo custom possiamo procedere con il testing delle CU: ``` $ sudo scripts/bc250-cu-health-test.sh start ``` Durante il test il PC si riavvierà automaticamente una ventina di volte. Una volta che il PC smette di riavviarsi in automatico possiamo vedere i risultati del test con: ``` $ 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) ``` A quanto pare ho vinto la lotteria del silicio e ho 8 core e 40 CU funzionanti. Urrà! 🎉 In caso però ci fossero state delle CU difettose avrei potuto mascherarle usando lo script `bc250-cu-mask.sh`. --- Facendo l'ultimo stress test con Furmark: ![Furmark (128 FPS)](images/14-furmark-40cu.png) Siamo passati dalla scheda nuda e cruda, senza alcun software aggiuntivo, che girava mediamente a 70 FPS ad avere un governor e tutte le CU sbloccate per avere dei picchi da 138 FPS, il doppio! Ovviamente questo approccio per lo sblocco delle 40 CU ha un problema abbastanza evidente soprattutto su distribuzioni rolling come Arch: bisogna ricordarsi di ricompilare il modulo ogni volta che si aggiorna il kernel. Anche questo è un problema che risolveremo più avanti, quando smetteremo di usare un OS di prova, ma se dopo un aggiornamento la GPU non va più veloce quanto prima forse è meglio buttarci un occhio. ### Sensori e altre configurazioni indispensabili Una volta sistemate le cose essenziali come CPU e GPU rimangono alcune piccole accortezze, come ad esempio la gestione dei sensori, delle ventole, la swap, lo split della VRAM, ecc... Potrei starne per ore a parlarne, ma rimando alla [documentazione della community](https://elektricm.github.io/amd-bc250-docs/), che è ben fornita. Quello che mi sento di fare adesso è far notare una cosa: usando il comando `sensors` abbiamo pochi dati 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 ``` Per avere più dati abbiamo bisogno del modulo `nct6683` (read-only) o `nct6687` (si possono creare curve custom, ma è *out of tree*). Dato che `nct6683` è già disponibile possiamo abilitarlo con: ``` $ 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 ``` Dopo aver riavviato vedremo molti più dati: ``` $ 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: Modifiche hardware Vorrei ricordare che per tutti questi test stavo utilizzando la BC-250 di Soffio, giusto per vedere se mi potesse interessare. E dato che ormai ero abbastanza preso, decido di prendermi tutto l'occorrente da AliExpress. Per fortuna con i saldi e anche grazie a TopCashback riesco a portarmi a casa tutto il necessario per meno di 200€. Compro poi un paio di Arctic P12 Pro da Amazon. In data 24 giugno mi arriva il tutto, e quindi ci si mette all'opera per fare: * Cambio pasta e pad termici; * Installazione dei dissipatori sul pannello posteriore, in modo da raffreddare le GDDR6; * Rimozione della linguetta metallica e dell'I/O shield (servono solo se la scheda viene montata nel rig); * Rifare la suite di test sopracitati per vedere se avevo vinto la lotteria del silicio per la seconda volta (per fortuna sì); * Modifica del dissipatore. La modifica del dissipatore mi permette di risolvere uno dei problemi che stavo avendo con la scheda, ovvero: come rimuovo 200W di calore? Per adesso avevo il pinguino, ma non potevo continuare ad usare una pompa di calore per raffreddare una singola scheda. Quando sono nel rig da mining, le BC-250 hanno tutti il dissipatore disposto longitudinalmente, quindi basta un array di ventole per raffreddare tutte e 12 le schede contemporaneamente. Se si vuole usare una di queste schede indipendentemente bisogna diventare un po' più creativi per rimuovere il calore. La soluzione più comune nella community è la [heatsink mod](https://reddit.com/r/BC250Gaming/comments/1rjc3io/), che consiste di aprire letteralmente il dissipatore nella sezione sopra l'APU per avere un posto dove mettere la ventola. È un operazione un po' lunga e tediosa, ma nulla di impossibile. È anche un compito abbastanza ripetitivo, quindi una volta che si è presa la mano finisce presto. Alla fine mi ci è voluta solo una forbice, buona musica e un'ora del mio tempo. ![Prima della modifica al dissipatore](images/15-before-heatsink-mod.jpg "La BC-250 appena rimossa dalla confezione, senza linguetta metallica e I/O shield") ![Dopo la modifica al dissipatore](images/16-after-heatsink-mod.jpg "Il dissipatore dopo la modifica") È un lavoro un po' *rough around the edges* (*literally*), ma funziona. E il foro è grande esattamente quando una ventola da 120mm, quindi una delle due ventole porta soffiare direttamente sopra all'APU. --- Dato che questo articolo si è fatto abbastanza lungo mi sento di spezzettarlo in più parti. Nella prossima andremo a progettare un case custom per il mio use case.