1 #!/bin/bash 2 # SPDX-License-Identifier: GPL-2.0 3 # 4 # Test the functionality of the Intel IFS(In Field Scan) driver. 5 # 6 7 # Matched with kselftest framework: tools/testing/selftests/kselftest.h 8 readonly KSFT_PASS=0 9 readonly KSFT_FAIL=1 10 readonly KSFT_XFAIL=2 11 readonly KSFT_SKIP=4 12 13 readonly CPU_SYSFS="/sys/devices/system/cpu" 14 readonly CPU_OFFLINE_SYSFS="${CPU_SYSFS}/offline" 15 readonly IMG_PATH="/lib/firmware/intel/ifs_0" 16 readonly IFS_SCAN_MODE="0" 17 readonly IFS_ARRAY_BIST_SCAN_MODE="1" 18 readonly IFS_PATH="/sys/devices/virtual/misc/intel_ifs" 19 readonly IFS_SCAN_SYSFS_PATH="${IFS_PATH}_${IFS_SCAN_MODE}" 20 readonly IFS_ARRAY_BIST_SYSFS_PATH="${IFS_PATH}_${IFS_ARRAY_BIST_SCAN_MODE}" 21 readonly RUN_TEST="run_test" 22 readonly STATUS="status" 23 readonly DETAILS="details" 24 readonly STATUS_PASS="pass" 25 readonly PASS="PASS" 26 readonly FAIL="FAIL" 27 readonly INFO="INFO" 28 readonly XFAIL="XFAIL" 29 readonly SKIP="SKIP" 30 readonly IFS_NAME="intel_ifs" 31 readonly ALL="all" 32 readonly SIBLINGS="siblings" 33 34 # Matches arch/x86/include/asm/intel-family.h and 35 # drivers/platform/x86/intel/ifs/core.c requirement as follows 36 readonly SAPPHIRERAPIDS_X="8f" 37 readonly EMERALDRAPIDS_X="cf" 38 39 readonly INTEL_FAM6="06" 40 41 LOOP_TIMES=3 42 FML="" 43 MODEL="" 44 STEPPING="" 45 CPU_FMS="" 46 TRUE="true" 47 FALSE="false" 48 RESULT=$KSFT_PASS 49 IMAGE_NAME="" 50 INTERVAL_TIME=1 51 OFFLINE_CPUS="" 52 # For IFS cleanup tags 53 ORIGIN_IFS_LOADED="" 54 IFS_IMAGE_NEED_RESTORE=$FALSE 55 IFS_LOG="/tmp/ifs_logs.$$" 56 RANDOM_CPU="" 57 DEFAULT_IMG_ID="" 58 59 append_log() 60 { 61 echo -e "$1" | tee -a "$IFS_LOG" 62 } 63 64 online_offline_cpu_list() 65 { 66 local on_off=$1 67 local target_cpus=$2 68 local cpu="" 69 local cpu_start="" 70 local cpu_end="" 71 local i="" 72 73 if [[ -n "$target_cpus" ]]; then 74 for cpu in $(echo "$target_cpus" | tr ',' ' '); do 75 if [[ "$cpu" == *"-"* ]]; then 76 cpu_start="" 77 cpu_end="" 78 i="" 79 cpu_start=$(echo "$cpu" | cut -d "-" -f 1) 80 cpu_end=$(echo "$cpu" | cut -d "-" -f 2) 81 for((i=cpu_start;i<=cpu_end;i++)); do 82 append_log "[$INFO] echo $on_off > \ 83 ${CPU_SYSFS}/cpu${i}/online" 84 echo "$on_off" > "$CPU_SYSFS"/cpu"$i"/online 85 done 86 else 87 set_target_cpu "$on_off" "$cpu" 88 fi 89 done 90 fi 91 } 92 93 ifs_scan_result_summary() 94 { 95 local failed_info pass_num skip_num fail_num 96 97 if [[ -e "$IFS_LOG" ]]; then 98 failed_info=$(grep ^"\[${FAIL}\]" "$IFS_LOG") 99 fail_num=$(grep -c ^"\[${FAIL}\]" "$IFS_LOG") 100 skip_num=$(grep -c ^"\[${SKIP}\]" "$IFS_LOG") 101 pass_num=$(grep -c ^"\[${PASS}\]" "$IFS_LOG") 102 103 if [[ "$fail_num" -ne 0 ]]; then 104 RESULT=$KSFT_FAIL 105 echo "[$INFO] IFS test failure summary:" 106 echo "$failed_info" 107 elif [[ "$skip_num" -ne 0 ]]; then 108 RESULT=$KSFT_SKIP 109 fi 110 echo "[$INFO] IFS test pass:$pass_num, skip:$skip_num, fail:$fail_num" 111 else 112 echo "[$INFO] No file $IFS_LOG for IFS scan summary" 113 fi 114 } 115 116 ifs_cleanup() 117 { 118 echo "[$INFO] Restore environment after IFS test" 119 120 # Restore ifs origin image if origin image backup step is needed 121 [[ "$IFS_IMAGE_NEED_RESTORE" == "$TRUE" ]] && { 122 mv -f "$IMG_PATH"/"$IMAGE_NAME"_origin "$IMG_PATH"/"$IMAGE_NAME" 123 } 124 125 # Restore the CPUs to the state before testing 126 [[ -z "$OFFLINE_CPUS" ]] || online_offline_cpu_list "0" "$OFFLINE_CPUS" 127 128 lsmod | grep -q "$IFS_NAME" && [[ "$ORIGIN_IFS_LOADED" == "$FALSE" ]] && { 129 echo "[$INFO] modprobe -r $IFS_NAME" 130 modprobe -r "$IFS_NAME" 131 } 132 133 ifs_scan_result_summary 134 [[ -e "$IFS_LOG" ]] && rm -rf "$IFS_LOG" 135 136 echo "[RESULT] IFS test exit with $RESULT" 137 exit "$RESULT" 138 } 139 140 do_cmd() 141 { 142 local cmd=$* 143 local ret="" 144 145 append_log "[$INFO] $cmd" 146 eval "$cmd" 147 ret=$? 148 if [[ $ret -ne 0 ]]; then 149 append_log "[$FAIL] $cmd failed. Return code is $ret" 150 RESULT=$KSFT_XFAIL 151 ifs_cleanup 152 fi 153 } 154 155 test_exit() 156 { 157 local info=$1 158 RESULT=$2 159 160 declare -A EXIT_MAP 161 EXIT_MAP[$KSFT_PASS]=$PASS 162 EXIT_MAP[$KSFT_FAIL]=$FAIL 163 EXIT_MAP[$KSFT_XFAIL]=$XFAIL 164 EXIT_MAP[$KSFT_SKIP]=$SKIP 165 166 append_log "[${EXIT_MAP[$RESULT]}] $info" 167 ifs_cleanup 168 } 169 170 online_all_cpus() 171 { 172 local off_cpus="" 173 174 OFFLINE_CPUS=$(cat "$CPU_OFFLINE_SYSFS") 175 online_offline_cpu_list "1" "$OFFLINE_CPUS" 176 177 off_cpus=$(cat "$CPU_OFFLINE_SYSFS") 178 if [[ -z "$off_cpus" ]]; then 179 append_log "[$INFO] All CPUs are online." 180 else 181 append_log "[$XFAIL] There is offline cpu:$off_cpus after online all cpu!" 182 RESULT=$KSFT_XFAIL 183 ifs_cleanup 184 fi 185 } 186 187 get_cpu_fms() 188 { 189 FML=$(grep -m 1 "family" /proc/cpuinfo | awk -F ":" '{printf "%02x",$2;}') 190 MODEL=$(grep -m 1 "model" /proc/cpuinfo | awk -F ":" '{printf "%02x",$2;}') 191 STEPPING=$(grep -m 1 "stepping" /proc/cpuinfo | awk -F ":" '{printf "%02x",$2;}') 192 CPU_FMS="${FML}-${MODEL}-${STEPPING}" 193 } 194 195 check_cpu_ifs_support_interval_time() 196 { 197 get_cpu_fms 198 199 if [[ "$FML" != "$INTEL_FAM6" ]]; then 200 test_exit "CPU family:$FML does not support IFS" "$KSFT_SKIP" 201 fi 202 203 # Ucode has time interval requirement for IFS scan on same CPU as follows: 204 case $MODEL in 205 "$SAPPHIRERAPIDS_X") 206 INTERVAL_TIME=180; 207 ;; 208 "$EMERALDRAPIDS_X") 209 INTERVAL_TIME=30; 210 ;; 211 *) 212 # Set default interval time for other platforms 213 INTERVAL_TIME=1; 214 append_log "[$INFO] CPU FML:$FML model:0x$MODEL, default: 1s interval time" 215 ;; 216 esac 217 } 218 219 check_ifs_loaded() 220 { 221 local ifs_info="" 222 223 ifs_info=$(lsmod | grep "$IFS_NAME") 224 if [[ -z "$ifs_info" ]]; then 225 append_log "[$INFO] modprobe $IFS_NAME" 226 modprobe "$IFS_NAME" || { 227 test_exit "Check if CONFIG_INTEL_IFS is set to m or \ 228 platform doesn't support ifs" "$KSFT_SKIP" 229 } 230 ifs_info=$(lsmod | grep "$IFS_NAME") 231 [[ -n "$ifs_info" ]] || test_exit "No ifs module listed by lsmod" "$KSFT_FAIL" 232 fi 233 } 234 235 test_ifs_scan_entry() 236 { 237 local ifs_info="" 238 239 ifs_info=$(lsmod | grep "$IFS_NAME") 240 241 if [[ -z "$ifs_info" ]]; then 242 ORIGIN_IFS_LOADED="$FALSE" 243 check_ifs_loaded 244 else 245 ORIGIN_IFS_LOADED="$TRUE" 246 append_log "[$INFO] Module $IFS_NAME is already loaded" 247 fi 248 249 if [[ -d "$IFS_SCAN_SYSFS_PATH" ]]; then 250 append_log "[$PASS] IFS sysfs $IFS_SCAN_SYSFS_PATH entry is created\n" 251 else 252 test_exit "No sysfs entry in $IFS_SCAN_SYSFS_PATH" "$KSFT_FAIL" 253 fi 254 } 255 256 load_image() 257 { 258 local image_id=$1 259 local image_info="" 260 local ret="" 261 262 check_ifs_loaded 263 if [[ -e "${IMG_PATH}/${IMAGE_NAME}" ]]; then 264 append_log "[$INFO] echo 0x$image_id > ${IFS_SCAN_SYSFS_PATH}/current_batch" 265 echo "0x$image_id" > "$IFS_SCAN_SYSFS_PATH"/current_batch 2>/dev/null 266 ret=$? 267 [[ "$ret" -eq 0 ]] || { 268 append_log "[$FAIL] Load ifs image $image_id failed with ret:$ret\n" 269 return "$ret" 270 } 271 image_info=$(cat ${IFS_SCAN_SYSFS_PATH}/current_batch) 272 if [[ "$image_info" == 0x"$image_id" ]]; then 273 append_log "[$PASS] load IFS current_batch:$image_info" 274 else 275 append_log "[$FAIL] current_batch:$image_info is not expected:$image_id" 276 return "$KSFT_FAIL" 277 fi 278 else 279 append_log "[$FAIL] No IFS image file ${IMG_PATH}/${IMAGE_NAME}"\ 280 return "$KSFT_FAIL" 281 fi 282 return 0 283 } 284 285 test_load_origin_ifs_image() 286 { 287 local image_id=$1 288 289 IMAGE_NAME="${CPU_FMS}-${image_id}.scan" 290 291 load_image "$image_id" || return $? 292 return 0 293 } 294 295 test_load_bad_ifs_image() 296 { 297 local image_id=$1 298 299 IMAGE_NAME="${CPU_FMS}-${image_id}.scan" 300 301 do_cmd "mv -f ${IMG_PATH}/${IMAGE_NAME} ${IMG_PATH}/${IMAGE_NAME}_origin" 302 303 # Set IFS_IMAGE_NEED_RESTORE to true before corrupt the origin ifs image file 304 IFS_IMAGE_NEED_RESTORE=$TRUE 305 do_cmd "dd if=/dev/urandom of=${IMG_PATH}/${IMAGE_NAME} bs=1K count=6 2>/dev/null" 306 307 # Use the specified judgment for negative testing 308 append_log "[$INFO] echo 0x$image_id > ${IFS_SCAN_SYSFS_PATH}/current_batch" 309 echo "0x$image_id" > "$IFS_SCAN_SYSFS_PATH"/current_batch 2>/dev/null 310 ret=$? 311 if [[ "$ret" -ne 0 ]]; then 312 append_log "[$PASS] Load invalid ifs image failed with ret:$ret not 0 as expected" 313 else 314 append_log "[$FAIL] Load invalid ifs image ret:$ret unexpectedly" 315 fi 316 317 do_cmd "mv -f ${IMG_PATH}/${IMAGE_NAME}_origin ${IMG_PATH}/${IMAGE_NAME}" 318 IFS_IMAGE_NEED_RESTORE=$FALSE 319 } 320 321 test_bad_and_origin_ifs_image() 322 { 323 local image_id=$1 324 325 append_log "[$INFO] Test loading bad and then loading original IFS image:" 326 test_load_origin_ifs_image "$image_id" || return $? 327 test_load_bad_ifs_image "$image_id" 328 # Load origin image again and make sure it's worked 329 test_load_origin_ifs_image "$image_id" || return $? 330 append_log "[$INFO] Loading invalid IFS image and then loading initial image passed.\n" 331 } 332 333 ifs_test_cpu() 334 { 335 local ifs_mode=$1 336 local cpu_num=$2 337 local image_id status details ret result result_info 338 339 echo "$cpu_num" > "$IFS_PATH"_"$ifs_mode"/"$RUN_TEST" 340 ret=$? 341 342 status=$(cat "${IFS_PATH}_${ifs_mode}/${STATUS}") 343 details=$(cat "${IFS_PATH}_${ifs_mode}/${DETAILS}") 344 345 if [[ "$ret" -eq 0 && "$status" == "$STATUS_PASS" ]]; then 346 result="$PASS" 347 else 348 result="$FAIL" 349 fi 350 351 cpu_num=$(cat "${CPU_SYSFS}/cpu${cpu_num}/topology/thread_siblings_list") 352 353 # There is no image file for IFS ARRAY BIST scan 354 if [[ -e "${IFS_PATH}_${ifs_mode}/current_batch" ]]; then 355 image_id=$(cat "${IFS_PATH}_${ifs_mode}/current_batch") 356 result_info=$(printf "[%s] ifs_%1d cpu(s):%s, current_batch:0x%02x, \ 357 ret:%2d, status:%s, details:0x%016x" \ 358 "$result" "$ifs_mode" "$cpu_num" "$image_id" "$ret" \ 359 "$status" "$details") 360 else 361 result_info=$(printf "[%s] ifs_%1d cpu(s):%s, ret:%2d, status:%s, details:0x%016x" \ 362 "$result" "$ifs_mode" "$cpu_num" "$ret" "$status" "$details") 363 fi 364 365 append_log "$result_info" 366 } 367 368 ifs_test_cpus() 369 { 370 local cpus_type=$1 371 local ifs_mode=$2 372 local image_id=$3 373 local cpu_max_num="" 374 local cpu_num="" 375 376 case "$cpus_type" in 377 "$ALL") 378 cpu_max_num=$(($(nproc) - 1)) 379 cpus=$(seq 0 $cpu_max_num) 380 ;; 381 "$SIBLINGS") 382 cpus=$(cat ${CPU_SYSFS}/cpu*/topology/thread_siblings_list \ 383 | sed -e 's/,.*//' \ 384 | sed -e 's/-.*//' \ 385 | sort -n \ 386 | uniq) 387 ;; 388 *) 389 test_exit "Invalid cpus_type:$cpus_type" "$KSFT_XFAIL" 390 ;; 391 esac 392 393 for cpu_num in $cpus; do 394 ifs_test_cpu "$ifs_mode" "$cpu_num" 395 done 396 397 if [[ -z "$image_id" ]]; then 398 append_log "[$INFO] ifs_$ifs_mode test $cpus_type cpus completed\n" 399 else 400 append_log "[$INFO] ifs_$ifs_mode $cpus_type cpus with $CPU_FMS-$image_id.scan \ 401 completed\n" 402 fi 403 } 404 405 test_ifs_same_cpu_loop() 406 { 407 local ifs_mode=$1 408 local cpu_num=$2 409 local loop_times=$3 410 411 append_log "[$INFO] Test ifs mode $ifs_mode on CPU:$cpu_num for $loop_times rounds:" 412 [[ "$ifs_mode" == "$IFS_SCAN_MODE" ]] && { 413 load_image "$DEFAULT_IMG_ID" || return $? 414 } 415 for (( i=1; i<=loop_times; i++ )); do 416 append_log "[$INFO] Loop iteration: $i in total of $loop_times" 417 # Only IFS scan needs the interval time 418 if [[ "$ifs_mode" == "$IFS_SCAN_MODE" ]]; then 419 do_cmd "sleep $INTERVAL_TIME" 420 elif [[ "$ifs_mode" == "$IFS_ARRAY_BIST_SCAN_MODE" ]]; then 421 true 422 else 423 test_exit "Invalid ifs_mode:$ifs_mode" "$KSFT_XFAIL" 424 fi 425 426 ifs_test_cpu "$ifs_mode" "$cpu_num" 427 done 428 append_log "[$INFO] $loop_times rounds of ifs_$ifs_mode test on CPU:$cpu_num completed.\n" 429 } 430 431 test_ifs_scan_available_imgs() 432 { 433 local image_ids="" 434 local image_id="" 435 436 append_log "[$INFO] Test ifs scan with available images:" 437 image_ids=$(find "$IMG_PATH" -maxdepth 1 -name "${CPU_FMS}-[0-9a-fA-F][0-9a-fA-F].scan" \ 438 2>/dev/null \ 439 | sort \ 440 | awk -F "-" '{print $NF}' \ 441 | cut -d "." -f 1) 442 443 for image_id in $image_ids; do 444 load_image "$image_id" || return $? 445 446 ifs_test_cpus "$SIBLINGS" "$IFS_SCAN_MODE" "$image_id" 447 # IFS scan requires time interval for the scan on the same CPU 448 do_cmd "sleep $INTERVAL_TIME" 449 done 450 } 451 452 prepare_ifs_test_env() 453 { 454 local max_cpu="" 455 456 check_cpu_ifs_support_interval_time 457 458 online_all_cpus 459 max_cpu=$(($(nproc) - 1)) 460 RANDOM_CPU=$(shuf -i 0-$max_cpu -n 1) 461 462 DEFAULT_IMG_ID=$(find $IMG_PATH -maxdepth 1 -name "${CPU_FMS}-[0-9a-fA-F][0-9a-fA-F].scan" \ 463 2>/dev/null \ 464 | sort \ 465 | head -n 1 \ 466 | awk -F "-" '{print $NF}' \ 467 | cut -d "." -f 1) 468 } 469 470 test_ifs() 471 { 472 prepare_ifs_test_env 473 474 test_ifs_scan_entry 475 476 if [[ -z "$DEFAULT_IMG_ID" ]]; then 477 append_log "[$SKIP] No proper ${IMG_PATH}/${CPU_FMS}-*.scan, skip ifs_0 scan" 478 else 479 test_bad_and_origin_ifs_image "$DEFAULT_IMG_ID" 480 test_ifs_scan_available_imgs 481 test_ifs_same_cpu_loop "$IFS_SCAN_MODE" "$RANDOM_CPU" "$LOOP_TIMES" 482 fi 483 484 if [[ -d "$IFS_ARRAY_BIST_SYSFS_PATH" ]]; then 485 ifs_test_cpus "$SIBLINGS" "$IFS_ARRAY_BIST_SCAN_MODE" 486 test_ifs_same_cpu_loop "$IFS_ARRAY_BIST_SCAN_MODE" "$RANDOM_CPU" "$LOOP_TIMES" 487 else 488 append_log "[$SKIP] No $IFS_ARRAY_BIST_SYSFS_PATH, skip IFS ARRAY BIST scan" 489 fi 490 } 491 492 trap ifs_cleanup SIGTERM SIGINT 493 test_ifs 494 ifs_cleanup
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.