Netdev List
 help / color / mirror / Atom feed
From: Rodrigo Vivi <rodrigo.vivi@intel.com>
To: Zack McKevitt <zachary.mckevitt@oss.qualcomm.com>
Cc: <dri-devel@lists.freedesktop.org>, <netdev@vger.kernel.org>,
	<riana.tauro@intel.com>, <aravind.iddamsetty@linux.intel.com>,
	<raag.jadav@intel.com>, <simona.vetter@ffwll.ch>,
	<airlied@gmail.com>, <kuba@kernel.org>, <ogabbay@kernel.org>,
	<lizhi.hou@amd.com>, <karol.wachowski@linux.intel.com>,
	<jeff.hugo@oss.qualcomm.com>, <carl.vanderlip@oss.qualcomm.com>,
	<troy.hanson@oss.qualcomm.com>,
	<youssef.abdulrahman@oss.qualcomm.com>
Subject: Re: [PATCH v3 2/3] drm/drm_ras: Extend DRM RAS interface to include telemetry nodes
Date: Mon, 9 Nov 2026 10:41:22 -0500	[thread overview]
Message-ID: <avHpogElibf5F0FR@intel.com> (raw)
In-Reply-To: <20261106181225.3333260-3-zachary.mckevitt@oss.qualcomm.com>

On Fri, Nov 06, 2026 at 10:12:24AM -0800, Zack McKevitt wrote:
> Add a new node type, attribute set, and doit/dump functions for
> performing telemetry read and write operations using the DRM RAS
> interface.
> 
> ynl-regen.sh was used to regenerate drm_ras_nl.c, drm_ras_nl.h, and
> include/uapi/drm/drm_ras.h from the drm_ras.yaml spec.
> 
> Reviewed-by: Jeff Hugo <jeff.hugo@oss.qualcomm.com>
> Signed-off-by: Zack McKevitt <zachary.mckevitt@oss.qualcomm.com>
> ---
>  Documentation/netlink/specs/drm_ras.yaml |  82 +++++-
>  drivers/gpu/drm/drm_ras.c                | 329 ++++++++++++++++++++++-
>  drivers/gpu/drm/drm_ras_nl.c             |  53 ++++
>  drivers/gpu/drm/drm_ras_nl.h             |   9 +
>  include/drm/drm_ras.h                    |  67 +++++
>  include/uapi/drm/drm_ras.h               |  19 +-
>  6 files changed, 545 insertions(+), 14 deletions(-)
> 
> diff --git a/Documentation/netlink/specs/drm_ras.yaml b/Documentation/netlink/specs/drm_ras.yaml
> index a88fdab7a1c7..cf015bba020d 100644
> --- a/Documentation/netlink/specs/drm_ras.yaml
> +++ b/Documentation/netlink/specs/drm_ras.yaml
> @@ -16,11 +16,11 @@ definitions:
>      type: enum
>      name: node-type
>      value-start: 1
> -    entries: [error-counter]
> +    entries: [error-counter, telemetry]
>      doc: >-
> -         Type of the node. Currently, only error-counter nodes are
> -         supported, which expose reliability counters for a hardware/software
> -         component.
> +         Type of the node. The error-counter nodes expose reliability counters
> +         for a hardware/software component, and telemetry nodes expose an
> +         interface for reading and writing telemetry values to a device.
>  
>  attribute-sets:
>    -
> @@ -100,6 +100,34 @@ attribute-sets:
>          name: error-value
>          type: u32
>          doc: Current value of the error counter.
> +  -
> +    name: telemetry-attrs
> +    attributes:
> +      -
> +        name: node-id
> +        type: u32

this we keep for legacy alignment.

> +        doc: >-
> +             Unique identifier for the node.
> +             Assigned dynamically by the DRM RAS core upon registration.
> +      -
> +        name: field
> +        type: u32

should we move this to uint as well?

> +        doc:  Telemetry field to be read/written, e.g., SoC temp.
> +      -
> +        name: field-name
> +        type: string
> +        doc:  Name of the telemetry field defined by the device's uAPI.
> +      -
> +        name: value
> +        type: sint
> +        doc: Value of telemetry field that was read/written.
> +      -
> +        name: status
> +        type: s32

and this to sint?!

> +        doc: >-
> +             Status of the telemetry operation.
> +             Populated by the device in response to the performed
> +             telemetry operation. Errors may be hardware specific.
>  
>  operations:
>    list:
> @@ -198,6 +226,52 @@ operations:
>              - node-id
>              - error-id
>              - error-threshold
> +    -
> +      name: telemetry-get
> +      doc: Perform a read of the specified telemetry field.
> +      attribute-set: telemetry-attrs
> +      do:
> +        pre: drm-ras-nl-pre-telemetry
> +        request:
> +          attributes:
> +            - node-id
> +            - field
> +        reply:
> +          attributes:
> +            - value
> +            - status
> +      dump:
> +        request:
> +          attributes:
> +            - node-id
> +        reply:
> +          attributes: &telemetry-field-attrs
> +            - field
> +            - field-name
> +    -
> +      name: telemetry-set
> +      doc: >-
> +           Perform a write of the specified telemetry field.
> +           Telemetry writes are device specific, and may be used to set
> +           device limits or other capacities, for example.
> +      attribute-set: telemetry-attrs
> +      flags: [admin-perm]
> +      do:
> +        pre: drm-ras-nl-pre-telemetry
> +        request:
> +          attributes:
> +            - node-id
> +            - field
> +            - value
> +        reply:
> +          attributes:
> +            - status
> +      dump:

does dump on set specified telemetry field makes sense?!

> +        request:
> +          attributes:
> +            - node-id
> +        reply:
> +          attributes: *telemetry-field-attrs
>  
>  mcast-groups:
>    list:
> diff --git a/drivers/gpu/drm/drm_ras.c b/drivers/gpu/drm/drm_ras.c
> index 4f4777060a4e..fda50563c4a5 100644
> --- a/drivers/gpu/drm/drm_ras.c
> +++ b/drivers/gpu/drm/drm_ras.c
> @@ -53,6 +53,15 @@
>   * 7. SET_ERROR_THRESHOLD: Set error threshold of a given counter.
>   *    Userspace must provide Node ID, Error ID and threshold to be set.
>   *
> + * 8. TELEMETRY_GET: Read a telemetry value.
> + *    Userspace must provide Node ID and telemetry field to be read.
> + *    Returns the status of the read and the value read (if valid).
> + *
> + * 9. TELEMETRY_SET: Write a telemetry value.
> + *    Userspace must provide Node ID, the telemetry field to write, and the value
> + *    to be written.
> + *    Returns the status of the write.
> + *
>   * Node registration:
>   *
>   * - drm_ras_node_register(): Registers a new node and assigns
> @@ -63,7 +72,6 @@
>   * Node type:
>   *
>   * - ERROR_COUNTER:
> - *     + Currently, only error counters are supported.
>   *     + The driver must implement the query_error_counter() callback to provide
>   *       the name and the value of the error counter.
>   *     + The driver must provide a error_counter_range.last value informing the
> @@ -81,6 +89,15 @@
>   *       that are raised by the hardware.
>   *     + The driver is responsible for error threshold bounds checking.
>   *
> + * - TELEMETRY:
> + *     + The driver must implement the telemetry_get() callbacks, telemetry_set()
> + *       is optional.
> + *     + The driver must provide a list of gettable telemetry fields corresponding
> + *       to their uAPI definitions and values. Settable telemetry fields are also
> + *       required if providing telemetry_set().
> + *     + The driver can optionally provide a pre_doit callback, telemetry_pre(),
> + *       to enforce permissions checks on telemetry operations.
> + *
>   * Netlink handlers:
>   *
>   * - drm_ras_nl_list_nodes_dumpit(): Implements the LIST_NODES
> @@ -95,6 +112,16 @@
>   *   operation, fetching the error threshold of a specific counter.
>   * - drm_ras_nl_set_error_threshold_doit(): Implements the SET_ERROR_THRESHOLD doit
>   *   operation, setting the error threshold of a specific counter.
> + * - drm_ras_nl_pre_telemetry(): Implements the TELEMETRY_READ and TELEMETRY_WRITE

_GET and _SET

