aboutsummaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/firmware/fw_upload.sh
blob: c7a6f06c9adbbca5ccf22cd44fbb1ae977a527e2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
# This validates the user-initiated fw upload mechanism of the firmware
# loader. It verifies that one or more firmware devices can be created
# for a device driver. It also verifies the data transfer, the
# cancellation support, and the error flows.
set -e

TEST_REQS_FW_UPLOAD="yes"
TEST_DIR=$(dirname $0)

progress_states="preparing transferring  programming"
errors="hw-error
	timeout
	device-busy
	invalid-file-size
	read-write-error
	flash-wearout"
error_abort="user-abort"
fwname1=fw1
fwname2=fw2
fwname3=fw3

source $TEST_DIR/fw_lib.sh

check_mods
check_setup
verify_reqs

trap "upload_finish" EXIT

upload_finish() {
	local fwdevs="$fwname1 $fwname2 $fwname3"

	for name in $fwdevs; do
		if [ -e "$DIR/$name" ]; then
			echo -n "$name" > "$DIR"/upload_unregister
		fi
	done
}

upload_fw() {
	local name="$1"
	local file="$2"

	echo 1 > "$DIR"/"$name"/loading
	cat "$file" > "$DIR"/"$name"/data
	echo 0 > "$DIR"/"$name"/loading
}

verify_fw() {
	local name="$1"
	local file="$2"

	echo -n "$name" > "$DIR"/config_upload_name
	if ! cmp "$file" "$DIR"/upload_read > /dev/null 2>&1; then
		echo "$0: firmware compare for $name did not match" >&2
		exit 1
	fi

	echo "$0: firmware upload for $name works" >&2
	return 0
}

inject_error() {
	local name="$1"
	local status="$2"
	local error="$3"

	echo 1 > "$DIR"/"$name"/loading
	echo -n "inject":"$status":"$error" > "$DIR"/"$name"/data
	echo 0 > "$DIR"/"$name"/loading
}

await_status() {
	local name="$1"
	local expected="$2"
	local status
	local i

	let i=0
	while [ $i -lt 50 ]; do
		status=$(cat "$DIR"/"$name"/status)
		if [ "$status" = "$expected" ]; then
			return 0;
		fi
		sleep 1e-03
		let i=$i+1
	done

	echo "$0: Invalid status: Expected $expected, Actual $status" >&2
	return 1;
}

await_idle() {
	local name="$1"

	await_status "$name" "idle"
	return $?
}

expect_error() {
	local name="$1"
	local expected="$2"
	local error=$(cat "$DIR"/"$name"/error)

	if [ "$error" != "$expected" ]; then
		echo "Invalid error: Expected $expected, Actual $error" >&2
		return 1
	fi

	return 0
}

random_firmware() {
	local bs="$1"
	local count="$2"
	local file=$(mktemp -p /tmp uploadfwXXX.bin)

	dd if=/dev/urandom of="$file" bs="$bs" count="$count" > /dev/null 2>&1
	echo "$file"
}

test_upload_cancel() {
	local name="$1"
	local status

	for status in $progress_states; do
		inject_error $name $status $error_abort
		if ! await_status $name $status; then
			exit 1
		fi

		echo 1 > "$DIR"/"$name"/cancel

		if ! await_idle $name; then
			exit 1
		fi

		if ! expect_error $name "$status":"$error_abort"; then
			exit 1
		fi
	done

	echo "$0: firmware upload cancellation works"
	return 0
}

test_error_handling() {
	local name=$1
	local status
	local error

	for status in $progress_states; do
		for error in $errors; do
			inject_error $name $status $error

			if ! await_idle $name; then
				exit 1
			fi

			if ! expect_error $name "$status":"$error"; then
				exit 1
			fi

		done
	done
	echo "$0: firmware upload error handling works"
}

test_fw_too_big() {
	local name=$1
	local fw_too_big=`random_firmware 512 5`
	local expected="preparing:invalid-file-size"

	upload_fw $name $fw_too_big
	rm -f $fw_too_big

	if ! await_idle $name; then
		exit 1
	fi

	if ! expect_error $name $expected; then
		exit 1
	fi

	echo "$0: oversized firmware error handling works"
}

echo -n "$fwname1" > "$DIR"/upload_register
echo -n "$fwname2" > "$DIR"/upload_register
echo -n "$fwname3" > "$DIR"/upload_register

test_upload_cancel $fwname1
test_error_handling $fwname1
test_fw_too_big $fwname1

fw_file1=`random_firmware 512 4`
fw_file2=`random_firmware 512 3`
fw_file3=`random_firmware 512 2`

upload_fw $fwname1 $fw_file1
upload_fw $fwname2 $fw_file2
upload_fw $fwname3 $fw_file3

verify_fw ${fwname1} ${fw_file1}
verify_fw ${fwname2} ${fw_file2}
verify_fw ${fwname3} ${fw_file3}

echo -n "$fwname1" > "$DIR"/upload_unregister
echo -n "$fwname2" > "$DIR"/upload_unregister
echo -n "$fwname3" > "$DIR"/upload_unregister

exit 0