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