Resctrl CAT selftests have been limited to mainly testing performance.
In order to validate the kernel side behavior better, add a functional
test that checks the MSR contents (if MSRs are accessible). As the
low-level mapping is architecture specific, this test is currently
limited to testing resctrl only on Intel CPUs.

Signed-off-by: Ilpo Järvinen <ilpo.jarvi...@linux.intel.com>
---
 tools/testing/selftests/resctrl/cat_test.c    | 126 ++++++++++++++++++
 tools/testing/selftests/resctrl/msr.c         |  55 ++++++++
 tools/testing/selftests/resctrl/resctrl.h     |   4 +
 .../testing/selftests/resctrl/resctrl_tests.c |   1 +
 4 files changed, 186 insertions(+)
 create mode 100644 tools/testing/selftests/resctrl/msr.c

diff --git a/tools/testing/selftests/resctrl/cat_test.c 
b/tools/testing/selftests/resctrl/cat_test.c
index 78cb9ac90bb1..fbe1d2f7657f 100644
--- a/tools/testing/selftests/resctrl/cat_test.c
+++ b/tools/testing/selftests/resctrl/cat_test.c
@@ -9,8 +9,15 @@
  *    Fenghua Yu <fenghua...@intel.com>
  */
 #include "resctrl.h"
+
+#include <string.h>
 #include <unistd.h>
 
+#define MSR_IA32_PQR_ASSOC     0xc8f
+#define  MSR_IA32_PQR_ASSOC_COS        0xffffffff00000000ULL
+
+#define MSR_IA32_L3_CBM_BASE   0xc90
+
 #define RESULT_FILE_NAME       "result_cat"
 #define NUM_OF_RUNS            5
 
@@ -452,6 +459,116 @@ static int cat_ctrlgrp_tasks_test(const struct 
resctrl_test *test,
        return ret;
 }
 
