To allow extended linear cache to also utilize the poison test, move the common helper functions to a common file for sourcing.
Signed-off-by: Dave Jiang <[email protected]> --- test/common-poison | 190 +++++++++++++++++++++++++++++++++++++++++++++ test/cxl-poison.sh | 187 +------------------------------------------- 2 files changed, 191 insertions(+), 186 deletions(-) create mode 100644 test/common-poison diff --git a/test/common-poison b/test/common-poison new file mode 100644 index 000000000000..15a091e41dc3 --- /dev/null +++ b/test/common-poison @@ -0,0 +1,190 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2025 Intel Corporation. All rights reserved. + +find_memdev() +{ + readarray -t capable_mems < <("$CXL" list -b "$CXL_TEST_BUS" -M | + jq -r ".[] | select(.pmem_size != null) | + select(.ram_size != null) | .memdev") + + if [ ${#capable_mems[@]} == 0 ]; then + echo "no memdevs found for test" + err "$LINENO" + fi + + memdev=${capable_mems[0]} +} + +find_auto_region() +{ + region="$($CXL list -b "$CXL_TEST_BUS" -R | jq -r ".[0].region")" + [[ -n "$region" && "$region" != "null" ]] || do_skip "no test region found" + mem0="$($CXL list -r "$region" --targets | jq -r ".[0].mappings[0].memdev")" + [[ -n "$mem0" && "$mem0" != "null" ]] || do_skip "no region target0 found" + mem1="$($CXL list -r "$region" --targets | jq -r ".[0].mappings[1].memdev")" + [[ -n "$mem1" && "$mem1" != "null" ]] || do_skip "no region target1 found" + echo "$region" +} + +# When cxl-cli support for inject and clear arrives, replace +# the writes to /sys/kernel/debug with the new cxl commands. + +_do_poison_sysfs() +{ + local action="$1" dev="$2" addr="$3" + local expect_fail=${4:-false} + + if "$expect_fail"; then + if echo "$addr" > "/sys/kernel/debug/cxl/$dev/${action}_poison"; then + echo "Expected ${action}_poison to fail for $addr" + err "$LINENO" + fi + else + echo "$addr" > "/sys/kernel/debug/cxl/$dev/${action}_poison" + fi +} + +inject_poison_sysfs() +{ + _do_poison_sysfs 'inject' "$@" +} + +clear_poison_sysfs() +{ + _do_poison_sysfs 'clear' "$@" +} + +check_trace_entry() +{ + local expected_region="$1" + local expected_hpa="$2" + + local trace_line + trace_line=$(grep "cxl_poison" /sys/kernel/tracing/trace | tail -n 1) + if [[ -z "$trace_line" ]]; then + echo "No cxl_poison trace event found" + err "$LINENO" + fi + + local trace_region trace_hpa + trace_region=$(echo "$trace_line" | grep -o 'region=[^ ]*' | cut -d= -f2) + trace_hpa=$(echo "$trace_line" | grep -o 'hpa=0x[0-9a-fA-F]\+' | cut -d= -f2) + + if [[ "$trace_region" != "$expected_region" ]]; then + echo "Expected region $expected_region not found in trace" + echo "$trace_line" + err "$LINENO" + fi + + if [[ "$trace_hpa" != "$expected_hpa" ]]; then + echo "Expected HPA $expected_hpa not found in trace" + echo "$trace_line" + err "$LINENO" + fi +} + +validate_poison_found() +{ + list_by="$1" + nr_expect="$2" + + poison_list="$($CXL list "$list_by" --media-errors | + jq -r '.[].media_errors')" + if [[ ! $poison_list ]]; then + nr_found=0 + else + nr_found=$(jq "length" <<< "$poison_list") + fi + if [ "$nr_found" -ne "$nr_expect" ]; then + echo "$nr_expect poison records expected, $nr_found found" + err "$LINENO" + fi +} + +test_poison_by_memdev_by_dpa() +{ + find_memdev + inject_poison_sysfs "$memdev" "0x40000000" + inject_poison_sysfs "$memdev" "0x40001000" + inject_poison_sysfs "$memdev" "0x600" + inject_poison_sysfs "$memdev" "0x0" + validate_poison_found "-m $memdev" 4 + + clear_poison_sysfs "$memdev" "0x40000000" + clear_poison_sysfs "$memdev" "0x40001000" + clear_poison_sysfs "$memdev" "0x600" + clear_poison_sysfs "$memdev" "0x0" + validate_poison_found "-m $memdev" 0 +} + +test_poison_by_region_by_dpa() +{ + inject_poison_sysfs "$mem0" "0" + inject_poison_sysfs "$mem1" "0" + validate_poison_found "-r $region" 2 + + clear_poison_sysfs "$mem0" "0" + clear_poison_sysfs "$mem1" "0" + validate_poison_found "-r $region" 0 +} + +test_poison_by_region_offset() +{ + local base gran hpa1 hpa2 + base=$(cat /sys/bus/cxl/devices/"$region"/resource) + gran=$(cat /sys/bus/cxl/devices/"$region"/interleave_granularity) + + # Test two HPA addresses: base and base + granularity + # This hits the two memdevs in the region interleave. + hpa1=$(printf "0x%x" $((base))) + hpa2=$(printf "0x%x" $((base + gran))) + + # Inject at the offset and check result using the hpa + # ABI takes an offset, but recall the hpa to check trace event + + inject_poison_sysfs "$region" 0 + check_trace_entry "$region" "$hpa1" + inject_poison_sysfs "$region" "$gran" + check_trace_entry "$region" "$hpa2" + validate_poison_found "-r $region" 2 + + clear_poison_sysfs "$region" 0 + check_trace_entry "$region" "$hpa1" + clear_poison_sysfs "$region" "$gran" + check_trace_entry "$region" "$hpa2" + validate_poison_found "-r $region" 0 +} + +test_poison_by_region_offset_negative() +{ + local region_size cache_size cache_offset exceed_offset large_offset + region_size=$(cat /sys/bus/cxl/devices/"$region"/size) + cache_size=0 + + # This case is a no-op until cxl-test ELC mocking arrives + # Try to get cache_size if the attribute exists + if [ -f "/sys/bus/cxl/devices/$region/extended_linear_cache_size" ]; then + cache_size=$(cat /sys/bus/cxl/devices/"$region"/extended_linear_cache_size) + fi + + # Offset within extended linear cache (if cache_size > 0) + if [[ $cache_size -gt 0 ]]; then + cache_offset=$((cache_size - 1)) + echo "Testing offset within cache: $cache_offset (cache_size: $cache_size)" + inject_poison_sysfs "$region" "$cache_offset" true + clear_poison_sysfs "$region" "$cache_offset" true + else + echo "Skipping cache test - cache_size is 0" + fi + + # Offset exceeds region size + exceed_offset=$((region_size)) + inject_poison_sysfs "$region" "$exceed_offset" true + clear_poison_sysfs "$region" "$exceed_offset" true + + # Offset exceeds region size by a lot + large_offset=$((region_size * 2)) + inject_poison_sysfs "$region" "$large_offset" true + clear_poison_sysfs "$region" "$large_offset" true +} + diff --git a/test/cxl-poison.sh b/test/cxl-poison.sh index 430780cf7128..b4caec0af12a 100644 --- a/test/cxl-poison.sh +++ b/test/cxl-poison.sh @@ -21,192 +21,7 @@ rc=1 # THEORY OF OPERATION: Exercise cxl-cli and cxl driver ability to # inject, clear, and get the poison list. Do it by memdev and by region. -find_memdev() -{ - readarray -t capable_mems < <("$CXL" list -b "$CXL_TEST_BUS" -M | - jq -r ".[] | select(.pmem_size != null) | - select(.ram_size != null) | .memdev") - - if [ ${#capable_mems[@]} == 0 ]; then - echo "no memdevs found for test" - err "$LINENO" - fi - - memdev=${capable_mems[0]} -} - -find_auto_region() -{ - region="$($CXL list -b "$CXL_TEST_BUS" -R | jq -r ".[0].region")" - [[ -n "$region" && "$region" != "null" ]] || do_skip "no test region found" - mem0="$($CXL list -r "$region" --targets | jq -r ".[0].mappings[0].memdev")" - [[ -n "$mem0" && "$mem0" != "null" ]] || do_skip "no region target0 found" - mem1="$($CXL list -r "$region" --targets | jq -r ".[0].mappings[1].memdev")" - [[ -n "$mem1" && "$mem1" != "null" ]] || do_skip "no region target1 found" - echo "$region" -} - -# When cxl-cli support for inject and clear arrives, replace -# the writes to /sys/kernel/debug with the new cxl commands. - -_do_poison_sysfs() -{ - local action="$1" dev="$2" addr="$3" - local expect_fail=${4:-false} - - if "$expect_fail"; then - if echo "$addr" > "/sys/kernel/debug/cxl/$dev/${action}_poison"; then - echo "Expected ${action}_poison to fail for $addr" - err "$LINENO" - fi - else - echo "$addr" > "/sys/kernel/debug/cxl/$dev/${action}_poison" - fi -} - -inject_poison_sysfs() -{ - _do_poison_sysfs 'inject' "$@" -} - -clear_poison_sysfs() -{ - _do_poison_sysfs 'clear' "$@" -} - -check_trace_entry() -{ - local expected_region="$1" - local expected_hpa="$2" - - local trace_line - trace_line=$(grep "cxl_poison" /sys/kernel/tracing/trace | tail -n 1) - if [[ -z "$trace_line" ]]; then - echo "No cxl_poison trace event found" - err "$LINENO" - fi - - local trace_region trace_hpa - trace_region=$(echo "$trace_line" | grep -o 'region=[^ ]*' | cut -d= -f2) - trace_hpa=$(echo "$trace_line" | grep -o 'hpa=0x[0-9a-fA-F]\+' | cut -d= -f2) - - if [[ "$trace_region" != "$expected_region" ]]; then - echo "Expected region $expected_region not found in trace" - echo "$trace_line" - err "$LINENO" - fi - - if [[ "$trace_hpa" != "$expected_hpa" ]]; then - echo "Expected HPA $expected_hpa not found in trace" - echo "$trace_line" - err "$LINENO" - fi -} - -validate_poison_found() -{ - list_by="$1" - nr_expect="$2" - - poison_list="$($CXL list "$list_by" --media-errors | - jq -r '.[].media_errors')" - if [[ ! $poison_list ]]; then - nr_found=0 - else - nr_found=$(jq "length" <<< "$poison_list") - fi - if [ "$nr_found" -ne "$nr_expect" ]; then - echo "$nr_expect poison records expected, $nr_found found" - err "$LINENO" - fi -} - -test_poison_by_memdev_by_dpa() -{ - find_memdev - inject_poison_sysfs "$memdev" "0x40000000" - inject_poison_sysfs "$memdev" "0x40001000" - inject_poison_sysfs "$memdev" "0x600" - inject_poison_sysfs "$memdev" "0x0" - validate_poison_found "-m $memdev" 4 - - clear_poison_sysfs "$memdev" "0x40000000" - clear_poison_sysfs "$memdev" "0x40001000" - clear_poison_sysfs "$memdev" "0x600" - clear_poison_sysfs "$memdev" "0x0" - validate_poison_found "-m $memdev" 0 -} - -test_poison_by_region_by_dpa() -{ - inject_poison_sysfs "$mem0" "0" - inject_poison_sysfs "$mem1" "0" - validate_poison_found "-r $region" 2 - - clear_poison_sysfs "$mem0" "0" - clear_poison_sysfs "$mem1" "0" - validate_poison_found "-r $region" 0 -} - -test_poison_by_region_offset() -{ - local base gran hpa1 hpa2 - base=$(cat /sys/bus/cxl/devices/"$region"/resource) - gran=$(cat /sys/bus/cxl/devices/"$region"/interleave_granularity) - - # Test two HPA addresses: base and base + granularity - # This hits the two memdevs in the region interleave. - hpa1=$(printf "0x%x" $((base))) - hpa2=$(printf "0x%x" $((base + gran))) - - # Inject at the offset and check result using the hpa - # ABI takes an offset, but recall the hpa to check trace event - - inject_poison_sysfs "$region" 0 - check_trace_entry "$region" "$hpa1" - inject_poison_sysfs "$region" "$gran" - check_trace_entry "$region" "$hpa2" - validate_poison_found "-r $region" 2 - - clear_poison_sysfs "$region" 0 - check_trace_entry "$region" "$hpa1" - clear_poison_sysfs "$region" "$gran" - check_trace_entry "$region" "$hpa2" - validate_poison_found "-r $region" 0 -} - -test_poison_by_region_offset_negative() -{ - local region_size cache_size cache_offset exceed_offset large_offset - region_size=$(cat /sys/bus/cxl/devices/"$region"/size) - cache_size=0 - - # This case is a no-op until cxl-test ELC mocking arrives - # Try to get cache_size if the attribute exists - if [ -f "/sys/bus/cxl/devices/$region/extended_linear_cache_size" ]; then - cache_size=$(cat /sys/bus/cxl/devices/"$region"/extended_linear_cache_size) - fi - - # Offset within extended linear cache (if cache_size > 0) - if [[ $cache_size -gt 0 ]]; then - cache_offset=$((cache_size - 1)) - echo "Testing offset within cache: $cache_offset (cache_size: $cache_size)" - inject_poison_sysfs "$region" "$cache_offset" true - clear_poison_sysfs "$region" "$cache_offset" true - else - echo "Skipping cache test - cache_size is 0" - fi - - # Offset exceeds region size - exceed_offset=$((region_size)) - inject_poison_sysfs "$region" "$exceed_offset" true - clear_poison_sysfs "$region" "$exceed_offset" true - - # Offset exceeds region size by a lot - large_offset=$((region_size * 2)) - inject_poison_sysfs "$region" "$large_offset" true - clear_poison_sysfs "$region" "$large_offset" true -} +. "$(dirname "$0")"/common-poison # Clear old trace events, enable cxl_poison, enable global tracing echo "" > /sys/kernel/tracing/trace -- 2.51.0
