#!/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