> + *   pre_doit operation, returning 0 if valid.
> + * - drm_ras_nl_telemetry_get_dumpit(): Implements the TELEMETRY_GET dumpit
> + *   operation, fetching all readable telemetry values for a telemetry node.
> + * - drm_ras_nl_telemetry_get_doit(): Implements the TELEMETRY_GET doit operation,
> + *   invoking the driver's telemetry_get callback and returning the results.
> + * - drm_ras_nl_telemetry_set_dumpit(): Implements the TELEMETRY_SET dumpit
> + *   operation, fetching all writeable telemetry values for a telemetry node.
> + * - drm_ras_nl_telemetry_set_doit(): Implements the TELEMETRY_SET doit operation,
> + *   invoking the driver's telemetry_set callback and returning the results.
>   */
>  
>  static DEFINE_XARRAY_ALLOC(drm_ras_xa);
> @@ -617,6 +644,285 @@ int drm_ras_nl_set_error_threshold_doit(struct sk_buff *skb, struct genl_info *i
>  	return set_node_error_threshold(node_id, error_id, threshold);
>  }
>  
> +/**
> + * drm_ras_nl_pre_telemetry - Enforce permission checks
> + * @ops: Generic netlink operations
> + * @skb: Netlink message buffer
> + * @info: Generic Netlink info containing attributes of the request
> + *
> + * Enforces a telemetry node's pre_doit conditions (if they exist).
> + *
> + * Returns 0 if no pre_doit is specified, otherwise returns the pre_doit.
> + */
> +int drm_ras_nl_pre_telemetry(const struct genl_split_ops *ops, struct sk_buff *skb,
> +			     struct genl_info *info)
> +{
> +	struct drm_ras_node *node;
> +	u32 node_id;
> +
> +	if (!info->attrs || GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID))
> +		return -EINVAL;
> +
> +	node_id = nla_get_u32(info->attrs[DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID]);
> +	node = xa_load(&drm_ras_xa, node_id);
> +	if (!node)
> +		return -ENOENT;

netlink review prompts ask us to use NL_SET_BAD_ATTR in cases like this.

Perhaps a
NL_SET_BAD_ATTR(info->extack, info->attrs[DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID]);

The same applies to the other unknown-node returns in the doits and dumpits.

> +
> +	if (node->telemetry_pre)
> +		return node->telemetry_pre(node);
> +
> +	return 0;
> +}
> +
> +static bool telemetry_fields_contains(const struct drm_ras_telemetry_field *fields, u32 value)
> +{
> +	unsigned long idx;
> +
> +	if (!fields)
> +		return false;
> +
> +	for (idx = 0; fields[idx].name; idx++) {
> +		if (fields[idx].value == value)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
> +static int telemetry_fields_dumpit(struct sk_buff *skb, struct netlink_callback *cb,
> +				   const struct drm_ras_telemetry_field *fields)
> +{
> +	const struct genl_info *info = genl_info_dump(cb);
> +	struct drm_ras_ctx *ctx = (void *)cb->ctx;
> +	const struct drm_ras_telemetry_field *field;
> +	struct nlattr *hdr;
> +	unsigned long idx;
> +	int ret = 0;
> +
> +	if (!fields)
> +		return -EOPNOTSUPP;
> +
> +	for (idx = ctx->restart; fields[idx].name; idx++) {
> +		field = &fields[idx];
> +
> +		hdr = genlmsg_iput(skb, info);
> +		if (!hdr) {
> +			ret = -EMSGSIZE;
> +			break;
> +		}
> +
> +		ret = nla_put_u32(skb, DRM_RAS_A_TELEMETRY_ATTRS_FIELD, field->value);
> +		if (ret) {
> +			genlmsg_cancel(skb, hdr);
> +			break;
> +		}
> +
> +		ret = nla_put_string(skb, DRM_RAS_A_TELEMETRY_ATTRS_FIELD_NAME, field->name);
> +		if (ret) {
> +			genlmsg_cancel(skb, hdr);
> +			break;
> +		}
> +
> +		genlmsg_end(skb, hdr);
> +	}
> +
> +	if (ret == -EMSGSIZE)
> +		ctx->restart = idx;
> +
> +	return ret;
> +}
> +
> +/**
> + * drm_ras_nl_telemetry_get_dumpit() - Dump readable telemetry fields.
> + * @skb: Netlink message buffer
> + * @cb: Callback context for multi-part dumps
> + *
> + * Displays the set of readable telemetry fields that is specified by
> + * the device for the given node.
> + *
> + * Return: 0 on success, or negative errno on failure.
> + */
> +int drm_ras_nl_telemetry_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
> +{
> +	const struct genl_info *info = genl_info_dump(cb);
> +	struct drm_ras_node *node;
> +	u32 node_id;
> +
> +	if (!info->attrs || GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID))
> +		return -EINVAL;
> +
> +	node_id = nla_get_u32(info->attrs[DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID]);
> +
> +	node = xa_load(&drm_ras_xa, node_id);
> +	if (!node)
> +		return -ENOENT;
> +
> +	return telemetry_fields_dumpit(skb, cb, node->telemetry_fields_gettable);
> +}
> +
> +/**
> + * drm_ras_nl_telemetry_get_doit() - Query a telemetry value
> + * @skb: Netlink message buffer
> + * @info: Generic Netlink info containing attributes of the request
> + *
> + * Extracts the telemetry field from the netlink attributes and
> + * reads that value from the device.
> + *
> + * Return: 0 on success, or negative errno on failure.
> + */
> +int drm_ras_nl_telemetry_get_doit(struct sk_buff *skb, struct genl_info *info)
> +{
> +	struct drm_ras_node *node;
> +	struct sk_buff *msg;
> +	struct nlattr *hdr;
> +	u32 node_id, field;
> +	s32 status = 0;
> +	s64 value = 0;
> +	int ret = 0;
> +
> +	if (!info->attrs ||
> +	    GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID) ||
> +	    GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_TELEMETRY_ATTRS_FIELD))
> +		return -EINVAL;
> +
> +	field = nla_get_u32(info->attrs[DRM_RAS_A_TELEMETRY_ATTRS_FIELD]);
> +	node_id = nla_get_u32(info->attrs[DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID]);
> +
> +	node = xa_load(&drm_ras_xa, node_id);
> +	if (!node || !node->telemetry_get)
> +		return -ENOENT;
> +
> +	if (!telemetry_fields_contains(node->telemetry_fields_gettable, field))
> +		return -EINVAL;

