mirror of
https://github.com/duggasco/bc250-40cu-unlock.git
synced 2026-07-15 23:31:00 +00:00
Merge pull request #11 from dannybastos/40cu-arch
added script for archlinux kernel 7.x
This commit is contained in:
386
scripts/bc250-enable-40cu-arch.sh
Executable file
386
scripts/bc250-enable-40cu-arch.sh
Executable file
@@ -0,0 +1,386 @@
|
||||
#!/usr/bin/env bash
|
||||
# bc250-enable-40cu-arch.sh — Build and install a patched amdgpu for 40 CU on BC-250
|
||||
#
|
||||
# Usage:
|
||||
# sudo ./bc250-enable-40cu-arch.sh build # patch + compile + install
|
||||
# sudo ./bc250-enable-40cu-arch.sh enable # set 40 CU mode and reboot
|
||||
# sudo ./bc250-enable-40cu-arch.sh disable # return to stock 24 CU and reboot
|
||||
# sudo ./bc250-enable-40cu-arch.sh status # show current CU state
|
||||
# sudo ./bc250-enable-40cu-arch.sh restore # restore original amdgpu module
|
||||
#
|
||||
# Requirements: linux-headers, gcc, make, zstd, curl. Must run as root on BC-250.
|
||||
# Tested on: Arch Linux
|
||||
#
|
||||
# Authors: duggasco, Claude | License: GPL-2.0
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
KVER="$(uname -r)"
|
||||
KVER_BASE="${KVER%%-*}" # e.g. 6.9.3 from 6.9.3-arch1-1
|
||||
MODDIR="/usr/lib/modules/${KVER}"
|
||||
MODPATH="${MODDIR}/kernel/drivers/gpu/drm/amd/amdgpu/amdgpu.ko"
|
||||
MODSRC=""
|
||||
BUILDDIR="/tmp/bc250-40cu-build"
|
||||
CONF40="/etc/modprobe.d/bc250-40cu.conf"
|
||||
BACKUP_SUFFIX=".bc250-backup-$(date +%Y%m%d)"
|
||||
BC250_PCI_ID="13fe"
|
||||
|
||||
info() { printf '\033[0;32m[+]\033[0m %s\n' "$*" >&2; }
|
||||
warn() { printf '\033[0;33m[!]\033[0m %s\n' "$*" >&2; }
|
||||
err() { printf '\033[0;31m[E]\033[0m %s\n' "$*" >&2; }
|
||||
die() { err "$@"; exit 1; }
|
||||
|
||||
write_param_patch() {
|
||||
cat > "$1" << 'ENDPARAM'
|
||||
|
||||
/* BC-250 40 CU unlock: clears harvest mask + enables SPI dispatch to all WGPs */
|
||||
static int bc250_cc_write_mode;
|
||||
module_param(bc250_cc_write_mode, int, 0444);
|
||||
MODULE_PARM_DESC(bc250_cc_write_mode,
|
||||
"BC-250: 0=off 1=probe-SE0SH0 2=clear-SE0SH0 3=clear-all-SAs 4=probe-all-SAs");
|
||||
#define BC250_PCI_DEVICE_ID 0x13FE
|
||||
|
||||
ENDPARAM
|
||||
}
|
||||
|
||||
write_cc_patch() {
|
||||
cat > "$1" << 'ENDCC'
|
||||
|
||||
/* BC-250: unlock harvested CUs — CC (enumeration) + SPI (dispatch) + RLC (power) */
|
||||
if (bc250_cc_write_mode > 0 && adev->pdev->device == BC250_PCI_DEVICE_ID) {
|
||||
int bc_se, bc_sh;
|
||||
for (bc_se = 0; bc_se < adev->gfx.config.max_shader_engines; bc_se++) {
|
||||
for (bc_sh = 0; bc_sh < adev->gfx.config.max_sh_per_se; bc_sh++) {
|
||||
u32 bc_cc_orig, bc_cc_after, bc_spi_orig, bc_spi_after;
|
||||
if (bc250_cc_write_mode == 2 && (bc_se > 0 || bc_sh > 0))
|
||||
continue;
|
||||
gfx_v10_0_select_se_sh(adev, bc_se, bc_sh, 0xffffffff, 0);
|
||||
bc_cc_orig = RREG32_SOC15(GC, 0, mmCC_GC_SHADER_ARRAY_CONFIG);
|
||||
WREG32_SOC15(GC, 0, mmCC_GC_SHADER_ARRAY_CONFIG, 0);
|
||||
bc_cc_after = RREG32_SOC15(GC, 0, mmCC_GC_SHADER_ARRAY_CONFIG);
|
||||
bc_spi_orig = RREG32_SOC15(GC, 0, mmSPI_PG_ENABLE_STATIC_WGP_MASK);
|
||||
WREG32_SOC15(GC, 0, mmSPI_PG_ENABLE_STATIC_WGP_MASK, 0x1f);
|
||||
bc_spi_after = RREG32_SOC15(GC, 0, mmSPI_PG_ENABLE_STATIC_WGP_MASK);
|
||||
WREG32_SOC15(GC, 0, mmRLC_PG_ALWAYS_ON_WGP_MASK, 0x1f);
|
||||
if (bc250_cc_write_mode == 1 || bc250_cc_write_mode == 4) {
|
||||
WREG32_SOC15(GC, 0, mmCC_GC_SHADER_ARRAY_CONFIG, bc_cc_orig);
|
||||
WREG32_SOC15(GC, 0, mmSPI_PG_ENABLE_STATIC_WGP_MASK, bc_spi_orig);
|
||||
dev_info(adev->dev,
|
||||
"bc250-40cu-probe: se=%d sh=%d CC=0x%08x->0x%08x SPI=0x%08x->0x%08x (restored)",
|
||||
bc_se, bc_sh, bc_cc_orig, bc_cc_after, bc_spi_orig, bc_spi_after);
|
||||
} else {
|
||||
dev_info(adev->dev,
|
||||
"bc250-40cu-enable: mode=%d se=%d sh=%d CC=0x%08x->0x%08x SPI=0x%08x->0x%08x",
|
||||
bc250_cc_write_mode, bc_se, bc_sh,
|
||||
bc_cc_orig, bc_cc_after, bc_spi_orig, bc_spi_after);
|
||||
}
|
||||
}
|
||||
}
|
||||
gfx_v10_0_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, 0);
|
||||
}
|
||||
|
||||
ENDCC
|
||||
}
|
||||
|
||||
check_bc250() {
|
||||
if ! lspci -nn 2>/dev/null | grep -qi "${BC250_PCI_ID}"; then
|
||||
warn "No BC-250 (PCI ID 13fe) detected. This patch is BC-250 specific."
|
||||
printf "Continue anyway? [y/N] "
|
||||
read -r ans
|
||||
case "$ans" in y|Y) ;; *) exit 1 ;; esac
|
||||
fi
|
||||
}
|
||||
|
||||
check_deps() {
|
||||
local missing=""
|
||||
command -v gcc >/dev/null 2>&1 || missing="${missing} gcc"
|
||||
command -v make >/dev/null 2>&1 || missing="${missing} make"
|
||||
command -v zstd >/dev/null 2>&1 || missing="${missing} zstd"
|
||||
command -v curl >/dev/null 2>&1 || missing="${missing} curl"
|
||||
if [ ! -d "${MODDIR}/build" ]; then
|
||||
missing="${missing} linux-headers"
|
||||
fi
|
||||
if [ -n "$missing" ]; then
|
||||
err "Missing dependencies:${missing}"
|
||||
err "Install with: pacman -S base-devel zstd curl linux-headers"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
find_source() {
|
||||
local d
|
||||
# Check common source locations (including Arch /usr/src/linux)
|
||||
for d in \
|
||||
"/usr/src/linux-${KVER}" \
|
||||
"/usr/src/linux-${KVER_BASE}" \
|
||||
"/usr/src/linux" \
|
||||
"/usr/src/linux-source-${KVER_BASE}"; do
|
||||
if [ -f "$d/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c" ]; then
|
||||
MODSRC="$d"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Check for a pre-extracted tarball left from a previous build
|
||||
if [ -f "${BUILDDIR}/src/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c" ]; then
|
||||
MODSRC="${BUILDDIR}/src"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Download minimal amdgpu subtree directly from kernel.org
|
||||
local major="${KVER_BASE%%.*}"
|
||||
local url="https://cdn.kernel.org/pub/linux/kernel/v${major}.x/linux-${KVER_BASE}.tar.xz"
|
||||
info "Kernel source not found locally."
|
||||
info "Downloading amdgpu source from kernel.org (~120 MB)..."
|
||||
info " ${url}"
|
||||
|
||||
mkdir -p "${BUILDDIR}/src"
|
||||
if curl -fL --progress-bar "$url" | \
|
||||
tar xJ -C "${BUILDDIR}/src" --strip-components=1 \
|
||||
--wildcards \
|
||||
'*/drivers/gpu/drm/amd/' \
|
||||
'*/include/drm/' \
|
||||
'*/include/uapi/drm/' \
|
||||
2>/dev/null; then
|
||||
if [ -f "${BUILDDIR}/src/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c" ]; then
|
||||
MODSRC="${BUILDDIR}/src"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
die "Cannot find kernel source for ${KVER_BASE}.
|
||||
Option 1: pacman -S asp && asp checkout linux (then makepkg -o)
|
||||
Option 2: place extracted source at /usr/src/linux-${KVER_BASE}"
|
||||
}
|
||||
|
||||
patch_source() {
|
||||
local gfx="${MODSRC}/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c"
|
||||
[ -f "$gfx" ] || die "gfx_v10_0.c not found at ${gfx}"
|
||||
|
||||
if grep -q 'bc250_cc_write_mode' "$gfx"; then
|
||||
info "Source already patched."
|
||||
return 0
|
||||
fi
|
||||
|
||||
info "Patching gfx_v10_0.c..."
|
||||
cp "$gfx" "${gfx}.orig"
|
||||
|
||||
# Step 1: insert module parameter before '#include "amdgpu.h"'
|
||||
if ! grep -q '#include "amdgpu.h"' "$gfx"; then
|
||||
die "Cannot find anchor: #include amdgpu.h"
|
||||
fi
|
||||
|
||||
local param_file
|
||||
param_file="$(mktemp)"
|
||||
write_param_patch "$param_file"
|
||||
sed -i "/#include \"amdgpu.h\"/r ${param_file}" "$gfx"
|
||||
rm -f "$param_file"
|
||||
|
||||
# Step 2: insert CC write block in gfx_v10_0_get_cu_info after mutex_lock
|
||||
local cc_file
|
||||
cc_file="$(mktemp)"
|
||||
write_cc_patch "$cc_file"
|
||||
|
||||
# Two-phase awk: avoid matching the forward declaration of gfx_v10_0_get_cu_info.
|
||||
# A forward declaration ends with "); " on a later line, while the actual body
|
||||
# starts with a standalone "{" on its own line right after the signature.
|
||||
awk -v insertfile="$cc_file" '
|
||||
/static.*gfx_v10_0_get_cu_info/ { maybe_func = 1 }
|
||||
maybe_func && /;/ { maybe_func = 0 }
|
||||
maybe_func && /^\{/ { in_cu_info = 1; maybe_func = 0 }
|
||||
in_cu_info && /mutex_lock/ && !inserted {
|
||||
print
|
||||
while ((getline line < insertfile) > 0) print line
|
||||
close(insertfile)
|
||||
inserted = 1
|
||||
next
|
||||
}
|
||||
{ print }
|
||||
' "$gfx" > "${gfx}.new"
|
||||
|
||||
if grep -q 'bc250-40cu-enable' "${gfx}.new"; then
|
||||
mv "${gfx}.new" "$gfx"
|
||||
rm -f "$cc_file"
|
||||
info "Patch applied successfully."
|
||||
else
|
||||
rm -f "${gfx}.new" "$cc_file"
|
||||
mv "${gfx}.orig" "$gfx"
|
||||
die "Failed to insert CC write block. Kernel source layout may differ."
|
||||
fi
|
||||
}
|
||||
|
||||
build_module() {
|
||||
local amdgpu_dir="${MODSRC}/drivers/gpu/drm/amd/amdgpu"
|
||||
[ -d "$amdgpu_dir" ] || die "amdgpu source directory not found"
|
||||
|
||||
# define_trace.h (in the kernel headers) resolves the trace header as:
|
||||
# ../../drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
|
||||
# relative to its own location, ending up at:
|
||||
# ${kbuild}/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
|
||||
# That directory already exists in linux-headers (contains only Kconfig),
|
||||
# so we copy the trace header there temporarily for the build.
|
||||
local kbuild="${MODDIR}/build"
|
||||
local kbuild_amdgpu="${kbuild}/drivers/gpu/drm/amd/amdgpu"
|
||||
local trace_dst="${kbuild_amdgpu}/amdgpu_trace.h"
|
||||
local trace_copied=0
|
||||
if [ ! -f "$trace_dst" ]; then
|
||||
mkdir -p "$kbuild_amdgpu"
|
||||
cp "${amdgpu_dir}/amdgpu_trace.h" "$trace_dst"
|
||||
trace_copied=1
|
||||
fi
|
||||
|
||||
info "Building amdgpu module for kernel ${KVER} (2-5 min)..."
|
||||
make -C "$kbuild" M="$amdgpu_dir" -j"$(nproc)" modules 2>&1 | tail -10 >&2
|
||||
local make_rc=${PIPESTATUS[0]}
|
||||
|
||||
[ "$trace_copied" -eq 1 ] && rm -f "$trace_dst"
|
||||
|
||||
[ "$make_rc" -eq 0 ] || die "Build failed (make exited $make_rc)"
|
||||
|
||||
local built="${amdgpu_dir}/amdgpu.ko"
|
||||
[ -f "$built" ] || die "Build failed - amdgpu.ko not produced"
|
||||
|
||||
# Use grep -qa to avoid SIGPIPE/pipefail issue with `strings | grep -q` on large .ko files
|
||||
if ! grep -qa 'bc250_cc_write_mode' "$built"; then
|
||||
die "Built module missing bc250_cc_write_mode - patch failed"
|
||||
fi
|
||||
|
||||
info "Build successful: ${built} ($(du -h "$built" | cut -f1))"
|
||||
echo "$built"
|
||||
}
|
||||
|
||||
install_module() {
|
||||
local built="$1"
|
||||
local target="${MODPATH}"
|
||||
|
||||
if [ -f "${target}.zst" ]; then
|
||||
target="${target}.zst"
|
||||
elif [ ! -f "$target" ]; then
|
||||
target="${target}.zst"
|
||||
fi
|
||||
|
||||
if [ -f "$target" ] && [ ! -f "${target}${BACKUP_SUFFIX}" ]; then
|
||||
info "Backing up original to ${target}${BACKUP_SUFFIX}"
|
||||
cp "$target" "${target}${BACKUP_SUFFIX}"
|
||||
fi
|
||||
|
||||
if [ "${target%.zst}" != "$target" ]; then
|
||||
info "Compressing and installing module..."
|
||||
zstd -f "$built" -o "$target"
|
||||
else
|
||||
cp "$built" "$target"
|
||||
fi
|
||||
|
||||
depmod -a "$KVER"
|
||||
info "Module installed at ${target}"
|
||||
}
|
||||
|
||||
do_build() {
|
||||
check_bc250
|
||||
check_deps
|
||||
find_source
|
||||
patch_source
|
||||
local built
|
||||
built="$(build_module)"
|
||||
install_module "$built"
|
||||
echo ""
|
||||
info "Done! Patched amdgpu module installed."
|
||||
info "Next: sudo $0 enable"
|
||||
}
|
||||
|
||||
do_enable() {
|
||||
printf '# BC-250 40 CU re-enablement\noptions amdgpu bc250_cc_write_mode=3\n' > "$CONF40"
|
||||
info "40 CU mode configured in ${CONF40}"
|
||||
if ! ( set +o pipefail; modinfo amdgpu 2>/dev/null | grep -q 'bc250_cc_write_mode' ); then
|
||||
warn "Patched module not detected. Run: sudo $0 build"
|
||||
rm -f "$CONF40"
|
||||
exit 1
|
||||
fi
|
||||
info "Rebooting..."
|
||||
sleep 2
|
||||
reboot
|
||||
}
|
||||
|
||||
do_disable() {
|
||||
rm -f "$CONF40"
|
||||
info "40 CU config removed. Rebooting to stock 24 CU..."
|
||||
sleep 2
|
||||
reboot
|
||||
}
|
||||
|
||||
do_restore() {
|
||||
local target="${MODPATH}"
|
||||
if [ -f "${target}.zst" ]; then target="${target}.zst"; fi
|
||||
local backup
|
||||
backup="$(ls -1 "${target}.bc250-backup-"* 2>/dev/null | head -1)"
|
||||
[ -n "$backup" ] || die "No backup found"
|
||||
cp "$backup" "$target"
|
||||
rm -f "$CONF40"
|
||||
depmod -a "$KVER"
|
||||
info "Original module restored. Reboot to apply."
|
||||
}
|
||||
|
||||
do_status() {
|
||||
printf '\033[1m=== BC-250 CU Status ===\033[0m\n\n'
|
||||
|
||||
if lspci -nn 2>/dev/null | grep -qi "${BC250_PCI_ID}"; then
|
||||
printf ' PCI device: \033[0;32mBC-250 detected\033[0m\n'
|
||||
else
|
||||
printf ' PCI device: \033[0;31mBC-250 not found\033[0m\n'
|
||||
fi
|
||||
|
||||
if ( set +o pipefail; modinfo amdgpu 2>/dev/null | grep -q 'bc250_cc_write_mode' ); then
|
||||
printf ' amdgpu module: \033[0;32mpatched\033[0m\n'
|
||||
else
|
||||
printf ' amdgpu module: \033[0;33mstock (unpatched)\033[0m\n'
|
||||
fi
|
||||
|
||||
local mode
|
||||
mode="$(cat /sys/module/amdgpu/parameters/bc250_cc_write_mode 2>/dev/null || echo 'N/A')"
|
||||
printf ' write_mode: %s\n' "$mode"
|
||||
|
||||
local cu_line
|
||||
cu_line="$(dmesg 2>/dev/null | grep 'active_cu_number' | tail -1)"
|
||||
if [ -n "$cu_line" ]; then
|
||||
local cus
|
||||
cus="$(echo "$cu_line" | grep -o 'active_cu_number [0-9]*' | awk '{print $2}')"
|
||||
if [ "$cus" = "40" ]; then
|
||||
printf ' active CUs: \033[0;32m\033[1m40\033[0m (full die)\n'
|
||||
elif [ "$cus" = "24" ]; then
|
||||
printf ' active CUs: \033[0;33m24\033[0m (stock)\n'
|
||||
else
|
||||
printf ' active CUs: %s\n' "$cus"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f "$CONF40" ]; then
|
||||
printf ' modprobe conf: \033[0;32m%s (40 CU enabled)\033[0m\n' "$CONF40"
|
||||
else
|
||||
printf ' modprobe conf: (none - stock mode)\n'
|
||||
fi
|
||||
echo ""
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
build) do_build ;;
|
||||
enable) do_enable ;;
|
||||
disable) do_disable ;;
|
||||
restore) do_restore ;;
|
||||
status) do_status ;;
|
||||
*)
|
||||
echo "BC-250 40 CU Re-enablement Tool (Arch Linux)"
|
||||
echo ""
|
||||
echo "Usage: sudo $0 <command>"
|
||||
echo ""
|
||||
echo " build Patch, compile, install patched amdgpu (~5 min)"
|
||||
echo " enable Activate 40 CU mode and reboot"
|
||||
echo " disable Return to stock 24 CU and reboot"
|
||||
echo " status Show current CU state"
|
||||
echo " restore Restore original amdgpu module"
|
||||
echo ""
|
||||
echo "Quick start:"
|
||||
echo " sudo $0 build && sudo $0 enable"
|
||||
echo ""
|
||||
echo "Dependencies: pacman -S base-devel zstd curl linux-headers"
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user