Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kselftest: Add new test for detecting unprobed Devicetree devices

Introduce a new kselftest to detect devices that were declared in the
Devicetree, and are expected to be probed by a driver, but weren't.

The test uses two lists: a list of compatibles that can match a
Devicetree device to a driver, and a list of compatibles that should be
ignored. The first is automatically generated by the
dt-extract-compatibles script, and is run as part of building this test.
The list of compatibles to ignore is a hand-crafted list to capture the
few exceptions of compatibles that are expected to match a driver but
not be bound to it.

Signed-off-by: Nícolas F. R. A. Prado <nfraprado@collabora.com>
Reviewed-by: Shuah Khan <skhan@linuxfoundation.org>
Link: https://lore.kernel.org/r/20230828211424.2964562-4-nfraprado@collabora.com
Signed-off-by: Rob Herring <robh@kernel.org>

authored by

Nícolas F. R. A. Prado and committed by
Rob Herring
14571ab1 365ba0c7

+178
+1
MAINTAINERS
··· 15971 15971 F: drivers/of/ 15972 15972 F: include/linux/of*.h 15973 15973 F: scripts/dtc/ 15974 + F: tools/testing/selftests/dt/ 15974 15975 K: of_overlay_notifier_ 15975 15976 K: of_overlay_fdt_apply 15976 15977 K: of_overlay_remove
+1
tools/testing/selftests/Makefile
··· 18 18 TARGETS += drivers/s390x/uvdevice 19 19 TARGETS += drivers/net/bonding 20 20 TARGETS += drivers/net/team 21 + TARGETS += dt 21 22 TARGETS += efivarfs 22 23 TARGETS += exec 23 24 TARGETS += fchmodat2
+1
tools/testing/selftests/dt/.gitignore
··· 1 + compatible_list
+21
tools/testing/selftests/dt/Makefile
··· 1 + PY3 = $(shell which python3 2>/dev/null) 2 + 3 + ifneq ($(PY3),) 4 + 5 + TEST_PROGS := test_unprobed_devices.sh 6 + TEST_GEN_FILES := compatible_list 7 + TEST_FILES := compatible_ignore_list ktap_helpers.sh 8 + 9 + include ../lib.mk 10 + 11 + $(OUTPUT)/compatible_list: 12 + $(top_srcdir)/scripts/dtc/dt-extract-compatibles -d $(top_srcdir) > $@ 13 + 14 + else 15 + 16 + all: no_py3_warning 17 + 18 + no_py3_warning: 19 + @echo "Missing python3. This test will be skipped." 20 + 21 + endif
+1
tools/testing/selftests/dt/compatible_ignore_list
··· 1 + simple-mfd
+70
tools/testing/selftests/dt/ktap_helpers.sh
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # 3 + # Copyright (c) 2023 Collabora Ltd 4 + # 5 + # Helpers for outputting in KTAP format 6 + # 7 + KTAP_TESTNO=1 8 + KTAP_CNT_PASS=0 9 + KTAP_CNT_FAIL=0 10 + KTAP_CNT_SKIP=0 11 + 12 + ktap_print_header() { 13 + echo "TAP version 13" 14 + } 15 + 16 + ktap_set_plan() { 17 + num_tests="$1" 18 + 19 + echo "1..$num_tests" 20 + } 21 + 22 + ktap_skip_all() { 23 + echo -n "1..0 # SKIP " 24 + echo $@ 25 + } 26 + 27 + __ktap_test() { 28 + result="$1" 29 + description="$2" 30 + directive="$3" # optional 31 + 32 + local directive_str= 33 + [[ ! -z "$directive" ]] && directive_str="# $directive" 34 + 35 + echo $result $KTAP_TESTNO $description $directive_str 36 + 37 + KTAP_TESTNO=$((KTAP_TESTNO+1)) 38 + } 39 + 40 + ktap_test_pass() { 41 + description="$1" 42 + 43 + result="ok" 44 + __ktap_test "$result" "$description" 45 + 46 + KTAP_CNT_PASS=$((KTAP_CNT_PASS+1)) 47 + } 48 + 49 + ktap_test_skip() { 50 + description="$1" 51 + 52 + result="ok" 53 + directive="SKIP" 54 + __ktap_test "$result" "$description" "$directive" 55 + 56 + KTAP_CNT_SKIP=$((KTAP_CNT_SKIP+1)) 57 + } 58 + 59 + ktap_test_fail() { 60 + description="$1" 61 + 62 + result="not ok" 63 + __ktap_test "$result" "$description" 64 + 65 + KTAP_CNT_FAIL=$((KTAP_CNT_FAIL+1)) 66 + } 67 + 68 + ktap_print_totals() { 69 + echo "# Totals: pass:$KTAP_CNT_PASS fail:$KTAP_CNT_FAIL xfail:0 xpass:0 skip:$KTAP_CNT_SKIP error:0" 70 + }
+83
tools/testing/selftests/dt/test_unprobed_devices.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + # 4 + # Copyright (c) 2023 Collabora Ltd 5 + # 6 + # Based on Frank Rowand's dt_stat script. 7 + # 8 + # This script tests for devices that were declared on the Devicetree and are 9 + # expected to bind to a driver, but didn't. 10 + # 11 + # To achieve this, two lists are used: 12 + # * a list of the compatibles that can be matched by a Devicetree node 13 + # * a list of compatibles that should be ignored 14 + # 15 + 16 + DIR="$(dirname $(readlink -f "$0"))" 17 + 18 + source "${DIR}"/ktap_helpers.sh 19 + 20 + PDT=/proc/device-tree/ 21 + COMPAT_LIST="${DIR}"/compatible_list 22 + IGNORE_LIST="${DIR}"/compatible_ignore_list 23 + 24 + KSFT_PASS=0 25 + KSFT_FAIL=1 26 + KSFT_SKIP=4 27 + 28 + ktap_print_header 29 + 30 + if [[ ! -d "${PDT}" ]]; then 31 + ktap_skip_all "${PDT} doesn't exist." 32 + exit "${KSFT_SKIP}" 33 + fi 34 + 35 + nodes_compatible=$( 36 + for node_compat in $(find ${PDT} -name compatible); do 37 + node=$(dirname "${node_compat}") 38 + # Check if node is available 39 + if [[ -e "${node}"/status ]]; then 40 + status=$(tr -d '\000' < "${node}"/status) 41 + [[ "${status}" != "okay" && "${status}" != "ok" ]] && continue 42 + fi 43 + echo "${node}" | sed -e 's|\/proc\/device-tree||' 44 + done | sort 45 + ) 46 + 47 + nodes_dev_bound=$( 48 + IFS=$'\n' 49 + for uevent in $(find /sys/devices -name uevent); do 50 + if [[ -d "$(dirname "${uevent}")"/driver ]]; then 51 + grep '^OF_FULLNAME=' "${uevent}" | sed -e 's|OF_FULLNAME=||' 52 + fi 53 + done 54 + ) 55 + 56 + num_tests=$(echo ${nodes_compatible} | wc -w) 57 + ktap_set_plan "${num_tests}" 58 + 59 + retval="${KSFT_PASS}" 60 + for node in ${nodes_compatible}; do 61 + if ! echo "${nodes_dev_bound}" | grep -E -q "(^| )${node}( |\$)"; then 62 + compatibles=$(tr '\000' '\n' < "${PDT}"/"${node}"/compatible) 63 + 64 + for compatible in ${compatibles}; do 65 + if grep -x -q "${compatible}" "${IGNORE_LIST}"; then 66 + continue 67 + fi 68 + 69 + if grep -x -q "${compatible}" "${COMPAT_LIST}"; then 70 + ktap_test_fail "${node}" 71 + retval="${KSFT_FAIL}" 72 + continue 2 73 + fi 74 + done 75 + ktap_test_skip "${node}" 76 + else 77 + ktap_test_pass "${node}" 78 + fi 79 + 80 + done 81 + 82 + ktap_print_totals 83 + exit "${retval}"