NL_SET_BAD_ATTR on NODE_ID for the -ENOENT case, and on FIELD for the -EINVAL
case (field not in the gettable/settable list).

> +
> +	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
> +	if (!msg)
> +		return -ENOMEM;
> +
> +	hdr = genlmsg_iput(msg, info);
> +	if (!hdr) {
> +		nlmsg_free(msg);
> +		return -EMSGSIZE;
> +	}
> +
> +	ret = node->telemetry_get(node, &field, &value, &status);
> +	if (ret) {
> +		nlmsg_free(msg);
> +		return ret;
> +	}
> +
> +	ret = nla_put_s32(msg, DRM_RAS_A_TELEMETRY_ATTRS_STATUS, status);
> +	if (ret) {
> +		genlmsg_cancel(msg, hdr);
> +		nlmsg_free(msg);
> +		return ret;
> +	}
> +
> +	ret = nla_put_sint(msg, DRM_RAS_A_TELEMETRY_ATTRS_VALUE, value);
> +	if (ret) {
> +		genlmsg_cancel(msg, hdr);
> +		nlmsg_free(msg);
> +		return ret;
> +	}
> +
> +	genlmsg_end(msg, hdr);
> +
> +	return genlmsg_reply(msg, info);
> +}
> +
> +/**
> + * drm_ras_nl_telemetry_set_dumpit() - Dump writeable telemetry fields.
> + * @skb: Netlink message buffer
> + * @cb: Callback context for multi-part dumps
> + *
> + * Displays the set of writeable telemetry fields that is specified by
> + * the device for the given node.
> + *
> + * Return: 0 on success, or negative errno on failure.
> + */
> +int drm_ras_nl_telemetry_set_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
> +{
> +	const struct genl_info *info = genl_info_dump(cb);
> +	struct drm_ras_node *node;
> +	u32 node_id;
> +
> +	if (!info->attrs || GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID))
> +		return -EINVAL;
> +
> +	node_id = nla_get_u32(info->attrs[DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID]);
> +
> +	node = xa_load(&drm_ras_xa, node_id);
> +	if (!node)
> +		return -ENOENT;
> +
> +	return telemetry_fields_dumpit(skb, cb, node->telemetry_fields_settable);
> +}
> +
> +/**
> + * drm_ras_nl_telemetry_set_doit() - Write a telemetry value
> + * @skb: Netlink message buffer
> + * @info: Generic Netlink info containing attributes of the request
> + *
> + * Extracts the telemetry field and value to be written from the netlink
> + * attributes and writes that value to the specified field on the device.
> + *
> + * Return: 0 on success, or negative errno on failure.
> + */
> +int drm_ras_nl_telemetry_set_doit(struct sk_buff *skb, struct genl_info *info)
> +{
> +	struct drm_ras_node *node;
> +	struct sk_buff *msg;
> +	struct nlattr *hdr;
> +	u32 node_id, field;
> +	s32 status = 0;
> +	s64 value = 0;
> +	int ret = 0;
> +
> +	if (!info->attrs ||
> +	    GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID) ||
> +	    GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_TELEMETRY_ATTRS_VALUE) ||
> +	    GENL_REQ_ATTR_CHECK(info, DRM_RAS_A_TELEMETRY_ATTRS_FIELD))
> +		return -EINVAL;
> +
> +	value = nla_get_sint(info->attrs[DRM_RAS_A_TELEMETRY_ATTRS_VALUE]);
> +	field = nla_get_u32(info->attrs[DRM_RAS_A_TELEMETRY_ATTRS_FIELD]);
> +	node_id = nla_get_u32(info->attrs[DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID]);
> +
> +	node = xa_load(&drm_ras_xa, node_id);
> +	if (!node || !node->telemetry_set)
> +		return -ENOENT;
> +
> +	if (!telemetry_fields_contains(node->telemetry_fields_settable, field))
> +		return -EINVAL;
> +
> +	msg = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
> +	if (!msg)
> +		return -ENOMEM;
> +
> +	hdr = genlmsg_iput(msg, info);
> +	if (!hdr) {
> +		nlmsg_free(msg);
> +		return -EMSGSIZE;
> +	}
> +
> +	ret = node->telemetry_set(node, &field, &value, &status);
> +	if (ret) {
> +		nlmsg_free(msg);
> +		return ret;
> +	}
> +
> +	ret = nla_put_s32(msg, DRM_RAS_A_TELEMETRY_ATTRS_STATUS, status);
> +	if (ret) {
> +		genlmsg_cancel(msg, hdr);
> +		nlmsg_free(msg);
> +		return ret;
> +	}
> +
> +	genlmsg_end(msg, hdr);
> +
> +	return genlmsg_reply(msg, info);
> +}
> +
>  /**
>   * drm_ras_node_register() - Register a new RAS node
>   * @node: Node structure to register
> @@ -631,14 +937,21 @@ int drm_ras_node_register(struct drm_ras_node *node)
>  	if (!node->device_name || !node->node_name)
>  		return -EINVAL;
>  
> -	/* Currently, only Error Counter Endpoints are supported */
> -	if (node->type != DRM_RAS_NODE_TYPE_ERROR_COUNTER)
> -		return -EINVAL;
> -
> -	/* Mandatory entries for Error Counter Node */
> -	if (node->type == DRM_RAS_NODE_TYPE_ERROR_COUNTER &&
> -	    (!node->error_counter_range.last || !node->query_error_counter))
> +	/* Currently, only Error Counter and Telemetry endpoints are supported */
> +	switch (node->type) {
> +	case DRM_RAS_NODE_TYPE_ERROR_COUNTER:
> +		/* Mandatory entries for Error Counter Node */
> +		if (!node->error_counter_range.last || !node->query_error_counter)
> +			return -EINVAL;
> +		break;
> +	case DRM_RAS_NODE_TYPE_TELEMETRY:
> +		/* Must provide telemetry_get, telemetry_set is optional */
> +		if (!node->telemetry_get || !node->telemetry_fields_gettable)
> +			return -EINVAL;
> +		break;
> +	default:
>  		return -EINVAL;
> +	}
>  
>  	return xa_alloc(&drm_ras_xa, &node->id, node, xa_limit_32b, GFP_KERNEL);
>  }
> diff --git a/drivers/gpu/drm/drm_ras_nl.c b/drivers/gpu/drm/drm_ras_nl.c
> index ff0dc406c27c..19e3683fb35a 100644
> --- a/drivers/gpu/drm/drm_ras_nl.c
> +++ b/drivers/gpu/drm/drm_ras_nl.c
> @@ -41,6 +41,29 @@ static const struct nla_policy drm_ras_set_error_threshold_nl_policy[DRM_RAS_A_E
>  	[DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD] = { .type = NLA_U32, },
>  };
>  
> +/* DRM_RAS_CMD_TELEMETRY_GET - do */
> +static const struct nla_policy drm_ras_telemetry_get_do_nl_policy[DRM_RAS_A_TELEMETRY_ATTRS_FIELD + 1] = {
> +	[DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID] = { .type = NLA_U32, },
> +	[DRM_RAS_A_TELEMETRY_ATTRS_FIELD] = { .type = NLA_U32, },
> +};
> +
> +/* DRM_RAS_CMD_TELEMETRY_GET - dump */
> +static const struct nla_policy drm_ras_telemetry_get_dump_nl_policy[DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID + 1] = {
> +	[DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID] = { .type = NLA_U32, },
> +};
> +
> +/* DRM_RAS_CMD_TELEMETRY_SET - do */
> +static const struct nla_policy drm_ras_telemetry_set_do_nl_policy[DRM_RAS_A_TELEMETRY_ATTRS_VALUE + 1] = {
> +	[DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID] = { .type = NLA_U32, },
> +	[DRM_RAS_A_TELEMETRY_ATTRS_FIELD] = { .type = NLA_U32, },
> +	[DRM_RAS_A_TELEMETRY_ATTRS_VALUE] = { .type = NLA_SINT, },
> +};
> +
> +/* DRM_RAS_CMD_TELEMETRY_SET - dump */
> +static const struct nla_policy drm_ras_telemetry_set_dump_nl_policy[DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID + 1] = {
> +	[DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID] = { .type = NLA_U32, },
> +};
> +
>  /* Ops table for drm_ras */
>  static const struct genl_split_ops drm_ras_nl_ops[] = {
>  	{
> @@ -83,6 +106,36 @@ static const struct genl_split_ops drm_ras_nl_ops[] = {
>  		.maxattr	= DRM_RAS_A_ERROR_COUNTER_ATTRS_ERROR_THRESHOLD,
>  		.flags		= GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
>  	},
> +	{
> +		.cmd		= DRM_RAS_CMD_TELEMETRY_GET,
> +		.pre_doit	= drm_ras_nl_pre_telemetry,
> +		.doit		= drm_ras_nl_telemetry_get_doit,
> +		.policy		= drm_ras_telemetry_get_do_nl_policy,
> +		.maxattr	= DRM_RAS_A_TELEMETRY_ATTRS_FIELD,
> +		.flags		= GENL_CMD_CAP_DO,
> +	},
> +	{
> +		.cmd		= DRM_RAS_CMD_TELEMETRY_GET,
> +		.dumpit		= drm_ras_nl_telemetry_get_dumpit,
> +		.policy		= drm_ras_telemetry_get_dump_nl_policy,
> +		.maxattr	= DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID,
> +		.flags		= GENL_CMD_CAP_DUMP,
> +	},
> +	{
> +		.cmd		= DRM_RAS_CMD_TELEMETRY_SET,
> +		.pre_doit	= drm_ras_nl_pre_telemetry,
> +		.doit		= drm_ras_nl_telemetry_set_doit,
> +		.policy		= drm_ras_telemetry_set_do_nl_policy,
> +		.maxattr	= DRM_RAS_A_TELEMETRY_ATTRS_VALUE,
> +		.flags		= GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
> +	},
> +	{
> +		.cmd		= DRM_RAS_CMD_TELEMETRY_SET,
> +		.dumpit		= drm_ras_nl_telemetry_set_dumpit,
> +		.policy		= drm_ras_telemetry_set_dump_nl_policy,
> +		.maxattr	= DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID,
> +		.flags		= GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP,
> +	},
>  };
>  
>  static const struct genl_multicast_group drm_ras_nl_mcgrps[] = {
> diff --git a/drivers/gpu/drm/drm_ras_nl.h b/drivers/gpu/drm/drm_ras_nl.h
> index 9aef097ea10f..ad3b28f2d809 100644
> --- a/drivers/gpu/drm/drm_ras_nl.h
> +++ b/drivers/gpu/drm/drm_ras_nl.h
> @@ -12,6 +12,9 @@
>  
>  #include <uapi/drm/drm_ras.h>
>  
> +int drm_ras_nl_pre_telemetry(const struct genl_split_ops *ops,
> +			     struct sk_buff *skb, struct genl_info *info);
> +
>  int drm_ras_nl_list_nodes_dumpit(struct sk_buff *skb,
>  				 struct netlink_callback *cb);
>  int drm_ras_nl_get_error_counter_doit(struct sk_buff *skb,
> @@ -24,6 +27,12 @@ int drm_ras_nl_get_error_threshold_doit(struct sk_buff *skb,
>  					struct genl_info *info);
>  int drm_ras_nl_set_error_threshold_doit(struct sk_buff *skb,
>  					struct genl_info *info);
> +int drm_ras_nl_telemetry_get_doit(struct sk_buff *skb, struct genl_info *info);
> +int drm_ras_nl_telemetry_get_dumpit(struct sk_buff *skb,
> +				    struct netlink_callback *cb);
> +int drm_ras_nl_telemetry_set_doit(struct sk_buff *skb, struct genl_info *info);
> +int drm_ras_nl_telemetry_set_dumpit(struct sk_buff *skb,
> +				    struct netlink_callback *cb);
>  
>  enum {
>  	DRM_RAS_NLGRP_ERROR_REPORT,
> diff --git a/include/drm/drm_ras.h b/include/drm/drm_ras.h
> index 1765a3130b09..1b2a40040c3b 100644
> --- a/include/drm/drm_ras.h
> +++ b/include/drm/drm_ras.h
> @@ -10,6 +10,16 @@
>  
>  #include <uapi/drm/drm_ras.h>
>  
> +/**
> + * struct drm_ras_telemetry_field - A descriptor of a telemetry field.
> + */
> +struct drm_ras_telemetry_field {
> +	/** @name: The enum or macro name defined by the device uAPI. */
> +	const char *name;
> +	/** @value: The numerical value of the field. */
> +	u32 value;
> +};
> +
>  /**
>   * struct drm_ras_node - A DRM RAS Node
>   */
> @@ -100,6 +110,63 @@ struct drm_ras_node {
>  	 */
>  	int (*set_error_threshold)(struct drm_ras_node *node, u32 error_id, u32 threshold);
>  
> +	/* Telemetry Related Callback and Variables */
> +
> +	/**
> +	 * @telemetry_fields_gettable:
> +	 *
> +	 * A list of gettable telemetry fields for a device.
> +	 * The list must be terminated by a NULL .name entry.
> +	 */
> +	const struct drm_ras_telemetry_field *telemetry_fields_gettable;
> +
> +	/**
> +	 * @telemetry_fields_settable:
> +	 *
> +	 * A list of settable telemetry fields for a device.
> +	 * The list must be terminated by a NULL .name entry.
> +	 */
> +	const struct drm_ras_telemetry_field *telemetry_fields_settable;
> +
> +	/**
> +	 * @telemetry_pre:
> +	 *
> +	 * This callback is used to enforce any pre_doit conditions necessary
> +	 * for telemetry. This is an optional callback for telemetry_node.
> +	 *
> +	 * Returns 0 on success, negative error code on failure.
> +	 */
> +	int (*telemetry_pre)(struct drm_ras_node *ep);
> +
> +	/**
> +	 * @telemetry_get:
> +	 *
> +	 * This callback is used for a drm-ras telemetry node to read a
> +	 * telemetry value. This is a mandatory callback for telemetry_node.
> +	 *
> +	 * The callback will read the desired device-specific field into value
> +	 * and update status corresponding to a device-specific error code.
> +	 *
> +	 * Returns 0 on success, negative error code on failure.
> +	 */
> +	int (*telemetry_get)(struct drm_ras_node *ep, u32 *field, s64 *value,
> +			     s32 *status);
> +
> +	/**
> +	 * @telemetry_set:
> +	 *
> +	 * This callback is used for a drm-ras telemetry node to write a
> +	 * telemetry value. This is an optional callback for telemetry_node.
> +	 *
> +	 * The callback will write the value to the desired device-specific
> +	 * field and update status corresponding to a device-specific error
> +	 * code.
> +	 *
> +	 * Returns 0 on success, negative error code on failure.
> +	 */
> +	int (*telemetry_set)(struct drm_ras_node *ep, u32 *field, s64 *value,
> +			     s32 *status);
> +
>  	/** @priv: Driver private data */
>  	void *priv;
>  };
> diff --git a/include/uapi/drm/drm_ras.h b/include/uapi/drm/drm_ras.h
> index 2f832275ee6e..4776c2f9cb5a 100644
> --- a/include/uapi/drm/drm_ras.h
> +++ b/include/uapi/drm/drm_ras.h
> @@ -11,11 +11,13 @@
>  #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.
> + * Type of the node. The error-counter nodes expose reliability counters for a
> + * hardware/software component, and telemetry nodes expose an interface for
> + * reading and writing telemetry values to a device.
>   */
>  enum drm_ras_node_type {
>  	DRM_RAS_NODE_TYPE_ERROR_COUNTER = 1,
> +	DRM_RAS_NODE_TYPE_TELEMETRY,
>  };
>  
>  enum {
> @@ -51,6 +53,17 @@ enum {
>  	DRM_RAS_A_ERROR_EVENT_ATTRS_MAX = (__DRM_RAS_A_ERROR_EVENT_ATTRS_MAX - 1)
>  };
>  
> +enum {
> +	DRM_RAS_A_TELEMETRY_ATTRS_NODE_ID = 1,
> +	DRM_RAS_A_TELEMETRY_ATTRS_FIELD,
> +	DRM_RAS_A_TELEMETRY_ATTRS_FIELD_NAME,
> +	DRM_RAS_A_TELEMETRY_ATTRS_VALUE,
> +	DRM_RAS_A_TELEMETRY_ATTRS_STATUS,
> +
> +	__DRM_RAS_A_TELEMETRY_ATTRS_MAX,
> +	DRM_RAS_A_TELEMETRY_ATTRS_MAX = (__DRM_RAS_A_TELEMETRY_ATTRS_MAX - 1)
> +};
> +
>  enum {
>  	DRM_RAS_CMD_LIST_NODES = 1,
>  	DRM_RAS_CMD_GET_ERROR_COUNTER,
> @@ -58,6 +71,8 @@ enum {
>  	DRM_RAS_CMD_ERROR_EVENT,
>  	DRM_RAS_CMD_GET_ERROR_THRESHOLD,
>  	DRM_RAS_CMD_SET_ERROR_THRESHOLD,
> +	DRM_RAS_CMD_TELEMETRY_GET,
> +	DRM_RAS_CMD_TELEMETRY_SET,
>  
>  	__DRM_RAS_CMD_MAX,
>  	DRM_RAS_CMD_MAX = (__DRM_RAS_CMD_MAX - 1)
> -- 
> 2.43.0
> 

  reply	other threads:[~2026-11-09 15:41 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-06 18:12 [PATCH v3 0/3] Extend drm_ras for qaic telemetry Zack McKevitt
2026-11-06 18:12 ` [PATCH v3 1/3] drm/drm_ras: Remove admin-perm flag from list-nodes operation Zack McKevitt
2026-11-06 18:12 ` [PATCH v3 2/3] drm/drm_ras: Extend DRM RAS interface to include telemetry nodes Zack McKevitt
2026-11-09 15:41   ` Rodrigo Vivi [this message]
2026-11-09 21:05     ` Zack McKevitt
2026-11-06 18:12 ` [PATCH v3 3/3] accel/qaic: Add callbacks for DRM RAS netlink telemetry Zack McKevitt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=avHpogElibf5F0FR@intel.com \
    --to=rodrigo.vivi@intel.com \
    --cc=airlied@gmail.com \
    --cc=aravind.iddamsetty@linux.intel.com \
    --cc=carl.vanderlip@oss.qualcomm.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=jeff.hugo@oss.qualcomm.com \
    --cc=karol.wachowski@linux.intel.com \
    --cc=kuba@kernel.org \
    --cc=lizhi.hou@amd.com \
    --cc=netdev@vger.kernel.org \
    --cc=ogabbay@kernel.org \
    --cc=raag.jadav@intel.com \
    --cc=riana.tauro@intel.com \
    --cc=simona.vetter@ffwll.ch \
    --cc=troy.hanson@oss.qualcomm.com \
    --cc=youssef.abdulrahman@oss.qualcomm.com \
    --cc=zachary.mckevitt@oss.qualcomm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox