[Intel-xe] [RFC v4 1/5] drm/netlink: Add netlink infrastructure

Ruhl, Michael J michael.j.ruhl at intel.com
Fri Oct 20 20:36:56 UTC 2023


>-----Original Message-----
>From: Aravind Iddamsetty <aravind.iddamsetty at linux.intel.com>
>Sent: Friday, October 20, 2023 11:59 AM
>To: intel-xe at lists.freedesktop.org; dri-devel at lists.freedesktop.org;
>alexander.deucher at amd.com; airlied at gmail.com; daniel at ffwll.ch;
>joonas.lahtinen at linux.intel.com; ogabbay at kernel.org; Tayar, Tomer (Habana)
><ttayar at habana.ai>; Hawking.Zhang at amd.com;
>Harish.Kasiviswanathan at amd.com; Felix.Kuehling at amd.com;
>Luben.Tuikov at amd.com; Ruhl, Michael J <michael.j.ruhl at intel.com>
>Subject: [RFC v4 1/5] drm/netlink: Add netlink infrastructure
>
>Define the netlink registration interface and commands, attributes that
>can be commonly used across by drm drivers. This patch intends to use
>the generic netlink family to expose various stats of device. At present
>it defines some commands that shall be used to expose RAS error counters.
>
>v2:
>define common interfaces to genl netlink subsystem that all drm drivers
>can leverage.(Tomer Tayar)
>
>v3: drop DRIVER_NETLINK flag and use the driver_genl_ops structure to
>register to netlink subsystem (Daniel Vetter)
>
>v4:(Michael J. Ruhl)
>1. rename drm_genl_send to drm_genl_reply
>2. catch error from xa_store and handle appropriately

Hi Aravind,

This looks reasonable to me.

Reviewed-by: Michael J. Ruhl <michael.j.ruhl at intel.com>

M

