[PATCH v1] tests/intel/xe_ras: Introduce error threshold
Raag Jadav <[email protected]>
| Newsgroups | org.freedesktop.lists.igt-dev |
|---|---|
| Message-ID | <[email protected]> |
Introduce error threshold test as part of xe_ras. This will serve as a foundation for all RAS related tests moving forward. Signed-off-by: Raag Jadav <[email protected]> --- include/drm-uapi/drm_ras.h | 53 ++++++++ meson.build | 3 + tests/intel/xe_ras.c | 242 +++++++++++++++++++++++++++++++++++++ tests/meson.build | 2 + 4 files changed, 300 insertions(+) create mode 100644 include/drm-uapi/drm_ras.h create mode 100644 tests/intel/xe_ras.c diff --git a/include/drm-uapi/drm_ras.h b/include/drm-uapi/drm_ras.h new file mode 100644 index 000000000..27c689564 --- /dev/null +++ b/include/drm-uapi/drm_ras.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/drm_ras.yaml */ +/* YNL-GEN uapi header */ +/* To regenerate run: tools/net/ynl/ynl-regen.sh */ + +#ifndef _UAPI_LINUX_DRM_RAS_H +#define _UAPI_LINUX_DRM_RAS_H + +#define DRM_RAS_FAMILY_NAME "drm-ras" +#define DRM_RAS_FAMILY_VERSION 1 + +/* + * Type of the node. Currently, only error-counter nodes are supported, which + * expose reliability counters for a hardware/software component. + */ +enum drm_ras_node_type { + DRM_RAS_NODE_TYPE_ERROR_COUNTER = 1, +}; + +enum { + DRM_RAS_A_NODE_ATTRS_NODE_ID = 1, + DRM_RAS_A_NODE_ATTRS_DEVICE_NAME, + DRM_RAS_A_NODE_ATTRS_NODE_NAME, + DRM_RAS_A_NODE_ATTRS_NODE_TYPE, + + __DRM_RAS_A_NODE_ATTRS_MAX, + DRM_RAS_A_NODE_ATTRS_MAX = (__DRM_RAS_A_NODE_ATTRS_MAX - 1) +}; + +enum { + DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID = 1, + DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID, + DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_NAME, + DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_VALUE, + DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD, + + __DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX, + DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX = (__DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX - 1) +}; + +enum { + DRM_RAS_CMD_LIST_NODES = 1, + DRM_RAS_CMD_GET_ERROR_COUNTER, + DRM_RAS_CMD_CLEAR_ERROR_COUNTER, + DRM_RAS_CMD_GET_ERROR_THRESHOLD, + DRM_RAS_CMD_SET_ERROR_THRESHOLD, + + __DRM_RAS_CMD_MAX, + DRM_RAS_CMD_MAX = (__DRM_RAS_CMD_MAX - 1) +}; + +#endif /* _UAPI_LINUX_DRM_RAS_H */ diff --git a/meson.build b/meson.build index 980fb6421..5ef0b4edf 100644 --- a/meson.build +++ b/meson.build @@ -153,6 +153,9 @@ libpci = dependency('libpci', required : true) libudev = dependency('libudev', required : true) glib = dependency('glib-2.0', required : true) +libnl = dependency('libnl-3.0', required: true) +libnl_genl = dependency('libnl-genl-3.0', required: true) + libtsi = cc.find_library('TSI', required : false) if libtsi.found() diff --git a/tests/intel/xe_ras.c b/tests/intel/xe_ras.c new file mode 100644 index 000000000..91f624d9f --- /dev/null +++ b/tests/intel/xe_ras.c @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2026 Intel Corporation + */ + +/** + * TEST: Check Reliability Availability Serviceability + * Category: Core + * Mega feature: RAS + * Sub-category: Error handling tests + * Test category: functionality test + */ + +#include <limits.h> +#include <netlink/socket.h> +#include <netlink/genl/ctrl.h> +#include <netlink/genl/genl.h> + +#include "igt.h" +#include "lib/igt_device.h" +#include "lib/igt_sysfs.h" + +#include "xe_drm.h" +#include "drm_ras.h" + +static const char * const error_severity[] = DRM_XE_RAS_ERROR_SEVERITY_NAMES; + +typedef struct { + int fd_xe; + int sysfs_fd; + struct pci_device *pci_xe; + struct nl_sock *sock; + struct nl_cb *cb; + int family_id; + uint32_t node_id; + uint32_t error_id; + uint32_t threshold; +} xe_ras_t; + +static void init_ras_ctx(xe_ras_t *ctx) +{ + int ret; + + ctx->fd_xe = drm_open_driver(DRIVER_XE); + ctx->sysfs_fd = igt_sysfs_open(ctx->fd_xe); + ctx->pci_xe = igt_device_get_pci_device(ctx->fd_xe); + + ctx->sock = nl_socket_alloc(); + igt_assert_f(ctx->sock, "Failed to allocate nl_sock"); + + ret = genl_connect(ctx->sock); + igt_assert_f(!ret, "Failed to connect nl_sock: %s\n", nl_geterror(ret)); + + ctx->family_id = genl_ctrl_resolve(ctx->sock, DRM_RAS_FAMILY_NAME); + igt_require_f(ctx->family_id >= 0, "drm-ras family not found\n"); +} + +static void cleanup_ras_ctx(xe_ras_t *ctx) +{ + nl_close(ctx->sock); + nl_socket_free(ctx->sock); + + close(ctx->sysfs_fd); + drm_close_driver(ctx->fd_xe); +} + +static uint32_t nlattr_max(uint32_t cmd) +{ + if (cmd == DRM_RAS_CMD_LIST_NODES) + return DRM_RAS_A_NODE_ATTRS_MAX; + else + return DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX; +} + +static int nl_cb(struct nl_msg *msg, void *arg) +{ + struct nlmsghdr *nlh = nlmsg_hdr(msg); + struct genlmsghdr *gnlh = nlmsg_data(nlh); + struct nlattr *attrs[UCHAR_MAX]; + int ret, cmd = gnlh->cmd; + xe_ras_t *ctx = arg; + + ret = genlmsg_parse(nlh, 0, attrs, nlattr_max(cmd), NULL); + if (ret) { + igt_warn("Failed to parse nl msg: %s\n", nl_geterror(ret)); + return NL_SKIP; + } + + switch (cmd) { + case DRM_RAS_CMD_LIST_NODES: { + char *device_name, *node_name, pci_name[UCHAR_MAX]; + struct pci_device *pci = ctx->pci_xe; + + if (!attrs[DRM_RAS_A_NODE_ATTRS_DEVICE_NAME]) { + igt_warn("Device name attribute not found\n"); + return NL_SKIP; + } + + if (!attrs[DRM_RAS_A_NODE_ATTRS_NODE_NAME]) { + igt_warn("Node name attribute not found\n"); + return NL_SKIP; + } + + if (!attrs[DRM_RAS_A_NODE_ATTRS_NODE_ID]) { + igt_warn("Node id attribute not found\n"); + return NL_SKIP; + } + + device_name = nla_get_string(attrs[DRM_RAS_A_NODE_ATTRS_DEVICE_NAME]); + node_name = nla_get_string(attrs[DRM_RAS_A_NODE_ATTRS_NODE_NAME]); + + snprintf(pci_name, UCHAR_MAX, "%04x:%02x:%02x.%01x", + pci->domain, pci->bus, pci->dev, pci->func); + + if (strcmp(node_name, error_severity[DRM_XE_RAS_ERR_SEV_CORRECTABLE]) || + strcmp(device_name, pci_name)) + return NL_SKIP; + + ctx->node_id = nla_get_u32(attrs[DRM_RAS_A_NODE_ATTRS_NODE_ID]); + return NL_OK; + } + case DRM_RAS_CMD_SET_ERROR_THRESHOLD: + return NL_OK; + case DRM_RAS_CMD_GET_ERROR_THRESHOLD: + if (!attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD]) { + igt_warn("Error threshold attribute not found\n"); + return NL_SKIP; + } + + ctx->threshold = nla_get_u32(attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD]); + return NL_OK; + default: + return NL_SKIP; + } +} + +static void prepare_nl_msg(xe_ras_t *ctx, struct nl_msg *msg, uint32_t cmd) +{ + int ret; + + switch (cmd) { + case DRM_RAS_CMD_LIST_NODES: + break; + case DRM_RAS_CMD_SET_ERROR_THRESHOLD: + ret = nla_put_u32(msg, DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD, ctx->threshold); + igt_assert_f(!ret, "Failed to put error threshold: %s\n", nl_geterror(ret)); + /* fallthrough */ + case DRM_RAS_CMD_GET_ERROR_THRESHOLD: + ret = nla_put_u32(msg, DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID, ctx->node_id); + igt_assert_f(!ret, "Failed to put node id: %s\n", nl_geterror(ret)); + + ret = nla_put_u32(msg, DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID, ctx->error_id); + igt_assert_f(!ret, "Failed to put error id: %s\n", nl_geterror(ret)); + break; + default: + igt_assert_f(0, "Invalid command: %u\n", cmd); + } +} + +static uint32_t nlmsg_flags(uint32_t cmd) +{ + uint32_t flags = NLM_F_REQUEST | NLM_F_ACK; + + if (cmd == DRM_RAS_CMD_LIST_NODES) + flags |= NLM_F_DUMP; + + return flags; +} + +static void test_cmd(xe_ras_t *ctx, uint32_t cmd) +{ + struct nl_msg *msg; + void *msg_head; + int ret; + + msg = nlmsg_alloc(); + igt_assert_f(msg, "Failed to allocate nl_msg\n"); + + msg_head = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, ctx->family_id, 0, + nlmsg_flags(cmd), cmd, DRM_RAS_FAMILY_VERSION); + igt_require_f(msg_head, "Failed to add nl msg header\n"); + + prepare_nl_msg(ctx, msg, cmd); + + ret = nl_socket_modify_cb(ctx->sock, NL_CB_VALID, NL_CB_CUSTOM, nl_cb, ctx); + igt_assert_f(!ret, "Failed to modify cb: %s\n", nl_geterror(ret)); + + ret = nl_send_auto(ctx->sock, msg); + igt_assert_f(ret > 0, "Failed to send nl msg: %s\n", nl_geterror(ret)); + + ret = nl_recvmsgs_default(ctx->sock); + igt_assert_f(!ret, "Failed to receive nl msg: %s\n", nl_geterror(ret)); + + nlmsg_free(msg); +} + +/** + * SUBTEST: error-threshold + * Description: test get/set error threshold of the counter + * Functionality: RAS + * GPU requirements: DRM RAS feature should be supported + */ +static void test_error_threshold(xe_ras_t *ctx) +{ + ctx->node_id = UINT_MAX; + + test_cmd(ctx, DRM_RAS_CMD_LIST_NODES); + + /* drm_ras is missing */ + igt_skip_on(ctx->node_id == UINT_MAX); + igt_info("node id: %d\n", ctx->node_id); + + ctx->error_id = DRM_XE_RAS_ERR_COMP_CORE_COMPUTE; + igt_info("error id: %d\n", ctx->error_id); + + test_cmd(ctx, DRM_RAS_CMD_GET_ERROR_THRESHOLD); + igt_info("get error threshold: %u\n", ctx->threshold); + + test_cmd(ctx, DRM_RAS_CMD_SET_ERROR_THRESHOLD); + igt_info("set error threshold: %u\n", ctx->threshold); +} + +int igt_main() +{ + xe_ras_t ctx; + + igt_fixture() { + memset(&ctx, 0, sizeof(ctx)); + init_ras_ctx(&ctx); + + igt_install_exit_handler(igt_drm_debug_mask_reset_exit_handler); + update_debug_mask_if_ci(DRM_UT_KMS); + } + + igt_subtest_f("error-threshold") { + test_error_threshold(&ctx); + } + + igt_fixture() { + cleanup_ras_ctx(&ctx); + } +} diff --git a/tests/meson.build b/tests/meson.build index a62f447df..2ebdc74da 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -333,6 +333,7 @@ intel_xe_progs = [ 'xe_prime_self_import', 'xe_pxp', 'xe_query', + 'xe_ras', 'xe_render_copy', 'xe_vm', 'xe_userptr_pressure', @@ -429,6 +430,7 @@ extra_dependencies = { 'xe_fault_injection': [ lib_igt_xe_oa ], 'xe_oa': [ lib_igt_xe_oa ], 'xe_compute': [ igt_deps,lib_igt_perf,lib_igt_profiling,math ], + 'xe_ras': [ libnl, libnl_genl ], } test_executables = [] -- 2.43.0