From: Dave Jiang <dave.jiang@intel.com>
To: alison.schofield@intel.com, nvdimm@lists.linux.dev,
linux-cxl@vger.kernel.org
Subject: Re: [ndctl PATCH] cxl/test: add cxl_translate unit test
Date: Wed, 26 Jun 2024 09:44:42 -0700 [thread overview]
Message-ID: <9eadfb5a-5870-41c2-9031-7dc8405659e7@intel.com> (raw)
In-Reply-To: <20240624210644.495563-1-alison.schofield@intel.com>
On 6/24/24 2:06 PM, alison.schofield@intel.com wrote:
> From: Alison Schofield <alison.schofield@intel.com>
>
> cxl_translate.sh is added to the CXL unit test suite along with
> a C program 'translate' that performs the address translations.
>
> The test program performs the same calculations as the CXL driver
> while the script feeds the test program trusted samples.
>
> The trusted samples are either from the CXL Driver Writers
> Guide[1] or from another source that has been verified. ie a
> spreadsheet reviewed by CXL developers.
>
> [1] https://www.intel.com/content/www/us/en/content-details/643805/cxl-memory-device-sw-guide.html
>
> Signed-off-by: Alison Schofield <alison.schofield@intel.com>
Looks ok to me. This is a direct copy of the kernel translation code? Is the intention to keep them in sync?
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> ---
>
> More sample data is wanted. If you have a sample set or would be
> willing to review sample sets I generate, please reach out.
>
> The CXL Drivers Writers Guide update that includes the tables used
> here is under review and not yet available at the provided link.
>
>
> test/cxl-translate.sh | 215 ++++++++++++++++++++++++++++++++++++++++++
> test/meson.build | 6 ++
> test/translate.c | 163 ++++++++++++++++++++++++++++++++
> 3 files changed, 384 insertions(+)
> create mode 100755 test/cxl-translate.sh
> create mode 100644 test/translate.c
>
> diff --git a/test/cxl-translate.sh b/test/cxl-translate.sh
> new file mode 100755
> index 000000000000..be6d7f43a136
> --- /dev/null
> +++ b/test/cxl-translate.sh
> @@ -0,0 +1,215 @@
> +#!/bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (C) 2024 Intel Corporation. All rights reserved.
> +
> +. $(dirname $0)/common
> +
> +set -ex
> +trap 'err $LINENO' ERR
> +
> +rc=1
> +
> +TEST=$TEST_PATH/translate
> +MODULO=0
> +XOR=1
> +
> +# Test against 'Sample Sets' and 'XOR Tables'
> +#
> +# Sample Set's have a pattern and the expected HPAs have been verified
> +# although maybe not published. They verify Modulo and XOR translations.
> +#
> +# XOR Table's are extracted from the CXL Driver Writers Guide [1].
> +# Although the XOR Tables do not include an explicit check of the Modulo
> +# translation result, a Modulo calculation is always the first step in
> +# any XOR calculation. ie. if Modulo fails so does XOR.
> +#
> +# [1] https://www.intel.com/content/www/us/en/content-details/643805/cxl-memory-device-sw-guide.html
> +
> +
> +# Sample Sets
> +#
> +# params_#: dpa, region eiw, region eig, host bridge eiw
> +# expect_[modulo|xor]_#: expected hpa for each position in the region
> +# interleave set for the modulo|xor math.
> +#
> +# Feeds the parameters with an expected hpa for each position in the
> +# region interleave to TEST. The test performs the same calculations
> +# as the CXL Driver and returns success if its calculation matches
> +# the expected hpa.
> +
> +# 1+1+1+1
> +# 4 way region interleave using 4 host bridges
> +declare -A Sample_4R_4H=(
> + ["params_0"]="0 2 0 2"
> + ["expect_modulo_0"]="0 256 512 768"
> + ["expect_xor_0"]="0 256 512 768"
> + ["params_1"]="256 2 0 2"
> + ["expect_modulo_1"]="1024 1280 1536 1792"
> + ["expect_xor_1"]="1024 1280 1536 1792"
> + ["params_2"]="2048 2 0 2"
> + ["expect_modulo_2"]="8192 8448 8704 8960"
> + ["expect_xor_2"]="8192 8448 8704 8960"
> +)
> +
> +# 1+1+1+1+1+1+1+1+1+1+1+1
> +# 12 way region interleave using 12 host bridges
> +declare -A Sample_12R_12H=(
> + ["params_0"]="0 10 0 10"
> + ["expect_modulo_0"]="0 256 512 768 1024 1280 1536 1792 2048 2304 2560 2816"
> + ["expect_xor_0"]="0 256 512 768 1024 1280 1536 1792 2304 2048 2816 2560"
> + ["params_1"]="512 10 0 10"
> + ["expect_modulo_1"]="6144 6400 6656 6912 7168 7424 7680 7936 8192 8448 8704 8960"
> + ["expect_xor_1"]="6912 6656 6400 6144 7936 7680 7424 7168 8192 8448 8704 8960"
> +)
> +
> +decode_r_eiw()
> +{
> + case $1 in
> + 0) echo 1 ;;
> + 1) echo 2 ;;
> + 2) echo 4 ;;
> + 3) echo 8 ;;
> + 4) echo 16 ;;
> + 8) echo 3 ;;
> + 9) echo 6 ;;
> + 10) echo 12 ;;
> + *) echo "Invalid r_eiw value: $1" ; err "$LINENO" ;;
> + esac
> +}
> +
> +test_sample_set()
> +{
> + local -n sample_set=$1
> + local sample_count=$((${#sample_set[@]} / 3))
> +
> + for i in $(seq 0 $((sample_count - 1))); do
> + # Split the parameters and expected hpa values
> + IFS=' ' read -r dpa r_eiw r_eig hb_eiw <<< "${sample_set["params_$i"]}"
> + IFS=' ' read -r -a expect_modulo_values <<< "${sample_set["expect_modulo_$i"]}"
> + IFS=' ' read -r -a expect_xor_values <<< "${sample_set["expect_xor_$i"]}"
> +
> + ways=$(decode_r_eiw "$r_eiw")
> + for ((pos = 0; pos < ways; pos++)); do
> + expect_hpa_modulo=${expect_modulo_values[$pos]}
> + expect_hpa_xor=${expect_xor_values[$pos]}
> +
> + "$TEST" "$dpa" "$pos" "$r_eiw" "$r_eig" "$hb_eiw" $MODULO "$expect_hpa_modulo" || {
> + err "$LINENO"
> + }
> + "$TEST" "$dpa" "$pos" "$r_eiw" "$r_eig" "$hb_eiw" $XOR "$expect_hpa_xor" || {
> + err "$LINENO"
> + }
> + done
> + done
> +}
> +
> +# XOR Tables
> +#
> +# The tables that follow are the XOR translation examples in the
> +# CXL Driver Writers Guide Sections 2.13.24.1 and 25.1
> +#
> +# Format: "dpa pos r_eiw r_eig h_eiw xor_hpa:
> +
> +# 1+1+1+1
> +# 4 way region interleave using 4 host bridges
> +XOR_Table_4R_4H=(
> + "248 0 2 0 2 248"
> + "16 1 2 0 2 272"
> + "16 2 2 0 2 528"
> + "32 3 2 0 2 800"
> + "288 0 2 0 2 1056"
> + "288 1 2 0 2 1312"
> + "288 2 2 0 2 1568"
> + "288 3 2 0 2 1824"
> + "544 1 2 0 2 2080"
> + "544 0 2 0 2 2336"
> + "544 3 2 0 2 2592"
> + "1040 2 2 0 2 4112"
> + "1568 3 2 0 2 6176"
> + "32784 1 2 0 2 131088"
> + "65552 2 2 0 2 262160"
> + "98336 3 2 0 2 393248"
> + "98328 2 2 0 2 393496"
> + "98352 2 2 0 2 393520"
> + "443953523 0 2 0 2 1775813747"
> +)
> +
> +# 2+2+2+2
> +# 8 way region interleave using 4 host bridges
> +XOR_Table_8R_4H=(
> + "248 0 3 0 2 248"
> + "16 2 3 0 2 528"
> + "16 4 3 0 2 1040"
> + "32 6 3 0 2 1568"
> + "272 2 3 0 2 2832"
> + "528 4 3 0 2 5648"
> + "800 6 3 0 2 7456"
> + "16400 1 3 0 2 131088"
> + "32784 2 3 0 2 262160"
> + "49184 3 3 0 2 393248"
> + "49176 2 3 0 2 393496"
> + "49200 2 3 0 2 393520"
> + "116520373 3 3 0 2 932162229"
> + "244690459 5 3 0 2 1957525275"
> + "292862215 5 3 0 2 2342899463"
> + "30721158 4 3 0 2 245769350"
> + "246386959 4 3 0 2 1971096847"
> + "72701249 5 3 0 2 581610561"
> + "529382429 5 3 0 2 4235060509"
> + "191132300 2 3 0 2 1529057420"
> + "18589081 1 3 0 2 148712089"
> + "344295715 7 3 0 2 2754367011"
> +)
> +
> +# 1+1+1+1+1+1+1+1+1+1+1+1
> +# 12 way region interleave using 12 host bridges
> +XOR_Table_12R_12H=(
> + "224 0 10 0 10 224"
> + "16 1 10 0 10 272"
> + "16 2 10 0 10 528"
> + "32 3 10 0 10 800"
> + "32 4 10 0 10 1056"
> + "32 5 10 0 10 1312"
> + "32 6 10 0 10 1568"
> + "32 7 10 0 10 1824"
> + "32 9 10 0 10 2080"
> + "32 8 10 0 10 2336"
> + "32 11 10 0 10 2592"
> + "32 10 10 0 10 2848"
> + "288 0 10 0 10 3360"
> + "299017087 7 10 0 10 3588205439"
> + "329210435 0 10 0 10 3950524995"
> + "151050637 11 10 0 10 1812608653"
> + "145169214 2 10 0 10 1742030654"
> + "328998732 10 10 0 10 3947985996"
> + "159252439 3 10 0 10 1911027415"
> + "342098916 5 10 0 10 4105186020"
> + "97970344 8 10 0 10 1175645096"
> + "214995572 8 10 0 10 2579948404"
> + "101289661 7 10 0 10 1215475645"
> + "40424079 7 10 0 10 485088911"
> + "231458716 7 10 0 10 2777503900"
> +)
> +
> +test_xor_table()
> +{
> + local -n samples=$1
> +
> + for sample in "${samples[@]}"; do
> + IFS=' ' read -r dpa pos r_eiw r_eig hb_eiw xor_hpa <<< "$sample"
> +
> + "$TEST" "$dpa" "$pos" "$r_eiw" "$r_eig" "$hb_eiw" $XOR "$xor_hpa" || {
> + err "$LINENO"
> + }
> + done
> +}
> +
> +# Process Samples
> +test_sample_set Sample_4R_4H
> +test_sample_set Sample_12R_12H
> +
> +test_xor_table XOR_Table_4R_4H
> +test_xor_table XOR_Table_8R_4H
> +test_xor_table XOR_Table_12R_12H
> +
> +echo "All samples processed successfully"
> diff --git a/test/meson.build b/test/meson.build
> index a965a79fd6cb..f15a97a12b47 100644
> --- a/test/meson.build
> +++ b/test/meson.build
> @@ -132,6 +132,10 @@ revoke_devmem = executable('revoke_devmem', testcore + [
>
> mmap = executable('mmap', 'mmap.c',)
>
> +translate = executable('translate', 'translate.c',
> + include_directories : root_inc,
> +)
> +
> create = find_program('create.sh')
> clear = find_program('clear.sh')
> pmem_errors = find_program('pmem-errors.sh')
> @@ -160,6 +164,7 @@ cxl_events = find_program('cxl-events.sh')
> cxl_sanitize = find_program('cxl-sanitize.sh')
> cxl_destroy_region = find_program('cxl-destroy-region.sh')
> cxl_qos_class = find_program('cxl-qos-class.sh')
> +cxl_translate = find_program('cxl-translate.sh')
>
> tests = [
> [ 'libndctl', libndctl, 'ndctl' ],
> @@ -192,6 +197,7 @@ tests = [
> [ 'cxl-sanitize.sh', cxl_sanitize, 'cxl' ],
> [ 'cxl-destroy-region.sh', cxl_destroy_region, 'cxl' ],
> [ 'cxl-qos-class.sh', cxl_qos_class, 'cxl' ],
> + [ 'cxl-translate.sh', cxl_translate, 'cxl' ],
> ]
>
> if get_option('destructive').enabled()
> diff --git a/test/translate.c b/test/translate.c
> new file mode 100644
> index 000000000000..e39637d6a8e1
> --- /dev/null
> +++ b/test/translate.c
> @@ -0,0 +1,163 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (C) 2024 Intel Corporation. All rights reserved.
> +#include <inttypes.h>
> +#include <limits.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include <ccan/short_types/short_types.h>
> +
> +/* Mimic kernel macros */
> +#define BITS_PER_LONG_LONG 64
> +#define GENMASK_ULL(h, l) \
> + (((~(0)) - ((1) << (l)) + 1) & (~(0) >> (BITS_PER_LONG_LONG - 1 - (h))))
> +
> +#define XOR_MATH 1
> +
> +static int hweight64(u64 value)
> +{
> + int count = 0;
> +
> + while (value) {
> + count += value & 1;
> + value >>= 1;
> + }
> + return count;
> +}
> +
> +static u64 __restore_xor_pos(u64 hpa, u64 map)
> +{
> + u64 val;
> + int pos;
> +
> + if (!map)
> + return hpa;
> +
> + /* XOR of all set bits */
> + val = (hweight64(hpa & map)) & 1;
> +
> + /* Find the lowest set bit in the map */
> + pos = ffs(map) - 1;
> +
> + /* Set bit at hpa[pos] to val */
> + hpa = (hpa & ~(1ULL << pos)) | (val << pos);
> +
> + return hpa;
> +}
> +
> +static u64 restore_xor_pos(u64 hpa_offset, u8 eiw)
> +{
> + u64 temp_a, temp_b, temp_c;
> +
> + switch (eiw) {
> + case 0: /* 1-way */
> + case 8: /* 3-way */
> + return hpa_offset;
> +
> + /*
> + * These map values were selected to match the samples
> + * in the CXL Drivers Writers Guide for Host Bridge
> + * Interleaves at HBIG 0: 0x2020900, 0x4041200
> + *
> + * TODO Add the xormaps as test parameters.
> + */
> + case 1: /* 2-way */
> + return __restore_xor_pos(hpa_offset, 0x2020900);
> +
> + case 2: /* 4-way */
> + temp_a = __restore_xor_pos(hpa_offset, 0x2020900);
> + return __restore_xor_pos(temp_a, 0x4041200);
> +
> + case 3: /* 8-way */
> + temp_a = __restore_xor_pos(hpa_offset, 0x2020900);
> + temp_b = __restore_xor_pos(temp_a, 0x4041200);
> + return __restore_xor_pos(temp_b, 0x1010400);
> +
> + case 4: /* 16-way */
> + temp_a = __restore_xor_pos(hpa_offset, 0x2020900);
> + temp_b = __restore_xor_pos(temp_a, 0x4041200);
> + temp_c = __restore_xor_pos(temp_b, 0x1010400);
> + return __restore_xor_pos(temp_c, 0x800);
> +
> + case 9: /* 6-way */
> + return __restore_xor_pos(hpa_offset, 0x2020900);
> +
> + case 10: /* 12-way */
> + temp_a = __restore_xor_pos(hpa_offset, 0x2020900);
> + return __restore_xor_pos(temp_a, 0x4041200);
> +
> + default:
> + return ULLONG_MAX;
> + }
> +
> + return ULLONG_MAX;
> +}
> +
> +static u64 to_hpa(u64 dpa_offset, int pos, u8 eiw, u16 eig, u8 hb_eiw, u8 math)
> +{
> + u64 mask_upper, mask_lower;
> + u64 bits_upper, bits_lower;
> + u64 hpa_offset;
> +
> + /*
> + * Translate DPA->HPA by reversing the HPA->DPA decoder logic
> + * defined in CXL Spec 3.0 Section 8.2.4.19.13 Implementation
> + * Note: Device Decode Logic
> + *
> + * Insert the 'pos' to construct the HPA.
> + */
> + mask_upper = GENMASK_ULL(51, eig + 8);
> +
> + if (eiw < 8) {
> + hpa_offset = (dpa_offset & mask_upper) << eiw;
> + hpa_offset |= pos << (eig + 8);
> + } else {
> + bits_upper = (dpa_offset & mask_upper) >> (eig + 8);
> + bits_upper = bits_upper * 3;
> + hpa_offset = ((bits_upper << (eiw - 8)) + pos) << (eig + 8);
> + }
> +
> + /* Lower bits don't change */
> + mask_lower = (1 << (eig + 8)) - 1;
> + bits_lower = dpa_offset & mask_lower;
> + hpa_offset += bits_lower;
> +
> + if (math == XOR_MATH)
> + hpa_offset = restore_xor_pos(hpa_offset, hb_eiw);
> +
> + return hpa_offset;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + u8 region_eiw, hostbridge_eiw;
> + u64 dpa, expect_hpa, hpa;
> + u16 region_eig;
> + int math, pos;
> +
> + if (argc != 8) {
> + printf("Usage: %s <dpa> <pos> <region_eiw> <region_eig> <host_eiw> <math> <hpa>\n",
> + argv[0]);
> + return EXIT_FAILURE;
> + }
> +
> + dpa = strtoull(argv[1], NULL, 0);
> + pos = atoi(argv[2]);
> + region_eiw = strtoul(argv[3], NULL, 0);
> + region_eig = strtoul(argv[4], NULL, 0);
> + hostbridge_eiw = strtoul(argv[5], NULL, 0);
> + math = atoi(argv[6]);
> + expect_hpa = strtoull(argv[7], NULL, 0);
> +
> + hpa = to_hpa(dpa, pos, region_eiw, region_eig, hostbridge_eiw, math);
> +
> + if (hpa != expect_hpa) {
> + printf("Fail: expected_hpa %lu translated_hpa:%lu\n",
> + expect_hpa, hpa);
> + return EXIT_FAILURE;
> + }
> + printf("Pass: expected_hpa %lu translated_hpa:%lu\n", expect_hpa, hpa);
> +
> + return 0;
> +}
>
> base-commit: 16f45755f991f4fb6d76fec70a42992426c84234
next prev parent reply other threads:[~2024-06-26 16:44 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-06-24 21:06 [ndctl PATCH] cxl/test: add cxl_translate unit test alison.schofield
2024-06-26 16:44 ` Dave Jiang [this message]
2024-06-27 1:38 ` Dan Williams
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=9eadfb5a-5870-41c2-9031-7dc8405659e7@intel.com \
--to=dave.jiang@intel.com \
--cc=alison.schofield@intel.com \
--cc=linux-cxl@vger.kernel.org \
--cc=nvdimm@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox