[PATCH 2/8] lib/igt_drm_netlink: add get_error_counter support
Ravi Kishore Koppuravuri <[email protected]> Wed, 29 Jul 2026 17:49:53 +0530
| Newsgroups | org.freedesktop.lists.igt-dev |
|---|---|
| Message-ID | <[email protected]> |
Add netlink request/response handling for DRM_RAS_CMD_GET_ERROR_COUNTER. Signed-off-by: Ravi Kishore Koppuravuri <[email protected]> --- lib/igt_drm_netlink.c | 179 +++++++++++++++++++++++++++++++++++++++++- lib/igt_drm_netlink.h | 11 +++ 2 files changed, 188 insertions(+), 2 deletions(-) diff --git a/lib/igt_drm_netlink.c b/lib/igt_drm_netlink.c index 1c07bb2db..4d543275d 100644 --- a/lib/igt_drm_netlink.c +++ b/lib/igt_drm_netlink.c @@ -5,6 +5,7 @@ #include <stdbool.h> #include <stdint.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -17,6 +18,146 @@ #include "igt_core.h" #include "igt_drm_netlink.h" +static int ras_command_cb(struct nl_msg *msg, void *arg) +{ + struct app_context *ctx = arg; + struct nlmsghdr *nlh; + struct genlmsghdr *gnlh; + int ret; + + nlh = nlmsg_hdr(msg); + gnlh = nlmsg_data(nlh); + + switch (gnlh->cmd) { + case DRM_RAS_CMD_GET_ERROR_COUNTER: { + struct nlattr *attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX + 1]; + + ret = genlmsg_parse(nlh, 0, attrs, + DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX, NULL); + if (ret < 0) + return NL_SKIP; + + if (!attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_VALUE]) + return NL_SKIP; + + ctx->error_value = nla_get_u32(attrs[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_VALUE]); + break; + } + default: + return NL_SKIP; + } + + return NL_OK; +} + +static int send_and_recv_nl_msg(struct app_context *ctx, + struct nl_cb *cb, + struct nl_msg *msg) +{ + int ret; + + ret = nl_send_auto(ctx->sock, msg); + nlmsg_free(msg); + if (ret < 0) { + nl_cb_put(cb); + return ret; + } + + ret = nl_recvmsgs(ctx->sock, cb); + nl_cb_put(cb); + + return ret; +} + +static int send_command(struct app_context *ctx, uint8_t cmd) +{ + struct nl_cb *cb; + struct nl_msg *msg; + void *msg_head; + int ret; + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + msg_head = genlmsg_put(msg, + NL_AUTO_PORT, + NL_AUTO_SEQ, + ctx->family_id, + 0, + NLM_F_REQUEST | NLM_F_ACK, + cmd, + DRM_RAS_FAMILY_VERSION); + if (!msg_head) { + nlmsg_free(msg); + return -ENOMEM; + } + + switch (cmd) { + case DRM_RAS_CMD_GET_ERROR_COUNTER: + ret = nla_put_u32(msg, + DRM_RAS_A_ERROR_COUNTER_ATTRS_NODE_ID, + ctx->node_id); + if (ret < 0) { + nlmsg_free(msg); + return ret; + } + + ret = nla_put_u32(msg, + DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_ID, + ctx->error_id); + if (ret < 0) { + nlmsg_free(msg); + return ret; + } + break; + default: + nlmsg_free(msg); + return -EOPNOTSUPP; + } + + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) { + nlmsg_free(msg); + return -ENOMEM; + } + + ret = nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, ras_command_cb, ctx); + if (ret < 0) { + nl_cb_put(cb); + nlmsg_free(msg); + return ret; + } + + return send_and_recv_nl_msg(ctx, cb, msg); +} + +int init_app_context(struct app_context *ctx) +{ + if (!ctx) + return -EINVAL; + + ctx->sock = NULL; + ctx->node_id = UINT32_MAX; + ctx->error_id = UINT32_MAX; + ctx->error_value = 0; + ctx->family_id = -1; + + return 0; +} + +void cleanup_app_context(struct app_context *ctx) +{ + if (!ctx) + return; + + ctx->sock = NULL; + ctx->node_id = UINT32_MAX; + ctx->error_id = UINT32_MAX; + ctx->error_value = 0; + ctx->family_id = -1; +} + void cleanup_nl_socket(struct app_context *ctx) { if (!ctx || !ctx->sock) @@ -24,14 +165,20 @@ void cleanup_nl_socket(struct app_context *ctx) nl_close(ctx->sock); nl_socket_free(ctx->sock); - ctx->sock = NULL; - ctx->family_id = -1; + + cleanup_app_context(ctx); igt_debug("Cleaned up netlink socket.\n"); } int init_nl_socket(struct app_context *ctx) { + int ret; + + ret = init_app_context(ctx); + if (ret < 0) + return ret; + ctx->sock = nl_socket_alloc(); if (!ctx->sock) return -1; @@ -58,3 +205,31 @@ int init_nl_socket(struct app_context *ctx) DRM_RAS_FAMILY_NAME, ctx->family_id); return 0; } + +int get_error_counter(struct app_context *ctx) +{ + int ret; + + if (!ctx || !ctx->sock || ctx->family_id < 0) + return -EINVAL; + + if (ctx->node_id == UINT32_MAX || + ctx->error_id == UINT32_MAX || + ctx->error_id == 0) { + igt_warn("Invalid node_id (%u) or error_id (%u) provided. " + "node_id should be >= 0 and error_id should be >= 1.\n", + ctx->node_id, ctx->error_id); + return -EINVAL; + } + + ctx->error_value = 0; + + ret = send_command(ctx, DRM_RAS_CMD_GET_ERROR_COUNTER); + if (ret < 0) + return ret; + + igt_debug("Retrieved error counter: node_id=%u error_id=%u value=%u\n", + ctx->node_id, ctx->error_id, ctx->error_value); + + return 0; +} diff --git a/lib/igt_drm_netlink.h b/lib/igt_drm_netlink.h index c20d5452b..e539bc030 100644 --- a/lib/igt_drm_netlink.h +++ b/lib/igt_drm_netlink.h @@ -9,17 +9,28 @@ #include <stdbool.h> #include <stdint.h> +#include <linux/genetlink.h> + +#include <netlink/attr.h> +#include <netlink/handlers.h> +#include <netlink/msg.h> #include <netlink/netlink.h> #include <drm-uapi/drm_ras.h> struct app_context { struct nl_sock *sock; + uint32_t node_id; + uint32_t error_id; + uint32_t error_value; int family_id; }; +int init_app_context(struct app_context *ctx); +void cleanup_app_context(struct app_context *ctx); void cleanup_nl_socket(struct app_context *ctx); int init_nl_socket(struct app_context *ctx); +int get_error_counter(struct app_context *ctx); #endif /* IGT_DRM_NETLINK_H */ -- 2.34.1