Skip to content

Commit 872d188

Browse files
Fix: EasePi-A2 Boot & Ethernet on Vendor Kernel (#9946)
* Add jellyfin-ffmpeg release constraints and ip-wrapper for easepi-r2 * Update config/boards/easepi-r2.conf Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix(easepi-a2): add extensions for U-Boot FIT FDT dependency and RTL8125B Ethernet Add two board-specific extensions for EasePi-A2 and move their enablement from main-config.sh to the board configuration file, following the established Armbian pattern (e.g., radxa-aic8800, bluetooth-hciattach, watchdog). 1. uboot-makefile-fix-itb-deps.sh Fixes a race condition in U-Boot parallel builds where u-boot.itb lacks u-boot.dtb as a dependency. When mkfitimage runs before u-boot.dtb is copied, the FDT segment in the FIT image is empty, causing "No valid device tree binary found" at boot. The extension patches the Makefile to add u-boot.dtb to u-boot.itb's dependency list via a pre_config_uboot_target hook. Uses multi-layer guards (bash fast pre-checks + Python multi-line regex matching) for idempotency and compatibility with both Radxa fork (single-line) and upstream (multi-line continuation) Makefile formats. 2. r8125-dkms.sh Fixes RTL8125B (XID 641) Ethernet on vendor kernel (6.1.115). The in-kernel r8169 driver has a TX path bug that causes DHCPv4 and all L2 TX to fail. This extension installs the official Realtek r8125 driver (v9.016.01) via DKMS and blacklists r8169. Only enabled when BRANCH=vendor. Source is pre-downloaded on the host side (extension_finish_config hook) and copied into chroot during post_install_kernel_debs. 3. config/boards/easepi-a2.conf Enable both extensions at the top level of the board config, keeping board-specific logic self-contained and main-config.sh clean. r8125-dkms is conditionally enabled only for vendor branch. Build-tested with easepi-a2 vendor branch minimal image. * Update extensions/r8125-dkms.sh Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix(easepi-a2): add extensions for U-Boot FIT FDT dependency and RTL8125B Ethernet Add two board-specific extensions for EasePi-A2 and move their enablement from main-config.sh to the board configuration file, following the established Armbian pattern (e.g., radxa-aic8800, bluetooth-hciattach, watchdog). 1. uboot-makefile-fix-itb-deps.sh Fixes a race condition in U-Boot parallel builds where u-boot.itb lacks u-boot.dtb as a dependency. When mkfitimage runs before u-boot.dtb is copied, the FDT segment in the FIT image is empty, causing "No valid device tree binary found" at boot. The extension patches the Makefile to add u-boot.dtb to u-boot.itb's dependency list via a pre_config_uboot_target hook. Uses multi-layer guards (bash fast pre-checks + Python multi-line regex matching) for idempotency and compatibility with both Radxa fork (single-line) and upstream (multi-line continuation) Makefile formats. 2. r8125-dkms.sh Fixes RTL8125B (XID 641) Ethernet on vendor kernel (6.1.115). The in-kernel r8169 driver has a TX path bug that causes DHCPv4 and all L2 TX to fail. This extension installs the official Realtek r8125 driver (v9.016.01) via DKMS and blacklists r8169. Only enabled when BRANCH=vendor. Source is pre-downloaded on the host side (extension_finish_config hook) and copied into chroot during post_install_kernel_debs. Uses IMAGE_INSTALLED_KERNEL_VERSION combined with BRANCH and LINUXFAMILY to construct the full kernel version string for DKMS -k parameter. 3. config/boards/easepi-a2.conf Enable both extensions at the top level of the board config, keeping board-specific logic self-contained and main-config.sh clean. r8125-dkms is conditionally enabled only for vendor branch. Build-tested with easepi-a2 vendor branch minimal image. * r8125-dkms: Use curl instead of wget for source download --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent 7d26def commit 872d188

3 files changed

Lines changed: 175 additions & 1 deletion

File tree

config/boards/easepi-a2.conf

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,17 @@ BOOT_SCENARIO="spl-blobs"
1414
IMAGE_PARTITION_TABLE="gpt"
1515
PACKAGE_LIST_BOARD="i2c-tools fonts-dejavu-core rfkill bluetooth bluez bluez-tools ir-keytable"
1616

17+
# Fix u-boot.itb missing u-boot.dtb dependency. Can be removed when
18+
# all U-Boot versions have the dependency fixed upstream.
19+
enable_extension "uboot-makefile-fix-itb-deps"
20+
21+
# Fix RTL8125B Ethernet on vendor kernel. The in-kernel r8169 driver
22+
# has a TX path bug with RTL8125B (XID 641). Replace with official
23+
# Realtek r8125 DKMS driver and blacklist r8169.
24+
if [[ "${BRANCH}" == "vendor" ]]; then
25+
enable_extension "r8125-dkms"
26+
fi
27+
1728
# ==================== uboot config ====================
1829
function post_family_config__easepi_a2_use_mainline_uboot_except_vendor() {
1930
if [[ "${BRANCH}" == "vendor" ]]; then
@@ -179,7 +190,7 @@ function post_family_tweaks_bsp__easepi_a2_install_eth_files() {
179190
install -D -m 0644 "${SRC}/packages/bsp/easepi/easepi-a2/71-net.rules" \
180191
"${destination}/etc/udev/rules.d/71-net.rules"
181192
}
182-
193+
# ==================== Jellyfin FFMPEG Module ====================
183194
function custom_apt_repo__add_jellyfin-ffmpeg-repo() {
184195
[[ "${CUSTOM_REPO_WHEN}" = "image-early" && "${BRANCH}" == "vendor" && "${RELEASE}" =~ ^(bookworm|trixie|jammy|noble)$ ]] || return 0
185196
display_alert "Preparing jellyfin ffmpeg repository..." "EasePi-A2" "info"

extensions/r8125-dkms.sh

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
# Copyright (c) 2026 ifroncy01
3+
#
4+
# Realtek RTL8125B DKMS driver for EasePi-A2 (rk35xx vendor kernel)
5+
#
6+
# The in-kernel r8169 driver on vendor kernel 6.1.115 has a TX path bug
7+
# with RTL8125B (XID 641), causing DHCPv4 and all L2 TX to fail.
8+
# This extension replaces r8169 with the official Realtek r8125 driver
9+
# (v9.016.01) via DKMS, and blacklists r8169.
10+
#
11+
# Only enabled for the vendor branch on easepi-a2 board.
12+
13+
function extension_finish_config__install_r8125_dkms() {
14+
if [[ "${KERNEL_HAS_WORKING_HEADERS}" != "yes" ]]; then
15+
display_alert "Kernel version has no working headers package" "skipping r8125 dkms for kernel v${KERNEL_MAJOR_MINOR}" "warn"
16+
return 0
17+
fi
18+
declare -g INSTALL_HEADERS="yes"
19+
display_alert "Forcing INSTALL_HEADERS=yes; for use with r8125 dkms" "${EXTENSION}" "debug"
20+
21+
# Pre-download r8125 DKMS source on the host side (which has direct GitHub access).
22+
# The Docker container may not have direct GitHub access (e.g. when using ghproxy).
23+
local r8125_cache_dir="${SRC}/cache/r8125-dkms"
24+
local r8125_tarball_url="https://github.com/awesometic/realtek-r8125-dkms/archive/refs/heads/master.tar.gz"
25+
26+
if [[ ! -f "${r8125_cache_dir}/source.tar.gz" ]]; then
27+
display_alert "Downloading r8125 DKMS source" "${r8125_tarball_url}" "info"
28+
run_host_command_logged mkdir -p "${r8125_cache_dir}"
29+
run_host_command_logged curl -fsSL --progress-bar "${r8125_tarball_url}" -o "${r8125_cache_dir}/source.tar.gz"
30+
fi
31+
}
32+
33+
function post_install_kernel_debs__install_r8125_dkms_package() {
34+
[[ "${INSTALL_HEADERS}" != "yes" ]] || [[ "${KERNEL_HAS_WORKING_HEADERS}" != "yes" ]] && return 0
35+
36+
display_alert "Installing Realtek r8125 DKMS driver for RTL8125B" "${EXTENSION}" "info"
37+
38+
# Install DKMS in the chroot
39+
use_clean_environment="yes" chroot_sdcard_apt_get_install "dkms"
40+
41+
# Copy pre-downloaded r8125 source into the chroot
42+
local r8125_cache_dir="${SRC}/cache/r8125-dkms"
43+
cp "${r8125_cache_dir}/source.tar.gz" "${SDCARD}/tmp/r8125.tar.gz"
44+
45+
# Extract r8125 source into /usr/src/r8125-9.016.01
46+
use_clean_environment="yes" chroot_sdcard "mkdir -p /usr/src/r8125-9.016.01"
47+
use_clean_environment="yes" chroot_sdcard "tar -xzf /tmp/r8125.tar.gz -C /tmp/"
48+
use_clean_environment="yes" chroot_sdcard "cp -a /tmp/realtek-r8125-dkms-master/. /usr/src/r8125-9.016.01/"
49+
use_clean_environment="yes" chroot_sdcard "rm -rf /tmp/r8125.tar.gz /tmp/realtek-r8125-dkms-master"
50+
51+
# Build and install the kernel module via DKMS
52+
declare -ag if_error_find_files_sdcard=("/var/lib/dkms/r8125*/*/build/*.log")
53+
display_alert "Building r8125 kernel module via DKMS" "${EXTENSION}" "info"
54+
55+
# Build the full target kernel version string
56+
# IMAGE_INSTALLED_KERNEL_VERSION provides the base version (e.g., "6.1.115")
57+
# We need to append BRANCH and LINUXFAMILY for the full version (e.g., "6.1.115-vendor-rk35xx")
58+
local target_kver="${IMAGE_INSTALLED_KERNEL_VERSION}-${BRANCH}-${LINUXFAMILY}"
59+
if [[ -z "${target_kver}" ]]; then
60+
display_alert "Cannot determine target kernel version" "r8125 DKMS build skipped" "warn"
61+
return 0
62+
fi
63+
display_alert "Target kernel version for DKMS" "${target_kver}" "debug"
64+
65+
use_clean_environment="yes" chroot_sdcard "dkms add -m r8125 -v 9.016.01"
66+
use_clean_environment="yes" chroot_sdcard "dkms build -m r8125 -v 9.016.01 -k ${target_kver}"
67+
use_clean_environment="yes" chroot_sdcard "dkms install -m r8125 -v 9.016.01 -k ${target_kver}"
68+
69+
# Blacklist the in-kernel r8169 driver so r8125 takes over
70+
use_clean_environment="yes" chroot_sdcard "echo 'blacklist r8169' > /etc/modprobe.d/blacklist-r8169.conf"
71+
72+
display_alert "r8125 DKMS driver installed, r8169 blacklisted" "${EXTENSION}" "info"
73+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#!/usr/bin/env bash
2+
#
3+
# SPDX-License-Identifier: GPL-2.0
4+
#
5+
# Copyright (c) 2013-2026 Igor Pecovnik, igor@armbian.com
6+
#
7+
# This file is a part of the Armbian Build Framework
8+
# https://github.com/armbian/build/
9+
#
10+
# Fix u-boot.itb missing dependency on u-boot.dtb.
11+
#
12+
# Background:
13+
# The FIT image generation script (arch/arm/mach-rockchip/make_fit_atf.sh)
14+
# references ./u-boot.dtb for the FDT node via /incbin/("./u-boot.dtb").
15+
# However, the u-boot.itb Makefile rule only depends on dts/dt.dtb, not
16+
# on u-boot.dtb (which is a separate copy target). With parallel make (-j),
17+
# this creates a race condition: mkfitimage may run before u-boot.dtb is
18+
# copied from dts/dt.dtb, resulting in a zero-size FDT in the FIT image.
19+
#
20+
# Affected U-Boot versions:
21+
# - Radxa fork (next-dev-v2024.10): single-line rule
22+
# - Mainline U-Boot (v2025.10): multi-line rule with \ continuations
23+
#
24+
# Fix:
25+
# Add u-boot.dtb as an explicit prerequisite of u-boot.itb, ensuring
26+
# the copy completes before the FIT image is assembled.
27+
#
28+
# This hook is safe for all U-Boot versions: it only patches when the
29+
# problematic rule exists and u-boot.dtb is not already a dependency.
30+
31+
function pre_config_uboot_target__fix_itb_dtb_dependency() {
32+
# Guard 1: skip if the Makefile has no u-boot.itb target at all
33+
if ! grep -q '^u-boot\.itb:' Makefile; then
34+
return 0
35+
fi
36+
37+
# Guard 2: skip if u-boot.dtb is already listed as a dependency
38+
if grep -q 'u-boot\.itb:.*u-boot\.dtb' Makefile; then
39+
return 0
40+
fi
41+
42+
display_alert "Patching Makefile" "adding u-boot.dtb as u-boot.itb dependency" "info"
43+
44+
# Use Python for robust multi-line matching.
45+
# Handles both single-line (Radxa fork) and multi-line continuation
46+
# (upstream v2025.10) formats of the u-boot.itb rule.
47+
python3 << 'PYTHON_SCRIPT'
48+
import re
49+
import sys
50+
51+
with open("Makefile", "r") as f:
52+
content = f.read()
53+
54+
# Match the u-boot.itb rule from its declaration to the terminating FORCE.
55+
# - ^u-boot\.itb: start of the rule line
56+
# - [\s\S]*? shortest match across lines (non-greedy)
57+
# - \bFORCE\s*$ FORCE at end of a line (may be on continuation line)
58+
# re.MULTILINE: ^ and $ match start/end of each line
59+
pattern = r'(^u-boot\.itb:[\s\S]*?\bFORCE\s*$)'
60+
match = re.search(pattern, content, re.MULTILINE)
61+
62+
if not match:
63+
print("u-boot.itb rule not found or unexpected format, skipping patch")
64+
sys.exit(0)
65+
66+
rule_text = match.group(1)
67+
68+
# Skip if already patched (double-check inside the matched rule)
69+
if "u-boot.dtb" in rule_text:
70+
print("u-boot.dtb already in u-boot.itb dependencies, skipping")
71+
sys.exit(0)
72+
73+
# Insert "u-boot.dtb " before FORCE at the end of the rule
74+
new_rule = re.sub(r'\bFORCE\s*$', r'u-boot.dtb FORCE', rule_text, count=1)
75+
76+
if new_rule == rule_text:
77+
print("Failed to insert u-boot.dtb dependency, skipping")
78+
sys.exit(0)
79+
80+
# Replace the old rule with the patched rule in the full content
81+
content = content[:match.start()] + new_rule + content[match.end():]
82+
83+
with open("Makefile", "w") as f:
84+
f.write(content)
85+
86+
print("Makefile patched: u-boot.dtb added as u-boot.itb dependency")
87+
PYTHON_SCRIPT
88+
89+
display_alert "Makefile patched" "u-boot.dtb added as u-boot.itb dependency" "info"
90+
}

0 commit comments

Comments
 (0)