+static int cat_ctrlgrp_check_msr(const struct user_params *uparams,
+                                unsigned long mask)
+{
+       __u64 msr_val;
+       __u32 clos;
+       int ret;
+
+       ret = read_msr(uparams->cpu, MSR_IA32_PQR_ASSOC, &msr_val);
+       if (ret)
+               return -1;
+
+       clos = (msr_val & MSR_IA32_PQR_ASSOC_COS) >> 
(ffsl(MSR_IA32_PQR_ASSOC_COS) - 1);
+
+       ret = read_msr(uparams->cpu, MSR_IA32_L3_CBM_BASE + clos, &msr_val);
+       if (ret)
+               return -1;
+
+       if (msr_val != mask) {
+               ksft_print_msg("Incorrect CBM mask %llx, should be %lx\n",
+                              msr_val, mask);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int cat_ctrlgrp_msr_test(const struct resctrl_test *test,
+                               const struct user_params *uparams)
+{
+       unsigned long mask1 = 0x3, mask2 = 0x6, mask3 = 0x0c;
+       cpu_set_t old_affinity;
+       char schemata[64];
+       pid_t bm_pid;
+       int ret;
+
+       bm_pid = getpid();
+
+       if (!msr_access_supported(uparams->cpu)) {
+               ksft_test_result_skip("Cannot access MSRs\n");
+               return 0;
+       }
+
+       ret = resctrl_grp_has_task(NULL, bm_pid);
+       if (ret < 0)
+               return ret;
+       if (!ret) {
+               ksft_print_msg("PID not found in the root group\n");
+               return 1;
+       }
+
+       /* Taskset benchmark to specified CPU */
+       ksft_print_msg("Placing task to ctrlgrp 'c1'\n");
+       ret = taskset_benchmark(bm_pid, uparams->cpu, &old_affinity);
+       if (ret)
+               return ret;
+       ret = write_bm_pid_to_resctrl(bm_pid, "c1", NULL);
+       if (ret)
+               goto reset_affinity;
+       snprintf(schemata, sizeof(schemata), "%lx", mask1);
+       ret = write_schemata("c1", schemata, uparams->cpu, test->resource);
+       if (ret)
+               goto reset_affinity;
+       ret = cat_ctrlgrp_check_msr(uparams, mask1);
+       if (ret)
+               goto reset_affinity;
+
+       ksft_print_msg("Placing task to ctrlgrp 'c2'\n");
+       ret = write_bm_pid_to_resctrl(bm_pid, "c2", NULL);
+       if (ret)
+               goto reset_affinity;
+       snprintf(schemata, sizeof(schemata), "%lx", mask2);
+       ret = write_schemata("c2", schemata, uparams->cpu, test->resource);
+       if (ret)
+               goto reset_affinity;
+       ret = cat_ctrlgrp_check_msr(uparams, mask2);
+       if (ret)
+               goto reset_affinity;
+
+       ksft_print_msg("Adjusting CBM for unrelated ctrlgrp 'c1'\n");
+       snprintf(schemata, sizeof(schemata), "%lx", mask3);
+       ret = write_schemata("c1", schemata, uparams->cpu, test->resource);
+       if (ret)
+               goto reset_affinity;
+       ret = cat_ctrlgrp_check_msr(uparams, mask2);
+       if (ret)
+               goto reset_affinity;
+
+       ksft_print_msg("Adjusting CBM for ctrlgrp 'c2'\n");
+       snprintf(schemata, sizeof(schemata), "%lx", mask1);
+       ret = write_schemata("c2", schemata, uparams->cpu, test->resource);
+       if (ret)
+               goto reset_affinity;
+       ret = cat_ctrlgrp_check_msr(uparams, mask1);
+       if (ret)
+               goto reset_affinity;
+
+       ksft_print_msg("Placing task to ctrlgrp 'c1'\n");
+       ret = write_bm_pid_to_resctrl(bm_pid, "c1", NULL);
+       if (ret)
+               goto reset_affinity;
+       ret = cat_ctrlgrp_check_msr(uparams, mask3);
+       if (ret)
+               goto reset_affinity;
+
+reset_affinity:
+       taskset_restore(bm_pid, &old_affinity);
+
+       return ret;
+}
+
 struct resctrl_test l3_cat_test = {
        .name = "L3_CAT",
        .group = "CAT",
@@ -484,3 +601,12 @@ struct resctrl_test cat_grp_tasks_test = {
        .feature_check = test_resource_feature_check,
        .run_test = cat_ctrlgrp_tasks_test,
 };
+
+struct resctrl_test cat_grp_mask_test = {
+       .name = "CAT_GROUP_MASK",
+       .group = "CAT",
+       .resource = "L3",
+       .vendor_specific = ARCH_INTEL,
+       .feature_check = test_resource_feature_check,
+       .run_test = cat_ctrlgrp_msr_test,
+};
diff --git a/tools/testing/selftests/resctrl/msr.c 
b/tools/testing/selftests/resctrl/msr.c
new file mode 100644
index 000000000000..1e8674036c7d
--- /dev/null
+++ b/tools/testing/selftests/resctrl/msr.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <fcntl.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <linux/types.h>
+
+#include "resctrl.h"
+
+#define MSR_PATH       "/dev/cpu/%d/msr"
+
+static int open_msr_file(int cpu)
+{
+       char msr_path[PATH_MAX];
+
+       snprintf(msr_path, sizeof(msr_path), MSR_PATH, cpu);
+
+       return open(msr_path, O_RDONLY);
+}
+
+int read_msr(int cpu, __u32 msr, __u64 *val)
+{
+       ssize_t res;
+       int fd;
+
+       fd = open_msr_file(cpu);
+       if (fd < 0) {
+               ksft_print_msg("Failed to open msr file for CPU %d\n", cpu);
+               return -1;
+       }
+
+       res = pread(fd, val, sizeof(*val), msr);
+       close(fd);
+       if (res < sizeof(*val)) {
+               ksft_print_msg("Reading MSR failed\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+bool msr_access_supported(int cpu)
+{
+       int fd;
+
+       fd = open_msr_file(cpu);
+       if (fd < 0)
+               return false;
+
+       close(fd);
+       return true;
+}
diff --git a/tools/testing/selftests/resctrl/resctrl.h 
b/tools/testing/selftests/resctrl/resctrl.h
index d25f83d0a54d..909a101f0e4c 100644
--- a/tools/testing/selftests/resctrl/resctrl.h
+++ b/tools/testing/selftests/resctrl/resctrl.h
@@ -243,8 +243,12 @@ extern struct resctrl_test mbm_test;
 extern struct resctrl_test mba_test;
 extern struct resctrl_test cmt_test;
 extern struct resctrl_test cat_grp_tasks_test;
+extern struct resctrl_test cat_grp_mask_test;
 extern struct resctrl_test l3_cat_test;
 extern struct resctrl_test l3_noncont_cat_test;
 extern struct resctrl_test l2_noncont_cat_test;
 
+bool msr_access_supported(int cpu);
+int read_msr(int cpu, __u32 msr, __u64 *val);
+
 #endif /* RESCTRL_H */
diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c 
b/tools/testing/selftests/resctrl/resctrl_tests.c
index 71b7cd846dc1..08ae48165c7a 100644
--- a/tools/testing/selftests/resctrl/resctrl_tests.c
+++ b/tools/testing/selftests/resctrl/resctrl_tests.c
@@ -19,6 +19,7 @@ static struct resctrl_test *resctrl_tests[] = {
        &mba_test,
        &cmt_test,
        &cat_grp_tasks_test,
+       &cat_grp_mask_test,
        &l3_cat_test,
        &l3_noncont_cat_test,
        &l2_noncont_cat_test,
-- 
2.39.5


Reply via email to