Re: [2/8] lib/igt_drm_netlink: add get_error_counter support
"Purkait, Soham" <[email protected]>
| Newsgroups | org.freedesktop.lists.igt-dev |
|---|---|
| Message-ID | <[email protected]> |
Hi Ravi, On 29-07-2026 17:49, Ravi Kishore Koppuravuri wrote: > 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); Is it blocking ? if so, is there any timeout ? > + nl_cb_put(cb); Why the callback is being removed on the fly ? > + > + 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); The callback could have been set during initialization to avoid setting and removing this callback on the fly. Thanks, Soham > + 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 */ >