From 1673962f39927fdf4c0816bcde9fb60b0bf997a6 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sun, 26 Oct 2025 20:19:57 +0200 Subject: [PATCH 1/2] tests: dt_binding_check: new test We currently "rely" on Rob Herring's mail bot to provide sanity checking on patches that touch device tree bindings: https://lore.kernel.org/netdev/176134124286.2841725.8990137232361008022.robh@kernel.org and that is sufficient in "public" settings (patches sent to netdev@vger.kernel.org and devicetree@vger.kernel.org also copied). But in "private" settings (i.e. individual developers encouraged to do sanity checking on their own, for example by running ingest_mdir), something that replicates Rob's mail bot is still required: https://gitlab.com/robherring/dt-review-ci/ https://gitlab.com/robherring/pw-utils The justification for including it in NIPA is that while device tree maintainers review binding patches, they get applied to the subsystem tree (in this case netdev). In terms of implementation, "make dt_binding_check" does not always nicely print "error" or "warning" on the lines with issues. Furthermore, the errors are multi-line. The "normal" lines contain things such as "make", "SCHEMA", "CHKDT", "LINT", "DTEX", "DTC" at the beginning. Instead of detecting all 'normal' lines to filter them out, we just use 'make -s' which suppresses them, and leaves only the error messages. Signed-off-by: Vladimir Oltean --- .../dt_binding_check/dt_binding_check.sh | 81 +++++++++++++++++++ tests/patch/dt_binding_check/info.json | 3 + 2 files changed, 84 insertions(+) create mode 100755 tests/patch/dt_binding_check/dt_binding_check.sh create mode 100644 tests/patch/dt_binding_check/info.json diff --git a/tests/patch/dt_binding_check/dt_binding_check.sh b/tests/patch/dt_binding_check/dt_binding_check.sh new file mode 100755 index 0000000..a9f037f --- /dev/null +++ b/tests/patch/dt_binding_check/dt_binding_check.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright 2025-2026 NXP + +HEAD=$(git rev-parse HEAD) +ncpu=$(grep -c processor /proc/cpuinfo) +rc=0 + +pr() { + echo " ====== $* ======" | tee -a /dev/stderr +} + +build() { + make -s -j $ncpu DT_CHECKER_FLAGS=-m dt_binding_check 2>&1 +} + +# Only run this check if the patch touches DT binding files. +if ! git show --diff-filter=AM --pretty="" --name-only "${HEAD}" | \ + grep -q -E "^Documentation/devicetree/bindings/" +then + echo "No DT binding files touched, skip" >&"$DESC_FD" + exit 0 +fi + +# Create temporary files for logs +tmpfile_o_raw=$(mktemp) +tmpfile_n_raw=$(mktemp) +tmp_new_issues=$(mktemp) + +echo "Tree base:" +git log -1 --pretty='%h ("%s")' HEAD~ +echo "Now at:" +git log -1 --pretty='%h ("%s")' HEAD + +pr "Checking before the patch" +git checkout -q HEAD~ + +# Run the check on the parent commit +(build | tee -a "$tmpfile_o_raw") || true + +# Sort the output +sort "$tmpfile_o_raw" > "${tmpfile_o_raw}.sorted" +mv "${tmpfile_o_raw}.sorted" "$tmpfile_o_raw" +incumbent_total=$(wc -l < "$tmpfile_o_raw") + +pr "Checking the tree with the patch" +git checkout -q "$HEAD" + +# Run the check on the new commit +(build | tee -a "$tmpfile_n_raw") || true + +# Sort the output +sort "$tmpfile_n_raw" > "${tmpfile_n_raw}.sorted" +mv "${tmpfile_n_raw}.sorted" "$tmpfile_n_raw" +current_total=$(wc -l < "$tmpfile_n_raw") + +# Compare the lists to find new and fixed issues +# Use comm to find fixed issues (lines only in the old log, column 1). +fixed_issues_count=$(comm -23 "$tmpfile_o_raw" "$tmpfile_n_raw" | wc -l) + +# Use comm to find new issues (lines only in the new log, column 2) +# and save them for later display. +comm -13 "$tmpfile_o_raw" "$tmpfile_n_raw" > "$tmp_new_issues" +new_issues_count=$(wc -l < "$tmp_new_issues") + +echo "Issues before: $incumbent_total, after: $current_total" \ + "(Fixed: $fixed_issues_count, New: $new_issues_count)" >&"$DESC_FD" + +if [ "$new_issues_count" -gt 0 ]; then + echo "New issues added:" 1>&2 + # Print the new issues we saved + cat "$tmp_new_issues" 1>&2 + rc=1 +elif [ "$fixed_issues_count" -gt 0 ]; then + echo "Patch fixed $fixed_issues_count issue(s)." >&2 + # No new issues, and some were fixed. This is a success. +fi + +rm "$tmpfile_o_raw" "$tmpfile_n_raw" "$tmp_new_issues" + +exit $rc diff --git a/tests/patch/dt_binding_check/info.json b/tests/patch/dt_binding_check/info.json new file mode 100644 index 0000000..9aaf3aa --- /dev/null +++ b/tests/patch/dt_binding_check/info.json @@ -0,0 +1,3 @@ +{ + "run": ["dt_binding_check.sh"] +} From 0b1d3b61f36fa8497ab919b90e9613f8236b36d4 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Fri, 14 Nov 2025 23:09:39 +0200 Subject: [PATCH 2/2] tests: dtbs_check: new test The idea is that subsystems (i.e. netdev) apply dt-binding patches, but those can introduce warnings in existing device trees. So we need a check. The trouble is that NIPA builds only for the host architecture (x86_64) whereas device trees are for lots of other architectures. The kernel build technically requires a cross-compilation toolchain, but "make dtbs" technically doesn't cross-compile anything. We just need the C preprocessor (gcc -E). This is a bit of a hack, but to get each and every architecture to compile, we use exclusively the host gcc and set up arch-specific 'shims' for it (which disregard options that the host gcc doesn't understand). Signed-off-by: Vladimir Oltean --- tests/patch/dtbs_check/dtbs_check.sh | 185 +++++++++++++++++++++++++++ tests/patch/dtbs_check/info.json | 3 + 2 files changed, 188 insertions(+) create mode 100755 tests/patch/dtbs_check/dtbs_check.sh create mode 100644 tests/patch/dtbs_check/info.json diff --git a/tests/patch/dtbs_check/dtbs_check.sh b/tests/patch/dtbs_check/dtbs_check.sh new file mode 100755 index 0000000..ded3c45 --- /dev/null +++ b/tests/patch/dtbs_check/dtbs_check.sh @@ -0,0 +1,185 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright 2025-2026 NXP + +HEAD=$(git rev-parse HEAD) +nproc=$(grep -c processor /proc/cpuinfo) +build_flags="-j $nproc" +rc=0 + +architectures=( + "arc" \ + "arm" \ + "arm64" \ + "csky" \ + "loongarch" \ + "microblaze" \ + "mips" \ + "nios2" \ + "openrisc" \ + "powerpc" \ + "riscv" \ + "sh" \ + "xtensa" \ +) + +pr() { + echo " ====== $* ======" | tee -a /dev/stderr +} + +# "make dtbs" will fail on many archs during the syncconfig stage, where it +# tries to probe the cross-compiler version. We don't actually need any +# cross-compilation feature, the host gcc could in principle handle everything +# as long as we filter out arch-specific flags. +setup_shims() { + local shims_dir="$1" + + mkdir -p "$shims_dir" + + cat > "$shims_dir/gcc" << 'EOF' +#!/bin/bash +args=() +skip_next=false +for arg in "$@"; do + if [[ "$skip_next" == "true" ]]; then + skip_next=false + continue + fi + case "$arg" in + -mdiv|-mno-stack-size|-mhard-float|-msoft-float|-mcpu=*|-march=*|-mtune=*|\ + -mmedium-calls|-mlock|-mswape|-munaligned-access|-mno-sdata|-mbig-endian|\ + -mabi=*|-mcmodel=*|-G|-mno-abicalls|-EB|0) + ;; + *) + args+=("$arg") + ;; + esac +done +exec /usr/bin/gcc "${args[@]}" +EOF + + chmod +x "$shims_dir/gcc" + + # Special case for xtensa + ln -s $(which gcc) "$shims_dir/xtensa_fsf-gcc" + ln -s "$(which ld)" "$shims_dir/xtensa_fsf-ld" +} + +prep_config() { + local arch=$1 + local output_dir=$2 + local shims_dir=$3 + PATH="$shims_dir:$PATH" make ARCH=$arch O=$output_dir allmodconfig $build_flags +} + +build() { + local arch=$1 + local output_dir=$2 + local shims_dir=$3 + PATH="$shims_dir:$PATH" make -s ARCH=$arch O=$output_dir $build_flags DT_CHECKER_FLAGS=-m CHECK_DT_BINDING=y dtbs 2>&1 +} + +clean_build() { + local output_dir=$1 + rm -rf "$output_dir" +} + +schema_modified=false +if git show --diff-filter=AM --pretty="" --name-only "${HEAD}" | \ + grep -q -E "^Documentation/devicetree/bindings/" +then + schema_modified=true +fi + +touched_archs=() +for arch in "${architectures[@]}"; do + if git show --diff-filter=AM --pretty="" --name-only "${HEAD}" | \ + grep -q -E "^arch/${arch}/boot/dts/" + then + touched_archs+=("$arch") + fi +done + +test_archs=() +if [ "$schema_modified" = true ]; then + test_archs=("${architectures[@]}") + echo "DT schema files modified, testing all architectures" >&"$DESC_FD" +elif [ ${#touched_archs[@]} -gt 0 ]; then + test_archs=("${touched_archs[@]}") + echo "DTS files touched for architectures: ${test_archs[*]}" >&"$DESC_FD" +else + echo "No DT schema or DTS files touched, skip" >&"$DESC_FD" + exit 0 +fi + +echo "Tree base:" +git log -1 --pretty='%h ("%s")' HEAD~ +echo "Now at:" +git log -1 --pretty='%h ("%s")' HEAD + +# Set up compiler shims +shims_dir="$PWD/shims" +setup_shims "$shims_dir" + +for arch in "${test_archs[@]}"; do + output_dir="build_dtbs_check_${arch}/" + + tmpfile_o_raw=$(mktemp) + tmpfile_n_raw=$(mktemp) + tmp_new_issues=$(mktemp) + + pr "Checking $arch before the patch" + git checkout -q HEAD~ + + # Prepare config and run the check on the parent commit + clean_build "$output_dir" + prep_config "$arch" "$output_dir" "$shims_dir" + (build "$arch" "$output_dir" "$shims_dir" | tee -a "$tmpfile_o_raw") || true + + # Sort the output + sort "$tmpfile_o_raw" > "${tmpfile_o_raw}.sorted" + mv "${tmpfile_o_raw}.sorted" "$tmpfile_o_raw" + incumbent_total=$(wc -l < "$tmpfile_o_raw") + + pr "Checking $arch with the patch" + git checkout -q "$HEAD" + + # Prepare config and run the check on the new commit + clean_build "$output_dir" + prep_config "$arch" "$output_dir" "$shims_dir" + (build "$arch" "$output_dir" "$shims_dir" | tee -a "$tmpfile_n_raw") || true + + # Sort the output + sort "$tmpfile_n_raw" > "${tmpfile_n_raw}.sorted" + mv "${tmpfile_n_raw}.sorted" "$tmpfile_n_raw" + current_total=$(wc -l < "$tmpfile_n_raw") + + # Compare the lists to find new and fixed issues + # Use comm to find fixed issues (lines only in the old log, column 1). + fixed_issues_count=$(comm -23 "$tmpfile_o_raw" "$tmpfile_n_raw" | wc -l) + + # Use comm to find new issues (lines only in the new log, column 2) + # and save them for later display. + comm -13 "$tmpfile_o_raw" "$tmpfile_n_raw" > "$tmp_new_issues" + new_issues_count=$(wc -l < "$tmp_new_issues") + + echo "[$arch] Issues before: $incumbent_total, after: $current_total" \ + "(Fixed: $fixed_issues_count, New: $new_issues_count)" >&"$DESC_FD" + + if [ "$new_issues_count" -gt 0 ]; then + echo "[$arch] New issues added:" 1>&2 + # Print the new issues we saved + cat "$tmp_new_issues" 1>&2 + rc=1 + elif [ "$fixed_issues_count" -gt 0 ]; then + echo "[$arch] Patch fixed $fixed_issues_count issue(s)." >&2 + # No new issues, and some were fixed. This is a success. + fi + + rm "$tmpfile_o_raw" "$tmpfile_n_raw" "$tmp_new_issues" +done + +# Clean up shims directory +rm -rf "$shims_dir" + +exit $rc diff --git a/tests/patch/dtbs_check/info.json b/tests/patch/dtbs_check/info.json new file mode 100644 index 0000000..cdc9ded --- /dev/null +++ b/tests/patch/dtbs_check/info.json @@ -0,0 +1,3 @@ +{ + "run": ["dtbs_check.sh"] +}