Merge tag 'block-5.11-2021-01-10' of git://git.kernel.dk/linux-block
[linux/fpc-iii.git] / scripts / dev-needs.sh
blob454cc304fb448030972cd447006dff0aec4b1265
1 #! /bin/sh
2 # SPDX-License-Identifier: GPL-2.0
3 # Copyright (c) 2020, Google LLC. All rights reserved.
4 # Author: Saravana Kannan <saravanak@google.com>
6 function help() {
7 cat << EOF
8 Usage: $(basename $0) [-c|-d|-m|-f] [filter options] <list of devices>
10 This script needs to be run on the target device once it has booted to a
11 shell.
13 The script takes as input a list of one or more device directories under
14 /sys/devices and then lists the probe dependency chain (suppliers and
15 parents) of these devices. It does a breadth first search of the dependency
16 chain, so the last entry in the output is close to the root of the
17 dependency chain.
19 By default it lists the full path to the devices under /sys/devices.
21 It also takes an optional modifier flag as the first parameter to change
22 what information is listed in the output. If the requested information is
23 not available, the device name is printed.
25 -c lists the compatible string of the dependencies
26 -d lists the driver name of the dependencies that have probed
27 -m lists the module name of the dependencies that have a module
28 -f list the firmware node path of the dependencies
29 -g list the dependencies as edges and nodes for graphviz
30 -t list the dependencies as edges for tsort
32 The filter options provide a way to filter out some dependencies:
33 --allow-no-driver By default dependencies that don't have a driver
34 attached are ignored. This is to avoid following
35 device links to "class" devices that are created
36 when the consumer probes (as in, not a probe
37 dependency). If you want to follow these links
38 anyway, use this flag.
40 --exclude-devlinks Don't follow device links when tracking probe
41 dependencies.
43 --exclude-parents Don't follow parent devices when tracking probe
44 dependencies.
46 EOF
49 function dev_to_detail() {
50 local i=0
51 while [ $i -lt ${#OUT_LIST[@]} ]
53 local C=${OUT_LIST[i]}
54 local S=${OUT_LIST[i+1]}
55 local D="'$(detail_chosen $C $S)'"
56 if [ ! -z "$D" ]
57 then
58 # This weirdness is needed to work with toybox when
59 # using the -t option.
60 printf '%05u\t%s\n' ${i} "$D" | tr -d \'
62 i=$((i+2))
63 done
66 function already_seen() {
67 local i=0
68 while [ $i -lt ${#OUT_LIST[@]} ]
70 if [ "$1" = "${OUT_LIST[$i]}" ]
71 then
72 # if-statement treats 0 (no-error) as true
73 return 0
75 i=$(($i+2))
76 done
78 # if-statement treats 1 (error) as false
79 return 1
82 # Return 0 (no-error/true) if parent was added
83 function add_parent() {
85 if [ ${ALLOW_PARENTS} -eq 0 ]
86 then
87 return 1
90 local CON=$1
91 # $CON could be a symlink path. So, we need to find the real path and
92 # then go up one level to find the real parent.
93 local PARENT=$(realpath $CON/..)
95 while [ ! -e ${PARENT}/driver ]
97 if [ "$PARENT" = "/sys/devices" ]
98 then
99 return 1
101 PARENT=$(realpath $PARENT/..)
102 done
104 CONSUMERS+=($PARENT)
105 OUT_LIST+=(${CON} ${PARENT})
106 return 0
109 # Return 0 (no-error/true) if one or more suppliers were added
110 function add_suppliers() {
111 local CON=$1
112 local RET=1
114 if [ ${ALLOW_DEVLINKS} -eq 0 ]
115 then
116 return 1
119 SUPPLIER_LINKS=$(ls -1d $CON/supplier:* 2>/dev/null)
120 for SL in $SUPPLIER_LINKS;
122 SYNC_STATE=$(cat $SL/sync_state_only)
124 # sync_state_only links are proxy dependencies.
125 # They can also have cycles. So, don't follow them.
126 if [ "$SYNC_STATE" != '0' ]
127 then
128 continue
131 SUPPLIER=$(realpath $SL/supplier)
133 if [ ! -e $SUPPLIER/driver -a ${ALLOW_NO_DRIVER} -eq 0 ]
134 then
135 continue
138 CONSUMERS+=($SUPPLIER)
139 OUT_LIST+=(${CON} ${SUPPLIER})
140 RET=0
141 done
143 return $RET
146 function detail_compat() {
147 f=$1/of_node/compatible
148 if [ -e $f ]
149 then
150 echo -n $(cat $f)
151 else
152 echo -n $1
156 function detail_module() {
157 f=$1/driver/module
158 if [ -e $f ]
159 then
160 echo -n $(basename $(realpath $f))
161 else
162 echo -n $1
166 function detail_driver() {
167 f=$1/driver
168 if [ -e $f ]
169 then
170 echo -n $(basename $(realpath $f))
171 else
172 echo -n $1
176 function detail_fwnode() {
177 f=$1/firmware_node
178 if [ ! -e $f ]
179 then
180 f=$1/of_node
183 if [ -e $f ]
184 then
185 echo -n $(realpath $f)
186 else
187 echo -n $1
191 function detail_graphviz() {
192 if [ "$2" != "ROOT" ]
193 then
194 echo -n "\"$(basename $2)\"->\"$(basename $1)\""
195 else
196 echo -n "\"$(basename $1)\""
200 function detail_tsort() {
201 echo -n "\"$2\" \"$1\""
204 function detail_device() { echo -n $1; }
206 alias detail=detail_device
207 ALLOW_NO_DRIVER=0
208 ALLOW_DEVLINKS=1
209 ALLOW_PARENTS=1
211 while [ $# -gt 0 ]
213 ARG=$1
214 case $ARG in
215 --help)
216 help
217 exit 0
220 alias detail=detail_compat
223 alias detail=detail_module
226 alias detail=detail_driver
229 alias detail=detail_fwnode
232 alias detail=detail_graphviz
235 alias detail=detail_tsort
237 --allow-no-driver)
238 ALLOW_NO_DRIVER=1
240 --exclude-devlinks)
241 ALLOW_DEVLINKS=0
243 --exclude-parents)
244 ALLOW_PARENTS=0
247 # Stop at the first argument that's not an option.
248 break
250 esac
251 shift
252 done
254 function detail_chosen() {
255 detail $1 $2
258 if [ $# -eq 0 ]
259 then
260 help
261 exit 1
264 CONSUMERS=($@)
265 OUT_LIST=()
267 # Do a breadth first, non-recursive tracking of suppliers. The parent is also
268 # considered a "supplier" as a device can't probe without its parent.
270 while [ $i -lt ${#CONSUMERS[@]} ]
272 CONSUMER=$(realpath ${CONSUMERS[$i]})
273 i=$(($i+1))
275 if already_seen ${CONSUMER}
276 then
277 continue
280 # If this is not a device with a driver, we don't care about its
281 # suppliers.
282 if [ ! -e ${CONSUMER}/driver -a ${ALLOW_NO_DRIVER} -eq 0 ]
283 then
284 continue
287 ROOT=1
289 # Add suppliers to CONSUMERS list and output the consumer details.
291 # We don't need to worry about a cycle in the dependency chain causing
292 # infinite loops. That's because the kernel doesn't allow cycles in
293 # device links unless it's a sync_state_only device link. And we ignore
294 # sync_state_only device links inside add_suppliers.
295 if add_suppliers ${CONSUMER}
296 then
297 ROOT=0
300 if add_parent ${CONSUMER}
301 then
302 ROOT=0
305 if [ $ROOT -eq 1 ]
306 then
307 OUT_LIST+=(${CONSUMER} "ROOT")
309 done
311 # Can NOT combine sort and uniq using sort -suk2 because stable sort in toybox
312 # isn't really stable.
313 dev_to_detail | sort -k2 -k1 | uniq -f 1 | sort | cut -f2-
315 exit 0