Re: [PATCH v6 1/2] drm/drm_ras: Add drm_ras netlink error event
From: Rodrigo Vivi <rodrigo.vivi@intel.com>
Date: 2026-07-23 16:34:51
Also in:
dri-devel, intel-xe
On Thu, Jul 23, 2026 at 08:06:22PM +0530, Tauro, Riana wrote:
@Rodrigo The sashiko comments are resolved and has been tested with multiple namespaces using docker. Sashiko review is now clear with a pre-existing issue that is being fixed in another patch [PATCH v5 1/5] drm/ras: Cancel and free message on get counter failure - Raag Jadav <https://lore.kernel.org/intel-xe/20260722034228.662746-2-raag.jadav@intel.com/ (local)>Let me know if this looks good
Yeap, this is okay. On this one I just had the feeling that Raag had changed his mind and asked further changes after the put the rv-b. Perhaps we should resend a clean history and then we use that to ask for the appropriate acks
Thanks Riana On 22-07-2026 15:11, Riana Tauro wrote:quoted
Define a new netlink event 'error-event' and a new multicast group 'error-report' in drm_ras. Each event contains device name, node and error information to identify the error triggering the event. Add drm_ras_nl_error_event() to trigger an event from the driver. Userspace must subscribe to 'error-report' to receive 'error-event' notifications. Usage: $ sudo ynl --family drm_ras --subscribe error-report Cc: Jakub Kicinski <kuba@kernel.org> Cc: Zack McKevitt <redacted> Cc: Lijo Lazar <redacted> Cc: Hawking Zhang <redacted> Cc: David S. Miller <davem@davemloft.net> Cc: Paolo Abeni <pabeni@redhat.com> Cc: Eric Dumazet <edumazet@google.com> Signed-off-by: Riana Tauro <redacted> Reviewed-by: Raag Jadav <raag.jadav@intel.com> --- v2: remove redundant initialization remove unnecessary space use ynl in commit message and doc (Raag) simplify doc for error-event attrs v3: rename error-notify to error-report Replace notify with report across the file (Raag) v4: send event to all network namespaces (Sashiko) remove has_listeners check v5: add context in function for choosing GFP_KERNEL (Sashiko) add additional checks for node registration, range checks (Raag) --- Documentation/gpu/drm-ras.rst | 21 +++++ Documentation/netlink/specs/drm_ras.yaml | 48 +++++++++++ drivers/gpu/drm/drm_ras.c | 101 +++++++++++++++++++++++ drivers/gpu/drm/drm_ras_nl.c | 6 ++ drivers/gpu/drm/drm_ras_nl.h | 4 + include/drm/drm_ras.h | 5 ++ include/uapi/drm/drm_ras.h | 15 ++++ 7 files changed, 200 insertions(+)diff --git a/Documentation/gpu/drm-ras.rst b/Documentation/gpu/drm-ras.rst index 83c21853b74b..406e4c49bac1 100644 --- a/Documentation/gpu/drm-ras.rst +++ b/Documentation/gpu/drm-ras.rst@@ -56,6 +56,7 @@ User space tools can: ``node-id`` and ``error-id`` as parameters. * Clear specific error counters with the ``clear-error-counter`` command, using both ``node-id`` and ``error-id`` as parameters. +* Subscribe to the ``error-report`` multicast group to receive ``error-event``. YAML-based Interface --------------------@@ -111,3 +112,23 @@ Example: Clear an error counter for a given node sudo ynl --family drm_ras --do clear-error-counter --json '{"node-id":0, "error-id":1}' None + +Example: Subscribe to ``error-report`` multicast group + +.. code-block:: bash + + sudo ynl --family drm_ras --output-json --subscribe error-report + +.. code-block:: json + + { + "name": "error-event", + "msg": { + "device-name": "0000:03:00.0", + "node-id": 1, + "node-name": "uncorrectable-errors", + "error-id": 1, + "error-name": "error_name1", + "error-value": 1 + } + }diff --git a/Documentation/netlink/specs/drm_ras.yaml b/Documentation/netlink/specs/drm_ras.yaml index e113056f8c01..8aed3d4515e5 100644 --- a/Documentation/netlink/specs/drm_ras.yaml +++ b/Documentation/netlink/specs/drm_ras.yaml@@ -69,6 +69,33 @@ attribute-sets: name: error-value type: u32 doc: Current value of the requested error counter. + - + name: error-event-attrs + attributes: + - + name: device-name + type: string + doc: Device (PCI BDF, UUID) that reported the error. + - + name: node-id + type: u32 + doc: ID of the node that reported the error. + - + name: node-name + type: string + doc: Name of the node that reported the error. + - + name: error-id + type: u32 + doc: ID of the error counter. + - + name: error-name + type: string + doc: Name of the error. + - + name: error-value + type: u32 + doc: Current value of the error counter. operations: list:@@ -124,3 +151,24 @@ operations: do: request: attributes: *id-attrs + - + name: error-event + doc: >- + Report an error event to userspace. + The event includes the device, node and error information + of the error that triggered the event. + attribute-set: error-event-attrs + mcgrp: error-report + event: + attributes: + - device-name + - node-id + - node-name + - error-id + - error-name + - error-value + +mcast-groups: + list: + - + name: error-reportdiff --git a/drivers/gpu/drm/drm_ras.c b/drivers/gpu/drm/drm_ras.c index d6eab29a1394..39155fb514de 100644 --- a/drivers/gpu/drm/drm_ras.c +++ b/drivers/gpu/drm/drm_ras.c@@ -41,6 +41,11 @@ * Userspace must provide Node ID, Error ID. * Clears specific error counter of a node if supported. * + * 4. ERROR_REPORT: Subscribe to this multicast group to receive error events + * + * 5. ERROR_EVENT: Report an error event to userspace. The event contains device, node + * and error information that triggered the event. + * * Node registration: * * - drm_ras_node_register(): Registers a new node and assigns@@ -186,6 +191,34 @@ static int msg_reply_value(struct sk_buff *msg, u32 error_id, value); } +static int msg_put_error_event_attrs(struct sk_buff *msg, struct drm_ras_node *node, + u32 error_id, const char *error_name, u32 value) +{ + int ret; + + ret = nla_put_string(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_DEVICE_NAME, node->device_name); + if (ret) + return ret; + + ret = nla_put_u32(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_NODE_ID, node->id); + if (ret) + return ret; + + ret = nla_put_string(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_NODE_NAME, node->node_name); + if (ret) + return ret; + + ret = nla_put_u32(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_ID, error_id); + if (ret) + return ret; + + ret = nla_put_string(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_NAME, error_name); + if (ret) + return ret; + + return nla_put_u32(msg, DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_VALUE, value); +} + static int doit_reply_value(struct genl_info *info, u32 node_id, u32 error_id) {@@ -222,6 +255,74 @@ static int doit_reply_value(struct genl_info *info, u32 node_id, return genlmsg_reply(msg, info); } +/** + * drm_ras_nl_error_event() - Report an error event + * @node: Node structure + * @error_id: ID of the error + * @error_name: Name of the error + * @value: Value of the error counter + * + * Report an error-event to userspace using the error-report multicast group. + * + * Context: Process context only. Uses %GFP_KERNEL and multicasts to all + * netns, which is unbounded work; callers in interrupt handlers + * or other atomic context must defer event. + * + * Return: 0 on success, or negative errno on failure. + */ +int drm_ras_nl_error_event(struct drm_ras_node *node, u32 error_id, const char *error_name, + u32 value) +{ + struct genl_info info; + struct sk_buff *msg; + struct nlattr *hdr; + int ret; + + if (!node || !error_name) + return -EINVAL; + + /* Check the node is currently registered */ + if (xa_load(&drm_ras_xa, node->id) != node) + return -ENOENT; + + /* Currently only Error Counter events are supported */ + if (node->type != DRM_RAS_NODE_TYPE_ERROR_COUNTER) + return -EOPNOTSUPP; + + /* Check the error ID is within the valid range */ + if (error_id < node->error_counter_range.first || + error_id > node->error_counter_range.last) + return -EINVAL; + + genl_info_init_ntf(&info, &drm_ras_nl_family, DRM_RAS_CMD_ERROR_EVENT); + + msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + hdr = genlmsg_iput(msg, &info); + if (!hdr) { + ret = -EMSGSIZE; + goto free_msg; + } + + ret = msg_put_error_event_attrs(msg, node, error_id, error_name, value); + if (ret) + goto cancel_msg; + + genlmsg_end(msg, hdr); + genlmsg_multicast_allns(&drm_ras_nl_family, msg, 0, DRM_RAS_NLGRP_ERROR_REPORT); + + return 0; + +cancel_msg: + genlmsg_cancel(msg, hdr); +free_msg: + nlmsg_free(msg); + return ret; +} +EXPORT_SYMBOL(drm_ras_nl_error_event); + /** * drm_ras_nl_get_error_counter_dumpit() - Dump all Error Counters * @skb: Netlink message bufferdiff --git a/drivers/gpu/drm/drm_ras_nl.c b/drivers/gpu/drm/drm_ras_nl.c index dea1c1b2494e..9d3123cc9f9c 100644 --- a/drivers/gpu/drm/drm_ras_nl.c +++ b/drivers/gpu/drm/drm_ras_nl.c@@ -58,6 +58,10 @@ static const struct genl_split_ops drm_ras_nl_ops[] = { }, }; +static const struct genl_multicast_group drm_ras_nl_mcgrps[] = { + [DRM_RAS_NLGRP_ERROR_REPORT] = { "error-report", }, +}; + struct genl_family drm_ras_nl_family __ro_after_init = { .name = DRM_RAS_FAMILY_NAME, .version = DRM_RAS_FAMILY_VERSION,@@ -66,4 +70,6 @@ struct genl_family drm_ras_nl_family __ro_after_init = { .module = THIS_MODULE, .split_ops = drm_ras_nl_ops, .n_split_ops = ARRAY_SIZE(drm_ras_nl_ops), + .mcgrps = drm_ras_nl_mcgrps, + .n_mcgrps = ARRAY_SIZE(drm_ras_nl_mcgrps), };diff --git a/drivers/gpu/drm/drm_ras_nl.h b/drivers/gpu/drm/drm_ras_nl.h index a398643572a5..03ec275aca92 100644 --- a/drivers/gpu/drm/drm_ras_nl.h +++ b/drivers/gpu/drm/drm_ras_nl.h@@ -21,6 +21,10 @@ int drm_ras_nl_get_error_counter_dumpit(struct sk_buff *skb, int drm_ras_nl_clear_error_counter_doit(struct sk_buff *skb, struct genl_info *info); +enum { + DRM_RAS_NLGRP_ERROR_REPORT, +}; + extern struct genl_family drm_ras_nl_family; #endif /* _LINUX_DRM_RAS_GEN_H */diff --git a/include/drm/drm_ras.h b/include/drm/drm_ras.h index 0beede3ddc4e..ee2caa0edc6f 100644 --- a/include/drm/drm_ras.h +++ b/include/drm/drm_ras.h@@ -80,9 +80,14 @@ struct drm_device; #if IS_ENABLED(CONFIG_DRM_RAS) int drm_ras_node_register(struct drm_ras_node *node); void drm_ras_node_unregister(struct drm_ras_node *node); +int drm_ras_nl_error_event(struct drm_ras_node *node, u32 error_id, const char *error_name, + u32 value); #else static inline int drm_ras_node_register(struct drm_ras_node *node) { return 0; } static inline void drm_ras_node_unregister(struct drm_ras_node *node) { } +static inline int drm_ras_nl_error_event(struct drm_ras_node *node, u32 error_id, + const char *error_name, u32 value) +{ return 0; } #endif #endifdiff --git a/include/uapi/drm/drm_ras.h b/include/uapi/drm/drm_ras.h index 218a3ee86805..eab8231aa87c 100644 --- a/include/uapi/drm/drm_ras.h +++ b/include/uapi/drm/drm_ras.h@@ -38,13 +38,28 @@ enum { DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX = (__DRM_RAS_A_ERROR_COUNTER_ATTRS_MAX - 1) }; +enum { + DRM_RAS_A_ERROR_EVENT_ATTRS_DEVICE_NAME = 1, + DRM_RAS_A_ERROR_EVENT_ATTRS_NODE_ID, + DRM_RAS_A_ERROR_EVENT_ATTRS_NODE_NAME, + DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_ID, + DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_NAME, + DRM_RAS_A_ERROR_EVENT_ATTRS_ERROR_VALUE, + + __DRM_RAS_A_ERROR_EVENT_ATTRS_MAX, + DRM_RAS_A_ERROR_EVENT_ATTRS_MAX = (__DRM_RAS_A_ERROR_EVENT_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_ERROR_EVENT, __DRM_RAS_CMD_MAX, DRM_RAS_CMD_MAX = (__DRM_RAS_CMD_MAX - 1) }; +#define DRM_RAS_MCGRP_ERROR_REPORT "error-report" + #endif /* _UAPI_LINUX_DRM_RAS_H */