VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   33 Branches   55 Tags
author: Saravana Kannan <saravanak@google.com> 2020-09-01 15:48:42 -0700 committer: Greg Kroah-Hartman <gregkh@linuxfoundation.org> 2020-09-04 18:19:37 +0200 commit: 51fae39bd5018e4f6d3e65a1a1a8ad40b5ee3662 parent: d012a7190fc1fd72ed48911e77ca97ba4521bccd
Commit Summary:
scripts/dev-needs: Add script to list device dependencies
Diffstat:
1 file changed, 267 insertions, 0 deletions
diff --git a/scripts/dev-needs.sh b/scripts/dev-needs.sh
new file mode 100755
index 000000000000..454cc304fb44
--- /dev/null
+++ b/scripts/dev-needs.sh
@@ -0,0 +1,315 @@
+#! /bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020, Google LLC. All rights reserved.
+# Author: Saravana Kannan <saravanak@google.com>
+
+function help() {
+	cat << EOF
+Usage: $(basename $0) [-c|-d|-m|-f] [filter options] <list of devices>
+
+This script needs to be run on the target device once it has booted to a
+shell.
+
+The script takes as input a list of one or more device directories under
+/sys/devices and then lists the probe dependency chain (suppliers and
+parents) of these devices. It does a breadth first search of the dependency
+chain, so the last entry in the output is close to the root of the
+dependency chain.
+
+By default it lists the full path to the devices under /sys/devices.
+
+It also takes an optional modifier flag as the first parameter to change
+what information is listed in the output. If the requested information is
+not available, the device name is printed.
+
+  -c	lists the compatible string of the dependencies
+  -d	lists the driver name of the dependencies that have probed
+  -m	lists the module name of the dependencies that have a module
+  -f	list the firmware node path of the dependencies
+  -g	list the dependencies as edges and nodes for graphviz
+  -t	list the dependencies as edges for tsort
+
+The filter options provide a way to filter out some dependencies:
+  --allow-no-driver	By default dependencies that don't have a driver
+			attached are ignored. This is to avoid following
+			device links to "class" devices that are created
+			when the consumer probes (as in, not a probe
+			dependency). If you want to follow these links
+			anyway, use this flag.
+
+  --exclude-devlinks	Don't follow device links when tracking probe
+			dependencies.
+
+  --exclude-parents	Don't follow parent devices when tracking probe
+			dependencies.
+
+EOF
+}
+
+function dev_to_detail() {
+	local i=0
+	while [ $i -lt ${#OUT_LIST[@]} ]
+	do
+		local C=${OUT_LIST[i]}
+		local S=${OUT_LIST[i+1]}
+		local D="'$(detail_chosen $C $S)'"
+		if [ ! -z "$D" ]
+		then
+			# This weirdness is needed to work with toybox when
+			# using the -t option.
+			printf '%05u\t%s\n' ${i} "$D" | tr -d \'
+		fi
+		i=$((i+2))
+	done
+}
+
+function already_seen() {
+	local i=0
+	while [ $i -lt ${#OUT_LIST[@]} ]
+	do
+		if [ "$1" = "${OUT_LIST[$i]}" ]
+		then
+			# if-statement treats 0 (no-error) as true
+			return 0
+		fi
+		i=$(($i+2))
+	done
+
+	# if-statement treats 1 (error) as false
+	return 1
+}
+
+# Return 0 (no-error/true) if parent was added
+function add_parent() {
+
+	if [ ${ALLOW_PARENTS} -eq 0 ]
+	then
+		return 1
+	fi
+
+	local CON=$1
+	# $CON could be a symlink path. So, we need to find the real path and
+	# then go up one level to find the real parent.
+	local PARENT=$(realpath $CON/..)
+
+	while [ ! -e ${PARENT}/driver ]
+	do
+		if [ "$PARENT" = "/sys/devices" ]
+		then
+			return 1
+		fi
+		PARENT=$(realpath $PARENT/..)
+	done
+
+	CONSUMERS+=($PARENT)
+	OUT_LIST+=(${CON} ${PARENT})
+	return 0
+}
+
+# Return 0 (no-error/true) if one or more suppliers were added
+function add_suppliers() {
+	local CON=$1
+	local RET=1
+
+	if [ ${ALLOW_DEVLINKS} -eq 0 ]
+	then
+		return 1
+	fi
+
+	SUPPLIER_LINKS=$(ls -1d $CON/supplier:* 2>/dev/null)
+	for SL in $SUPPLIER_LINKS;
+	do
+		SYNC_STATE=$(cat $SL/sync_state_only)
+
+		# sync_state_only links are proxy dependencies.
+		# They can also have cycles. So, don't follow them.
+		if [ "$SYNC_STATE" != '0' ]
+		then
+			continue
+		fi
+
+		SUPPLIER=$(realpath $SL/supplier)
+
+		if [ ! -e $SUPPLIER/driver -a ${ALLOW_NO_DRIVER} -eq 0 ]
+		then
+			continue
+		fi
+
+		CONSUMERS+=($SUPPLIER)
+		OUT_LIST+=(${CON} ${SUPPLIER})
+		RET=0
+	done
+
+	return $RET
+}
+
+function detail_compat() {
+	f=$1/of_node/compatible
+	if [ -e $f ]
+	then
+		echo -n $(cat $f)
+	else
+		echo -n $1
+	fi
+}
+
+function detail_module() {
+	f=$1/driver/module
+	if [ -e $f ]
+	then
+		echo -n $(basename $(realpath $f))
+	else
+		echo -n $1
+	fi
+}
+
+function detail_driver() {
+	f=$1/driver
+	if [ -e $f ]
+	then
+		echo -n $(basename $(realpath $f))
+	else
+		echo -n $1
+	fi
+}
+
+function detail_fwnode() {
+	f=$1/firmware_node
+	if [ ! -e $f ]
+	then
+		f=$1/of_node
+	fi
+
+	if [ -e $f ]
+	then
+		echo -n $(realpath $f)
+	else
+		echo -n $1
+	fi
+}
+
+function detail_graphviz() {
+	if [ "$2" != "ROOT" ]
+	then
+		echo -n "\"$(basename $2)\"->\"$(basename $1)\""
+	else
+		echo -n "\"$(basename $1)\""
+	fi
+}
+
+function detail_tsort() {
+	echo -n "\"$2\" \"$1\""
+}
+
+function detail_device() { echo -n $1; }
+
+alias detail=detail_device
+ALLOW_NO_DRIVER=0
+ALLOW_DEVLINKS=1
+ALLOW_PARENTS=1
+
+while [ $# -gt 0 ]
+do
+	ARG=$1
+	case $ARG in
+		--help)
+			help
+			exit 0
+			;;
+		-c)
+			alias detail=detail_compat
+			;;
+		-m)
+			alias detail=detail_module
+			;;
+		-d)
+			alias detail=detail_driver
+			;;
+		-f)
+			alias detail=detail_fwnode
+			;;
+		-g)
+			alias detail=detail_graphviz
+			;;
+		-t)
+			alias detail=detail_tsort
+			;;
+		--allow-no-driver)
+			ALLOW_NO_DRIVER=1
+			;;
+		--exclude-devlinks)
+			ALLOW_DEVLINKS=0
+			;;
+		--exclude-parents)
+			ALLOW_PARENTS=0
+			;;
+		*)
+			# Stop at the first argument that's not an option.
+			break
+			;;
+	esac
+	shift
+done
+
+function detail_chosen() {
+	detail $1 $2
+}
+
+if [ $# -eq 0 ]
+then
+	help
+	exit 1
+fi
+
+CONSUMERS=($@)
+OUT_LIST=()
+
+# Do a breadth first, non-recursive tracking of suppliers. The parent is also
+# considered a "supplier" as a device can't probe without its parent.
+i=0
+while [ $i -lt ${#CONSUMERS[@]} ]
+do
+	CONSUMER=$(realpath ${CONSUMERS[$i]})
+	i=$(($i+1))
+
+	if already_seen ${CONSUMER}
+	then
+		continue
+	fi
+
+	# If this is not a device with a driver, we don't care about its
+	# suppliers.
+	if [ ! -e ${CONSUMER}/driver -a ${ALLOW_NO_DRIVER} -eq 0 ]
+	then
+		continue
+	fi
+
+	ROOT=1
+
+	# Add suppliers to CONSUMERS list and output the consumer details.
+	#
+	# We don't need to worry about a cycle in the dependency chain causing
+	# infinite loops. That's because the kernel doesn't allow cycles in
+	# device links unless it's a sync_state_only device link. And we ignore
+	# sync_state_only device links inside add_suppliers.
+	if add_suppliers ${CONSUMER}
+	then
+		ROOT=0
+	fi
+
+	if add_parent ${CONSUMER}
+	then
+		ROOT=0
+	fi
+
+	if [ $ROOT -eq 1 ]
+	then
+		OUT_LIST+=(${CONSUMER} "ROOT")
+	fi
+done
+
+# Can NOT combine sort and uniq using sort -suk2 because stable sort in toybox
+# isn't really stable.
+dev_to_detail | sort -k2 -k1 | uniq -f 1 | sort | cut -f2-
+
+exit 0