xref: /openbmc/linux/scripts/dev-needs.sh (revision cbecf716ca618fd44feda6bd9a64a8179d031fc5)
1*51fae39bSSaravana Kannan#! /bin/sh
2*51fae39bSSaravana Kannan# SPDX-License-Identifier: GPL-2.0
3*51fae39bSSaravana Kannan# Copyright (c) 2020, Google LLC. All rights reserved.
4*51fae39bSSaravana Kannan# Author: Saravana Kannan <saravanak@google.com>
5*51fae39bSSaravana Kannan
6*51fae39bSSaravana Kannanfunction help() {
7*51fae39bSSaravana Kannan	cat << EOF
8*51fae39bSSaravana KannanUsage: $(basename $0) [-c|-d|-m|-f] [filter options] <list of devices>
9*51fae39bSSaravana Kannan
10*51fae39bSSaravana KannanThis script needs to be run on the target device once it has booted to a
11*51fae39bSSaravana Kannanshell.
12*51fae39bSSaravana Kannan
13*51fae39bSSaravana KannanThe script takes as input a list of one or more device directories under
14*51fae39bSSaravana Kannan/sys/devices and then lists the probe dependency chain (suppliers and
15*51fae39bSSaravana Kannanparents) of these devices. It does a breadth first search of the dependency
16*51fae39bSSaravana Kannanchain, so the last entry in the output is close to the root of the
17*51fae39bSSaravana Kannandependency chain.
18*51fae39bSSaravana Kannan
19*51fae39bSSaravana KannanBy default it lists the full path to the devices under /sys/devices.
20*51fae39bSSaravana Kannan
21*51fae39bSSaravana KannanIt also takes an optional modifier flag as the first parameter to change
22*51fae39bSSaravana Kannanwhat information is listed in the output. If the requested information is
23*51fae39bSSaravana Kannannot available, the device name is printed.
24*51fae39bSSaravana Kannan
25*51fae39bSSaravana Kannan  -c	lists the compatible string of the dependencies
26*51fae39bSSaravana Kannan  -d	lists the driver name of the dependencies that have probed
27*51fae39bSSaravana Kannan  -m	lists the module name of the dependencies that have a module
28*51fae39bSSaravana Kannan  -f	list the firmware node path of the dependencies
29*51fae39bSSaravana Kannan  -g	list the dependencies as edges and nodes for graphviz
30*51fae39bSSaravana Kannan  -t	list the dependencies as edges for tsort
31*51fae39bSSaravana Kannan
32*51fae39bSSaravana KannanThe filter options provide a way to filter out some dependencies:
33*51fae39bSSaravana Kannan  --allow-no-driver	By default dependencies that don't have a driver
34*51fae39bSSaravana Kannan			attached are ignored. This is to avoid following
35*51fae39bSSaravana Kannan			device links to "class" devices that are created
36*51fae39bSSaravana Kannan			when the consumer probes (as in, not a probe
37*51fae39bSSaravana Kannan			dependency). If you want to follow these links
38*51fae39bSSaravana Kannan			anyway, use this flag.
39*51fae39bSSaravana Kannan
40*51fae39bSSaravana Kannan  --exclude-devlinks	Don't follow device links when tracking probe
41*51fae39bSSaravana Kannan			dependencies.
42*51fae39bSSaravana Kannan
43*51fae39bSSaravana Kannan  --exclude-parents	Don't follow parent devices when tracking probe
44*51fae39bSSaravana Kannan			dependencies.
45*51fae39bSSaravana Kannan
46*51fae39bSSaravana KannanEOF
47*51fae39bSSaravana Kannan}
48*51fae39bSSaravana Kannan
49*51fae39bSSaravana Kannanfunction dev_to_detail() {
50*51fae39bSSaravana Kannan	local i=0
51*51fae39bSSaravana Kannan	while [ $i -lt ${#OUT_LIST[@]} ]
52*51fae39bSSaravana Kannan	do
53*51fae39bSSaravana Kannan		local C=${OUT_LIST[i]}
54*51fae39bSSaravana Kannan		local S=${OUT_LIST[i+1]}
55*51fae39bSSaravana Kannan		local D="'$(detail_chosen $C $S)'"
56*51fae39bSSaravana Kannan		if [ ! -z "$D" ]
57*51fae39bSSaravana Kannan		then
58*51fae39bSSaravana Kannan			# This weirdness is needed to work with toybox when
59*51fae39bSSaravana Kannan			# using the -t option.
60*51fae39bSSaravana Kannan			printf '%05u\t%s\n' ${i} "$D" | tr -d \'
61*51fae39bSSaravana Kannan		fi
62*51fae39bSSaravana Kannan		i=$((i+2))
63*51fae39bSSaravana Kannan	done
64*51fae39bSSaravana Kannan}
65*51fae39bSSaravana Kannan
66*51fae39bSSaravana Kannanfunction already_seen() {
67*51fae39bSSaravana Kannan	local i=0
68*51fae39bSSaravana Kannan	while [ $i -lt ${#OUT_LIST[@]} ]
69*51fae39bSSaravana Kannan	do
70*51fae39bSSaravana Kannan		if [ "$1" = "${OUT_LIST[$i]}" ]
71*51fae39bSSaravana Kannan		then
72*51fae39bSSaravana Kannan			# if-statement treats 0 (no-error) as true
73*51fae39bSSaravana Kannan			return 0
74*51fae39bSSaravana Kannan		fi
75*51fae39bSSaravana Kannan		i=$(($i+2))
76*51fae39bSSaravana Kannan	done
77*51fae39bSSaravana Kannan
78*51fae39bSSaravana Kannan	# if-statement treats 1 (error) as false
79*51fae39bSSaravana Kannan	return 1
80*51fae39bSSaravana Kannan}
81*51fae39bSSaravana Kannan
82*51fae39bSSaravana Kannan# Return 0 (no-error/true) if parent was added
83*51fae39bSSaravana Kannanfunction add_parent() {
84*51fae39bSSaravana Kannan
85*51fae39bSSaravana Kannan	if [ ${ALLOW_PARENTS} -eq 0 ]
86*51fae39bSSaravana Kannan	then
87*51fae39bSSaravana Kannan		return 1
88*51fae39bSSaravana Kannan	fi
89*51fae39bSSaravana Kannan
90*51fae39bSSaravana Kannan	local CON=$1
91*51fae39bSSaravana Kannan	# $CON could be a symlink path. So, we need to find the real path and
92*51fae39bSSaravana Kannan	# then go up one level to find the real parent.
93*51fae39bSSaravana Kannan	local PARENT=$(realpath $CON/..)
94*51fae39bSSaravana Kannan
95*51fae39bSSaravana Kannan	while [ ! -e ${PARENT}/driver ]
96*51fae39bSSaravana Kannan	do
97*51fae39bSSaravana Kannan		if [ "$PARENT" = "/sys/devices" ]
98*51fae39bSSaravana Kannan		then
99*51fae39bSSaravana Kannan			return 1
100*51fae39bSSaravana Kannan		fi
101*51fae39bSSaravana Kannan		PARENT=$(realpath $PARENT/..)
102*51fae39bSSaravana Kannan	done
103*51fae39bSSaravana Kannan
104*51fae39bSSaravana Kannan	CONSUMERS+=($PARENT)
105*51fae39bSSaravana Kannan	OUT_LIST+=(${CON} ${PARENT})
106*51fae39bSSaravana Kannan	return 0
107*51fae39bSSaravana Kannan}
108*51fae39bSSaravana Kannan
109*51fae39bSSaravana Kannan# Return 0 (no-error/true) if one or more suppliers were added
110*51fae39bSSaravana Kannanfunction add_suppliers() {
111*51fae39bSSaravana Kannan	local CON=$1
112*51fae39bSSaravana Kannan	local RET=1
113*51fae39bSSaravana Kannan
114*51fae39bSSaravana Kannan	if [ ${ALLOW_DEVLINKS} -eq 0 ]
115*51fae39bSSaravana Kannan	then
116*51fae39bSSaravana Kannan		return 1
117*51fae39bSSaravana Kannan	fi
118*51fae39bSSaravana Kannan
119*51fae39bSSaravana Kannan	SUPPLIER_LINKS=$(ls -1d $CON/supplier:* 2>/dev/null)
120*51fae39bSSaravana Kannan	for SL in $SUPPLIER_LINKS;
121*51fae39bSSaravana Kannan	do
122*51fae39bSSaravana Kannan		SYNC_STATE=$(cat $SL/sync_state_only)
123*51fae39bSSaravana Kannan
124*51fae39bSSaravana Kannan		# sync_state_only links are proxy dependencies.
125*51fae39bSSaravana Kannan		# They can also have cycles. So, don't follow them.
126*51fae39bSSaravana Kannan		if [ "$SYNC_STATE" != '0' ]
127*51fae39bSSaravana Kannan		then
128*51fae39bSSaravana Kannan			continue
129*51fae39bSSaravana Kannan		fi
130*51fae39bSSaravana Kannan
131*51fae39bSSaravana Kannan		SUPPLIER=$(realpath $SL/supplier)
132*51fae39bSSaravana Kannan
133*51fae39bSSaravana Kannan		if [ ! -e $SUPPLIER/driver -a ${ALLOW_NO_DRIVER} -eq 0 ]
134*51fae39bSSaravana Kannan		then
135*51fae39bSSaravana Kannan			continue
136*51fae39bSSaravana Kannan		fi
137*51fae39bSSaravana Kannan
138*51fae39bSSaravana Kannan		CONSUMERS+=($SUPPLIER)
139*51fae39bSSaravana Kannan		OUT_LIST+=(${CON} ${SUPPLIER})
140*51fae39bSSaravana Kannan		RET=0
141*51fae39bSSaravana Kannan	done
142*51fae39bSSaravana Kannan
143*51fae39bSSaravana Kannan	return $RET
144*51fae39bSSaravana Kannan}
145*51fae39bSSaravana Kannan
146*51fae39bSSaravana Kannanfunction detail_compat() {
147*51fae39bSSaravana Kannan	f=$1/of_node/compatible
148*51fae39bSSaravana Kannan	if [ -e $f ]
149*51fae39bSSaravana Kannan	then
150*51fae39bSSaravana Kannan		echo -n $(cat $f)
151*51fae39bSSaravana Kannan	else
152*51fae39bSSaravana Kannan		echo -n $1
153*51fae39bSSaravana Kannan	fi
154*51fae39bSSaravana Kannan}
155*51fae39bSSaravana Kannan
156*51fae39bSSaravana Kannanfunction detail_module() {
157*51fae39bSSaravana Kannan	f=$1/driver/module
158*51fae39bSSaravana Kannan	if [ -e $f ]
159*51fae39bSSaravana Kannan	then
160*51fae39bSSaravana Kannan		echo -n $(basename $(realpath $f))
161*51fae39bSSaravana Kannan	else
162*51fae39bSSaravana Kannan		echo -n $1
163*51fae39bSSaravana Kannan	fi
164*51fae39bSSaravana Kannan}
165*51fae39bSSaravana Kannan
166*51fae39bSSaravana Kannanfunction detail_driver() {
167*51fae39bSSaravana Kannan	f=$1/driver
168*51fae39bSSaravana Kannan	if [ -e $f ]
169*51fae39bSSaravana Kannan	then
170*51fae39bSSaravana Kannan		echo -n $(basename $(realpath $f))
171*51fae39bSSaravana Kannan	else
172*51fae39bSSaravana Kannan		echo -n $1
173*51fae39bSSaravana Kannan	fi
174*51fae39bSSaravana Kannan}
175*51fae39bSSaravana Kannan
176*51fae39bSSaravana Kannanfunction detail_fwnode() {
177*51fae39bSSaravana Kannan	f=$1/firmware_node
178*51fae39bSSaravana Kannan	if [ ! -e $f ]
179*51fae39bSSaravana Kannan	then
180*51fae39bSSaravana Kannan		f=$1/of_node
181*51fae39bSSaravana Kannan	fi
182*51fae39bSSaravana Kannan
183*51fae39bSSaravana Kannan	if [ -e $f ]
184*51fae39bSSaravana Kannan	then
185*51fae39bSSaravana Kannan		echo -n $(realpath $f)
186*51fae39bSSaravana Kannan	else
187*51fae39bSSaravana Kannan		echo -n $1
188*51fae39bSSaravana Kannan	fi
189*51fae39bSSaravana Kannan}
190*51fae39bSSaravana Kannan
191*51fae39bSSaravana Kannanfunction detail_graphviz() {
192*51fae39bSSaravana Kannan	if [ "$2" != "ROOT" ]
193*51fae39bSSaravana Kannan	then
194*51fae39bSSaravana Kannan		echo -n "\"$(basename $2)\"->\"$(basename $1)\""
195*51fae39bSSaravana Kannan	else
196*51fae39bSSaravana Kannan		echo -n "\"$(basename $1)\""
197*51fae39bSSaravana Kannan	fi
198*51fae39bSSaravana Kannan}
199*51fae39bSSaravana Kannan
200*51fae39bSSaravana Kannanfunction detail_tsort() {
201*51fae39bSSaravana Kannan	echo -n "\"$2\" \"$1\""
202*51fae39bSSaravana Kannan}
203*51fae39bSSaravana Kannan
204*51fae39bSSaravana Kannanfunction detail_device() { echo -n $1; }
205*51fae39bSSaravana Kannan
206*51fae39bSSaravana Kannanalias detail=detail_device
207*51fae39bSSaravana KannanALLOW_NO_DRIVER=0
208*51fae39bSSaravana KannanALLOW_DEVLINKS=1
209*51fae39bSSaravana KannanALLOW_PARENTS=1
210*51fae39bSSaravana Kannan
211*51fae39bSSaravana Kannanwhile [ $# -gt 0 ]
212*51fae39bSSaravana Kannando
213*51fae39bSSaravana Kannan	ARG=$1
214*51fae39bSSaravana Kannan	case $ARG in
215*51fae39bSSaravana Kannan		--help)
216*51fae39bSSaravana Kannan			help
217*51fae39bSSaravana Kannan			exit 0
218*51fae39bSSaravana Kannan			;;
219*51fae39bSSaravana Kannan		-c)
220*51fae39bSSaravana Kannan			alias detail=detail_compat
221*51fae39bSSaravana Kannan			;;
222*51fae39bSSaravana Kannan		-m)
223*51fae39bSSaravana Kannan			alias detail=detail_module
224*51fae39bSSaravana Kannan			;;
225*51fae39bSSaravana Kannan		-d)
226*51fae39bSSaravana Kannan			alias detail=detail_driver
227*51fae39bSSaravana Kannan			;;
228*51fae39bSSaravana Kannan		-f)
229*51fae39bSSaravana Kannan			alias detail=detail_fwnode
230*51fae39bSSaravana Kannan			;;
231*51fae39bSSaravana Kannan		-g)
232*51fae39bSSaravana Kannan			alias detail=detail_graphviz
233*51fae39bSSaravana Kannan			;;
234*51fae39bSSaravana Kannan		-t)
235*51fae39bSSaravana Kannan			alias detail=detail_tsort
236*51fae39bSSaravana Kannan			;;
237*51fae39bSSaravana Kannan		--allow-no-driver)
238*51fae39bSSaravana Kannan			ALLOW_NO_DRIVER=1
239*51fae39bSSaravana Kannan			;;
240*51fae39bSSaravana Kannan		--exclude-devlinks)
241*51fae39bSSaravana Kannan			ALLOW_DEVLINKS=0
242*51fae39bSSaravana Kannan			;;
243*51fae39bSSaravana Kannan		--exclude-parents)
244*51fae39bSSaravana Kannan			ALLOW_PARENTS=0
245*51fae39bSSaravana Kannan			;;
246*51fae39bSSaravana Kannan		*)
247*51fae39bSSaravana Kannan			# Stop at the first argument that's not an option.
248*51fae39bSSaravana Kannan			break
249*51fae39bSSaravana Kannan			;;
250*51fae39bSSaravana Kannan	esac
251*51fae39bSSaravana Kannan	shift
252*51fae39bSSaravana Kannandone
253*51fae39bSSaravana Kannan
254*51fae39bSSaravana Kannanfunction detail_chosen() {
255*51fae39bSSaravana Kannan	detail $1 $2
256*51fae39bSSaravana Kannan}
257*51fae39bSSaravana Kannan
258*51fae39bSSaravana Kannanif [ $# -eq 0 ]
259*51fae39bSSaravana Kannanthen
260*51fae39bSSaravana Kannan	help
261*51fae39bSSaravana Kannan	exit 1
262*51fae39bSSaravana Kannanfi
263*51fae39bSSaravana Kannan
264*51fae39bSSaravana KannanCONSUMERS=($@)
265*51fae39bSSaravana KannanOUT_LIST=()
266*51fae39bSSaravana Kannan
267*51fae39bSSaravana Kannan# Do a breadth first, non-recursive tracking of suppliers. The parent is also
268*51fae39bSSaravana Kannan# considered a "supplier" as a device can't probe without its parent.
269*51fae39bSSaravana Kannani=0
270*51fae39bSSaravana Kannanwhile [ $i -lt ${#CONSUMERS[@]} ]
271*51fae39bSSaravana Kannando
272*51fae39bSSaravana Kannan	CONSUMER=$(realpath ${CONSUMERS[$i]})
273*51fae39bSSaravana Kannan	i=$(($i+1))
274*51fae39bSSaravana Kannan
275*51fae39bSSaravana Kannan	if already_seen ${CONSUMER}
276*51fae39bSSaravana Kannan	then
277*51fae39bSSaravana Kannan		continue
278*51fae39bSSaravana Kannan	fi
279*51fae39bSSaravana Kannan
280*51fae39bSSaravana Kannan	# If this is not a device with a driver, we don't care about its
281*51fae39bSSaravana Kannan	# suppliers.
282*51fae39bSSaravana Kannan	if [ ! -e ${CONSUMER}/driver -a ${ALLOW_NO_DRIVER} -eq 0 ]
283*51fae39bSSaravana Kannan	then
284*51fae39bSSaravana Kannan		continue
285*51fae39bSSaravana Kannan	fi
286*51fae39bSSaravana Kannan
287*51fae39bSSaravana Kannan	ROOT=1
288*51fae39bSSaravana Kannan
289*51fae39bSSaravana Kannan	# Add suppliers to CONSUMERS list and output the consumer details.
290*51fae39bSSaravana Kannan	#
291*51fae39bSSaravana Kannan	# We don't need to worry about a cycle in the dependency chain causing
292*51fae39bSSaravana Kannan	# infinite loops. That's because the kernel doesn't allow cycles in
293*51fae39bSSaravana Kannan	# device links unless it's a sync_state_only device link. And we ignore
294*51fae39bSSaravana Kannan	# sync_state_only device links inside add_suppliers.
295*51fae39bSSaravana Kannan	if add_suppliers ${CONSUMER}
296*51fae39bSSaravana Kannan	then
297*51fae39bSSaravana Kannan		ROOT=0
298*51fae39bSSaravana Kannan	fi
299*51fae39bSSaravana Kannan
300*51fae39bSSaravana Kannan	if add_parent ${CONSUMER}
301*51fae39bSSaravana Kannan	then
302*51fae39bSSaravana Kannan		ROOT=0
303*51fae39bSSaravana Kannan	fi
304*51fae39bSSaravana Kannan
305*51fae39bSSaravana Kannan	if [ $ROOT -eq 1 ]
306*51fae39bSSaravana Kannan	then
307*51fae39bSSaravana Kannan		OUT_LIST+=(${CONSUMER} "ROOT")
308*51fae39bSSaravana Kannan	fi
309*51fae39bSSaravana Kannandone
310*51fae39bSSaravana Kannan
311*51fae39bSSaravana Kannan# Can NOT combine sort and uniq using sort -suk2 because stable sort in toybox
312*51fae39bSSaravana Kannan# isn't really stable.
313*51fae39bSSaravana Kannandev_to_detail | sort -k2 -k1 | uniq -f 1 | sort | cut -f2-
314*51fae39bSSaravana Kannan
315*51fae39bSSaravana Kannanexit 0
316