>Cc: Tomer Tayar <ttayar at habana.ai>
>Cc: Daniel Vetter <daniel at ffwll.ch>
>Cc: Michael J. Ruhl <michael.j.ruhl at intel.com>
>
>Signed-off-by: Aravind Iddamsetty <aravind.iddamsetty at linux.intel.com>
>---
> drivers/gpu/drm/Makefile       |   1 +
> drivers/gpu/drm/drm_drv.c      |   7 ++
> drivers/gpu/drm/drm_netlink.c  | 188
>+++++++++++++++++++++++++++++++++
> include/drm/drm_device.h       |   8 ++
> include/drm/drm_drv.h          |   7 ++
> include/drm/drm_netlink.h      |  30 ++++++
> include/uapi/drm/drm_netlink.h |  83 +++++++++++++++
> 7 files changed, 324 insertions(+)
> create mode 100644 drivers/gpu/drm/drm_netlink.c
> create mode 100644 include/drm/drm_netlink.h
> create mode 100644 include/uapi/drm/drm_netlink.h
>
>diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
>index ee64c51274ad..60864369adaa 100644
>--- a/drivers/gpu/drm/Makefile
>+++ b/drivers/gpu/drm/Makefile
>@@ -35,6 +35,7 @@ drm-y := \
> 	drm_mode_object.o \
> 	drm_modes.o \
> 	drm_modeset_lock.o \
>+	drm_netlink.o \
> 	drm_plane.o \
> 	drm_prime.o \
> 	drm_print.o \
>diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
>index 535f16e7882e..31f55c1c7524 100644
>--- a/drivers/gpu/drm/drm_drv.c
>+++ b/drivers/gpu/drm/drm_drv.c
>@@ -937,6 +937,12 @@ int drm_dev_register(struct drm_device *dev,
>unsigned long flags)
> 	if (ret)
> 		goto err_minors;
>
>+	if (driver->genl_ops) {
>+		ret = drm_genl_register(dev);
>+		if (ret)
>+			goto err_minors;
>+	}
>+
> 	ret = create_compat_control_link(dev);
> 	if (ret)
> 		goto err_minors;
>@@ -1074,6 +1080,7 @@ static void drm_core_exit(void)
> {
> 	drm_privacy_screen_lookup_exit();
> 	accel_core_exit();
>+	drm_genl_exit();
> 	unregister_chrdev(DRM_MAJOR, "drm");
> 	debugfs_remove(drm_debugfs_root);
> 	drm_sysfs_destroy();
>diff --git a/drivers/gpu/drm/drm_netlink.c b/drivers/gpu/drm/drm_netlink.c
>new file mode 100644
>index 000000000000..8add249c1da3
>--- /dev/null
>+++ b/drivers/gpu/drm/drm_netlink.c
>@@ -0,0 +1,188 @@
>+// SPDX-License-Identifier: MIT
>+/*
>+ * Copyright © 2023 Intel Corporation
>+ */
>+
>+#include <drm/drm_device.h>
>+#include <drm/drm_drv.h>
>+#include <drm/drm_file.h>
>+#include <drm/drm_managed.h>
>+#include <drm/drm_netlink.h>
>+#include <drm/drm_print.h>
>+
>+DEFINE_XARRAY(drm_dev_xarray);
>+
>+/**
>+ * drm_genl_reply - response to a request
>+ * @msg: socket buffer
>+ * @info: receiver information
>+ * @usrhdr: pointer to user specific header in the message buffer
>+ *
>+ * RETURNS:
>+ * 0 on success and negative error code on failure
>+ */
>+int drm_genl_reply(struct sk_buff *msg, struct genl_info *info, void *usrhdr)
>+{
>+	int ret;
>+
>+	genlmsg_end(msg, usrhdr);
>+
>+	ret = genlmsg_reply(msg, info);
>+	if (ret)
>+		nlmsg_free(msg);
>+
>+	return ret;
>+}
>+EXPORT_SYMBOL(drm_genl_reply);
>+
>+/**
>+ * drm_genl_alloc_msg - allocate genl message buffer
>+ * @dev: drm_device for which the message is being allocated
>+ * @info: receiver information
>+ * @usrhdr: pointer to user specific header in the message buffer
>+ *
>+ * RETURNS:
>+ * pointer to new allocated buffer on success, NULL on failure
>+ */
>+struct sk_buff *
>+drm_genl_alloc_msg(struct drm_device *dev,
>+		   struct genl_info *info,
>+		   size_t msg_size, void **usrhdr)
>+{
>+	struct sk_buff *new_msg;
>+	new_msg = genlmsg_new(msg_size, GFP_KERNEL);
>+	if (!new_msg)
>+		return new_msg;
>+
>+	*usrhdr = genlmsg_put_reply(new_msg, info, &dev->drm_genl_family, 0, info->genlhdr->cmd);
>+	if (!*usrhdr) {
>+		nlmsg_free(new_msg);
>+		new_msg = NULL;
>+	}
>+
>+	return new_msg;
>+}
>+EXPORT_SYMBOL(drm_genl_alloc_msg);
>+
>+static struct drm_device *genl_to_dev(struct genl_info *info)
>+{
>+	return xa_load(&drm_dev_xarray, info->nlhdr->nlmsg_type);
>+}
>+
>+static int drm_genl_list_errors(struct sk_buff *msg, struct genl_info *info)
>+{
>+	struct drm_device *dev = genl_to_dev(info);
>+
>+	if (GENL_REQ_ATTR_CHECK(info, DRM_RAS_ATTR_REQUEST))
>+		return -EINVAL;
>+
>+	if (WARN_ON(!dev->driver->genl_ops[info->genlhdr->cmd].doit))
>+		return -EOPNOTSUPP;
>+
>+	return dev->driver->genl_ops[info->genlhdr->cmd].doit(dev, msg,
>info);
>+}
>+
>+static int drm_genl_read_error(struct sk_buff *msg, struct genl_info *info)
>+{
>+	struct drm_device *dev = genl_to_dev(info);
>+
>+	if (GENL_REQ_ATTR_CHECK(info, DRM_RAS_ATTR_ERROR_ID))
>+		return -EINVAL;
>+
>+	if (WARN_ON(!dev->driver->genl_ops[info->genlhdr->cmd].doit))
>+		return -EOPNOTSUPP;
>+
>+	return dev->driver->genl_ops[info->genlhdr->cmd].doit(dev, msg,
>info);
>+}
>+
>+/* attribute policies */
>+static const struct nla_policy drm_attr_policy_query[DRM_ATTR_MAX + 1] = {
>+	[DRM_RAS_ATTR_REQUEST] = { .type = NLA_U8 },
>+};
>+
>+static const struct nla_policy drm_attr_policy_read_one[DRM_ATTR_MAX + 1]
>= {
>+	[DRM_RAS_ATTR_ERROR_ID] = { .type = NLA_U64 },
>+};
>+
>+/* drm genl operations definition */
>+const struct genl_ops drm_genl_ops[] = {
>+	{
>+		.cmd = DRM_RAS_CMD_QUERY,
>+		.doit = drm_genl_list_errors,
>+		.policy = drm_attr_policy_query,
>+	},
>+	{
>+		.cmd = DRM_RAS_CMD_READ_ONE,
>+		.doit = drm_genl_read_error,
>+		.policy = drm_attr_policy_read_one,
>+	},
>+	{
>+		.cmd = DRM_RAS_CMD_READ_ALL,
>+		.doit = drm_genl_list_errors,
>+		.policy = drm_attr_policy_query,
>+	},
>+};
>+
>+static void drm_genl_family_init(struct drm_device *dev)
>+{
>+	/* Use drm primary node name eg: card0 to name the genl family */
>+	snprintf(dev->drm_genl_family.name, sizeof(dev->drm_genl_family.name), "%s", dev->primary->kdev->kobj.name);
>+	dev->drm_genl_family.version = DRM_GENL_VERSION;
>+	dev->drm_genl_family.parallel_ops = true;
>+	dev->drm_genl_family.ops = drm_genl_ops;
>+	dev->drm_genl_family.n_ops = ARRAY_SIZE(drm_genl_ops);
>+	dev->drm_genl_family.maxattr = DRM_ATTR_MAX;
>+	dev->drm_genl_family.module = dev->dev->driver->owner;
>+}
>+
>+static void drm_genl_deregister(struct drm_device *dev,  void *arg)
>+{
>+	drm_dbg_driver(dev, "unregistering genl family %s\n", dev->drm_genl_family.name);
>+
>+	xa_erase(&drm_dev_xarray, dev->drm_genl_family.id);
>+
>+	genl_unregister_family(&dev->drm_genl_family);
>+}
>+
>+/**
>+ * drm_genl_register - Register genl family
>+ * @dev: drm_device for which genl family needs to be registered
>+ *
>+ * RETURNS:
>+ * 0 on success and negative error code on failure
>+ */
>+int drm_genl_register(struct drm_device *dev)
>+{
>+	int ret;
>+
>+	drm_genl_family_init(dev);
>+
>+	ret = genl_register_family(&dev->drm_genl_family);
>+	if (ret < 0) {
>+		drm_warn(dev, "genl family registration failed\n");
>+		return ret;
>+	}
>+
>+	drm_dbg_driver(dev, "genl family id %d and name %s\n", dev->drm_genl_family.id, dev->drm_genl_family.name);
>+
>+	ret = xa_err(xa_store(&drm_dev_xarray, dev->drm_genl_family.id, dev, GFP_KERNEL));
>+	if (ret)
>+		goto genl_unregister;
>+
>+	ret = drmm_add_action_or_reset(dev, drm_genl_deregister, NULL);
>+
>+	return ret;
>+
>+genl_unregister:
>+	genl_unregister_family(&dev->drm_genl_family);
>+	return ret;
>+}
>+
>+/**
>+ * drm_genl_exit: destroy drm_dev_xarray
>+ */
>+void drm_genl_exit(void)
>+{
>+	xa_destroy(&drm_dev_xarray);
>+}
>diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h
>index c490977ee250..d3ae91b7714d 100644
>--- a/include/drm/drm_device.h
>+++ b/include/drm/drm_device.h
>@@ -8,6 +8,7 @@
>
> #include <drm/drm_legacy.h>
> #include <drm/drm_mode_config.h>
>+#include <drm/drm_netlink.h>
>
> struct drm_driver;
> struct drm_minor;
>@@ -318,6 +319,13 @@ struct drm_device {
> 	 */
> 	struct dentry *debugfs_root;
>
>+	/**
>+	 * @drm_genl_family:
>+	 *
>+	 * Generic netlink family registration structure.
>+	 */
>+	struct genl_family drm_genl_family;
>+
> 	/* Everything below here is for legacy driver, never use! */
> 	/* private: */
> #if IS_ENABLED(CONFIG_DRM_LEGACY)
>diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h
>index e2640dc64e08..ebdb7850d235 100644
>--- a/include/drm/drm_drv.h
>+++ b/include/drm/drm_drv.h
>@@ -434,6 +434,13 @@ struct drm_driver {
> 	 */
> 	const struct file_operations *fops;
>
>+	/**
>+	 * @genl_ops:
>+	 *
>+	 * Drivers private callback to genl commands
>+	 */
>+	const struct driver_genl_ops *genl_ops;
>+
> #ifdef CONFIG_DRM_LEGACY
> 	/* Everything below here is for legacy driver, never use! */
> 	/* private: */
>diff --git a/include/drm/drm_netlink.h b/include/drm/drm_netlink.h
>new file mode 100644
>index 000000000000..54527dae7847
>--- /dev/null
>+++ b/include/drm/drm_netlink.h
>@@ -0,0 +1,30 @@
>+/* SPDX-License-Identifier: MIT */
>+/*
>+ * Copyright © 2023 Intel Corporation
>+ */
>+
>+#ifndef __DRM_NETLINK_H__
>+#define __DRM_NETLINK_H__
>+
>+#include <linux/netdevice.h>
>+#include <net/genetlink.h>
>+#include <net/sock.h>
>+#include <uapi/drm/drm_netlink.h>
>+
>+struct drm_device;
>+
>+struct driver_genl_ops {
>+	int		       (*doit)(struct drm_device *dev,
>+				       struct sk_buff *skb,
>+				       struct genl_info *info);
>+};
>+
>+int drm_genl_register(struct drm_device *dev);
>+void drm_genl_exit(void);
>+int drm_genl_reply(struct sk_buff *msg, struct genl_info *info, void *usrhdr);
>+struct sk_buff *
>+drm_genl_alloc_msg(struct drm_device *dev,
>+		   struct genl_info *info,
>+		   size_t msg_size, void **usrhdr);
>+#endif
>+
>diff --git a/include/uapi/drm/drm_netlink.h b/include/uapi/drm/drm_netlink.h
>new file mode 100644
>index 000000000000..aab42147a20e
>--- /dev/null
>+++ b/include/uapi/drm/drm_netlink.h
>@@ -0,0 +1,83 @@
>+/* SPDX-License-Identifier: MIT */
>+/*
>+ * Copyright 2023 Intel Corporation
>+ *
>+ * Permission is hereby granted, free of charge, to any person obtaining a
>+ * copy of this software and associated documentation files (the "Software"),
>+ * to deal in the Software without restriction, including without limitation
>+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>+ * and/or sell copies of the Software, and to permit persons to whom the
>+ * Software is furnished to do so, subject to the following conditions:
>+ *
>+ * The above copyright notice and this permission notice (including the next
>+ * paragraph) shall be included in all copies or substantial portions of the
>+ * Software.
>+ *
>+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>EXPRESS OR
>+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>MERCHANTABILITY,
>+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO
>EVENT SHALL
>+ * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
>DAMAGES OR
>+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
>OTHERWISE,
>+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
>USE OR
>+ * OTHER DEALINGS IN THE SOFTWARE.
>+ */
>+
>+#ifndef _DRM_NETLINK_H_
>+#define _DRM_NETLINK_H_
>+
>+#define DRM_GENL_VERSION 1
>+
>+#if defined(__cplusplus)
>+extern "C" {
>+#endif
>+
>+/**
>+ * enum drm_genl_error_cmds - Supported error commands
>+ *
>+ */
>+enum drm_genl_error_cmds {
>+	DRM_CMD_UNSPEC,
>+	/** @DRM_RAS_CMD_QUERY: Command to list all errors names with
>config-id */
>+	DRM_RAS_CMD_QUERY,
>+	/** @DRM_RAS_CMD_READ_ONE: Command to get a counter for a
>specific error */
>+	DRM_RAS_CMD_READ_ONE,
>+	/** @DRM_RAS_CMD_READ_ALL: Command to get counters of all
>errors */
>+	DRM_RAS_CMD_READ_ALL,
>+
>+	__DRM_CMD_MAX,
>+	DRM_CMD_MAX = __DRM_CMD_MAX - 1,
>+};
>+
>+/**
>+ * enum drm_error_attr - Attributes to use with drm_genl_error_cmds
>+ *
>+ */
>+enum drm_error_attr {
>+	DRM_ATTR_UNSPEC,
>+	DRM_ATTR_PAD = DRM_ATTR_UNSPEC,
>+	/**
>+	 * @DRM_RAS_ATTR_REQUEST: Should be used with
>DRM_RAS_CMD_QUERY,
>+	 * DRM_RAS_CMD_READ_ALL
>+	 */
>+	DRM_RAS_ATTR_REQUEST, /* NLA_U8 */
>+	/**
>+	 * @DRM_RAS_ATTR_QUERY_REPLY: First Nested attributed sent as a
>+	 * response to DRM_RAS_CMD_QUERY, DRM_RAS_CMD_READ_ALL
>commands.
>+	 */
>+	DRM_RAS_ATTR_QUERY_REPLY, /*NLA_NESTED*/
>+	/** @DRM_RAS_ATTR_ERROR_NAME: Used to pass error name */
>+	DRM_RAS_ATTR_ERROR_NAME, /* NLA_NUL_STRING */
>+	/** @DRM_RAS_ATTR_ERROR_ID: Used to pass error id */
>+	DRM_RAS_ATTR_ERROR_ID, /* NLA_U64 */
>+	/** @DRM_RAS_ATTR_ERROR_VALUE: Used to pass error value */
>+	DRM_RAS_ATTR_ERROR_VALUE, /* NLA_U64 */
>+
>+	__DRM_ATTR_MAX,
>+	DRM_ATTR_MAX = __DRM_ATTR_MAX - 1,
>+};
>+
>+#if defined(__cplusplus)
>+}
>+#endif
>+
>+#endif
>--
>2.25.1



More information about the Intel-xe mailing list