All of lore.kernel.org
 help / color / mirror / Atom feed
From: Laura Nao <laura.nao@collabora.com>
To: rafael@kernel.org, lenb@kernel.org, shuah@kernel.org
Cc: dan.carpenter@linaro.org, broonie@kernel.org,
	groeck@chromium.org, kernel@collabora.com,
	kernelci@lists.linux.dev, linux-acpi@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
	robh+dt@kernel.org, saravanak@google.com, davidgow@google.com,
	Tim.Bird@sony.com, dianders@chromium.org,
	Laura Nao <laura.nao@collabora.com>
Subject: [RFC PATCH v2 2/2] kselftest: Add test to detect unprobed devices on ACPI platforms
Date: Fri,  8 Mar 2024 15:49:33 +0100	[thread overview]
Message-ID: <20240308144933.337107-3-laura.nao@collabora.com> (raw)
In-Reply-To: <20240308144933.337107-1-laura.nao@collabora.com>

Add new kselftest that tests whether devices declared in the ACPI
namespace and supported by the kernel are correctly bound
to a driver.

The test traverses the ACPI sysfs tree to get a list of all the devices
defined in the ACPI namespace and verifies whether the physical devices
linked to each ACPI object are bound to a driver.
The test relies on two lists to skip devices not expected to be bound
to a driver:
- List generated by the acpi-extract-ids script: includes the ACPI IDs
  matched by a driver
- Manual list of ignored IDs: includes the ID of devices that may be
  discovered only via the platform firmware and that don't require a
  driver or cannot be represented as platform devices

The test also examines the sysfs attributes of the target device objects
linked by physical_node* to exclude other devices that should not be
bound to a driver. This includes:
- Devices not assigned to any subsystem
- Devices that are linked to other devices
- Class devices
- Specific PCI bridges that do not require a driver

Signed-off-by: Laura Nao <laura.nao@collabora.com>
---
 MAINTAINERS                                   |   1 +
 tools/testing/selftests/Makefile              |   1 +
 tools/testing/selftests/acpi/.gitignore       |   1 +
 tools/testing/selftests/acpi/Makefile         |  21 +++
 tools/testing/selftests/acpi/id_ignore_list   |   3 +
 .../selftests/acpi/test_unprobed_devices.sh   | 138 ++++++++++++++++++
 6 files changed, 165 insertions(+)
 create mode 100644 tools/testing/selftests/acpi/.gitignore
 create mode 100644 tools/testing/selftests/acpi/Makefile
 create mode 100644 tools/testing/selftests/acpi/id_ignore_list
 create mode 100755 tools/testing/selftests/acpi/test_unprobed_devices.sh

diff --git a/MAINTAINERS b/MAINTAINERS
index 8333ead448c4..1f58949c9e51 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -294,6 +294,7 @@ F:	include/linux/fwnode.h
 F:	include/linux/fw_table.h
 F:	lib/fw_table.c
 F:	scripts/acpi/acpi-extract-ids
+F:	tools/testing/selftests/acpi/
 F:	tools/power/acpi/
 
 ACPI APEI
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index e1504833654d..3107301ea4f3 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
+TARGETS += acpi
 TARGETS += alsa
 TARGETS += amd-pstate
 TARGETS += arm64
diff --git a/tools/testing/selftests/acpi/.gitignore b/tools/testing/selftests/acpi/.gitignore
new file mode 100644
index 000000000000..3c520e8a1962
--- /dev/null
+++ b/tools/testing/selftests/acpi/.gitignore
@@ -0,0 +1 @@
+id_list
diff --git a/tools/testing/selftests/acpi/Makefile b/tools/testing/selftests/acpi/Makefile
new file mode 100644
index 000000000000..b80d4fb797ac
--- /dev/null
+++ b/tools/testing/selftests/acpi/Makefile
@@ -0,0 +1,21 @@
+PY3 = $(shell which python3 2>/dev/null)
+
+ifneq ($(PY3),)
+
+TEST_PROGS := test_unprobed_devices.sh
+TEST_GEN_FILES := id_list
+TEST_FILES := id_ignore_list
+
+include ../lib.mk
+
+$(OUTPUT)/id_list:
+	$(top_srcdir)/scripts/acpi/acpi-extract-ids -d $(top_srcdir) > $@
+
+else
+
+all: no_py3_warning
+
+no_py3_warning:
+	@echo "Missing python3. This test will be skipped."
+
+endif
\ No newline at end of file
diff --git a/tools/testing/selftests/acpi/id_ignore_list b/tools/testing/selftests/acpi/id_ignore_list
new file mode 100644
index 000000000000..86ddf4b0a55a
--- /dev/null
+++ b/tools/testing/selftests/acpi/id_ignore_list
@@ -0,0 +1,3 @@
+PNP0A05
+PNP0A06
+ACPI0004
\ No newline at end of file
diff --git a/tools/testing/selftests/acpi/test_unprobed_devices.sh b/tools/testing/selftests/acpi/test_unprobed_devices.sh
new file mode 100755
index 000000000000..23e52833c475
--- /dev/null
+++ b/tools/testing/selftests/acpi/test_unprobed_devices.sh
@@ -0,0 +1,138 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (c) 2023 Collabora Ltd
+#
+# Inspired by the tools/testing/selftests/dt/test_unprobed_devices.sh
+# script, adapted for the ACPI use case.
+#
+# This script checks whether devices declared in the ACPI namespace and
+# supported by the kernel are correctly bound to a driver.
+#
+# To do this, two lists are used:
+# * a list of ACPI IDs matched by existing drivers
+# * a list of IDs that should be ignored
+#
+
+DIR="$(dirname "$(readlink -f "$0")")"
+
+KTAP_HELPERS="${DIR}/../kselftest/ktap_helpers.sh"
+if ! source "$KTAP_HELPERS"; then
+	exit 4
+fi
+
+ACPI_SYSTEM_DIR="/sys/devices/LNXSYSTM:00"
+ID_IGNORE_LIST="${DIR}"/id_ignore_list
+ID_LIST="${DIR}"/id_list
+
+PCI_CLASS_BRIDGE_HOST="0x0600"
+PCI_CLASS_BRIDGE_ISA="0x0601"
+
+ktap_print_header
+
+if [[ ! -d "${ACPI_SYSTEM_DIR}" ]]; then
+	ktap_skip_all "${ACPI_SYSTEM_DIR} doesn't exist."
+	exit "${KSFT_SKIP}"
+fi
+
+# The ACPI specification mandates that ACPI objects representing devices on
+# non-enumerable and enumerable busses contain a _HID or an _ADR
+# identification object respectively. Get a list of devices of both types,
+# by searching the ACPI sysfs subtree for directories containing a hid or
+# adr attribute.
+supp_dev_paths=$(while IFS=$'\n' read -r dev_path; do
+	if [ ! -f "${dev_path}"/hid ] && [ ! -f "${dev_path}"/adr ]; then
+		continue
+	fi
+
+	# Check if the device is present, enabled, and functioning properly
+	status="${dev_path}/status"
+	if [ -f "${status}" ]; then
+		status_hex=$(($(cat "${status}")))
+
+		if [ $((status_hex & 1)) -eq 0 ] ||
+			[ $((status_hex >> 1 & 1)) -eq 0 ] ||
+			[ $((status_hex >> 3 & 1)) -eq 0 ]; then
+			continue
+		fi
+	fi
+
+	if [ -n "$(find -L "${dev_path}" -maxdepth 1 -name "physical_node*" -print -quit)" ]; then
+		for node in "${dev_path}"/physical_node*; do
+			# Ignore devices without a subsystem, devices that link to
+			# other devices, and class devices
+			if [ ! -d "${node}/subsystem" ] ||
+				[ -d "${node}/device" ] ||
+				[[ "$(readlink -f "${node}/subsystem")" == /sys/class/* ]]; then
+				continue
+			fi
+
+			echo "${node}"
+		done
+	fi
+done < <(find ${ACPI_SYSTEM_DIR} -name uevent -exec dirname {} \;))
+
+supp_dev_paths_num=$(echo "${supp_dev_paths}" | wc -w)
+ktap_set_plan "${supp_dev_paths_num}"
+
+# Iterate over ACPI devices
+for dev_path in ${supp_dev_paths}; do
+	if [ -f "${dev_path}/firmware_node/path" ]; then
+		acpi_path="$(<"${dev_path}"/firmware_node/path)"
+	fi
+
+	dev_link=$(readlink -f "${dev_path}")
+	desc="${acpi_path}-${dev_link#/sys/devices/}"
+
+	if [ -f "${dev_path}/firmware_node/hid" ]; then
+		hid="$(<"${dev_path}"/firmware_node/hid)"
+
+		if [ -f "${dev_path}/firmware_node/modalias" ]; then
+			modalias=$(<"${dev_path}/firmware_node/modalias")
+			cid=$(echo "${modalias}" | cut -d':' -f3)
+
+			# Skip devices with ignored HID/CID
+			if ignored_id=$(grep -i "${hid}" "${ID_IGNORE_LIST}" ||
+				{ [ -n "${cid}" ] && grep -i "${cid}" "${ID_IGNORE_LIST}"; }); then
+				ktap_print_msg "ID ${ignored_id} ignored [SKIP]"
+				ktap_test_skip "${desc}"
+				continue
+			fi
+			# Skip devices with unsupported HID/CID
+			if [[ "${hid}" != LNX* ]] && ! grep -x -q -i "${hid}" "${ID_LIST}"; then
+				if [ -z "${cid}" ] || ! grep -x -q -i "${cid}" "${ID_LIST}"; then
+					ktap_print_msg "no match for ${hid}${cid:+:${cid}} found \
+						in the supported IDs list [SKIP]"
+					ktap_test_skip "${desc}"
+					continue
+				fi
+			fi
+		fi
+	fi
+
+	# Skip bridges that don't require a driver
+	if [ -f "${dev_path}/class" ]; then
+		class=$(<"${dev_path}"/class)
+		if [[ ${class} == ${PCI_CLASS_BRIDGE_HOST}* ]] ||
+			[[ ${class} == ${PCI_CLASS_BRIDGE_ISA}* ]]; then
+			ktap_print_msg "device linked to ${desc} does not require a driver [SKIP]"
+			ktap_test_skip "${desc}"
+			continue
+		fi
+	fi
+
+	# Search for the driver in both the device folder and the companion's folder
+	if [ -d "${dev_path}/driver" ] || [ -d "${dev_path}/firmware_node/driver" ]; then
+		ktap_test_pass "${desc}"
+	# Skip char devices
+	elif [ -f "${dev_path}/dev" ]; then
+		ktap_print_msg "${desc} is a char device [SKIP]"
+		ktap_test_skip "${desc}"
+		continue
+	else
+		ktap_test_fail "${desc}"
+	fi
+
+done
+
+ktap_finished
-- 
2.30.2


      parent reply	other threads:[~2024-03-08 14:49 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-03-08 14:49 [RFC PATCH v2 0/2] Add a test to verify device probing on ACPI platforms Laura Nao
2024-03-08 14:49 ` [RFC PATCH v2 1/2] acpi: Add script to extract ACPI device ids in the kernel Laura Nao
2024-03-08 14:49 ` Laura Nao [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240308144933.337107-3-laura.nao@collabora.com \
    --to=laura.nao@collabora.com \
    --cc=Tim.Bird@sony.com \
    --cc=broonie@kernel.org \
    --cc=dan.carpenter@linaro.org \
    --cc=davidgow@google.com \
    --cc=dianders@chromium.org \
    --cc=groeck@chromium.org \
    --cc=kernel@collabora.com \
    --cc=kernelci@lists.linux.dev \
    --cc=lenb@kernel.org \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=rafael@kernel.org \
    --cc=robh+dt@kernel.org \
    --cc=saravanak@google.com \
    --cc=shuah@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.