Add the Linux client driver for the Network Packet ACcelerator (NPAC). The driver communicates with the NPAC host driver via RPMsg, allowing offloading of ethernet-related packet processing tasks.
The driver provides the basic framework for receiving offload commands via IOCTL and communicating with the NPAC hardware accelerator. Signed-off-by: Jaspinder Budhal <[email protected]> --- drivers/accel/Kconfig | 1 + drivers/accel/Makefile | 1 + drivers/accel/npac/Kconfig | 13 ++ drivers/accel/npac/Makefile | 3 + drivers/accel/npac/npac_drv.c | 218 ++++++++++++++++++++++++++++++++++ 5 files changed, 236 insertions(+) create mode 100644 drivers/accel/npac/Kconfig create mode 100644 drivers/accel/npac/Makefile create mode 100644 drivers/accel/npac/npac_drv.c diff --git a/drivers/accel/Kconfig b/drivers/accel/Kconfig index bdf48ccafcf2..a6d8c1ebfcf1 100644 --- a/drivers/accel/Kconfig +++ b/drivers/accel/Kconfig @@ -28,6 +28,7 @@ source "drivers/accel/amdxdna/Kconfig" source "drivers/accel/ethosu/Kconfig" source "drivers/accel/habanalabs/Kconfig" source "drivers/accel/ivpu/Kconfig" +source "drivers/accel/npac/Kconfig" source "drivers/accel/qaic/Kconfig" source "drivers/accel/rocket/Kconfig" diff --git a/drivers/accel/Makefile b/drivers/accel/Makefile index 1d3a7251b950..0df7b9f2ae18 100644 --- a/drivers/accel/Makefile +++ b/drivers/accel/Makefile @@ -4,5 +4,6 @@ obj-$(CONFIG_DRM_ACCEL_AMDXDNA) += amdxdna/ obj-$(CONFIG_DRM_ACCEL_ARM_ETHOSU) += ethosu/ obj-$(CONFIG_DRM_ACCEL_HABANALABS) += habanalabs/ obj-$(CONFIG_DRM_ACCEL_IVPU) += ivpu/ +obj-$(CONFIG_DRM_ACCEL_NPAC_CLIENT) += npac/ obj-$(CONFIG_DRM_ACCEL_QAIC) += qaic/ obj-$(CONFIG_DRM_ACCEL_ROCKET) += rocket/ \ No newline at end of file diff --git a/drivers/accel/npac/Kconfig b/drivers/accel/npac/Kconfig new file mode 100644 index 000000000000..a9543ac2c7aa --- /dev/null +++ b/drivers/accel/npac/Kconfig @@ -0,0 +1,13 @@ +config DRM_ACCEL_NPAC_CLIENT + tristate "NPAC Client Driver" + depends on DRM_ACCEL + depends on RPMSG + help + This driver is the NPAC (Network Packet ACcelerator) client, + communicating with the NPAC host driver running on a remote + processor over RPMsg. The driver registers with the DRM accelerator + framework and exposes /dev/accel/accel* as the userspace interface + for ACL rule offload operations. + If you have a device with NPAC and wish to use it with this + driver, say M to compile this driver as a module, or Y to + compile it into the kernel. diff --git a/drivers/accel/npac/Makefile b/drivers/accel/npac/Makefile new file mode 100644 index 000000000000..89f4773d7041 --- /dev/null +++ b/drivers/accel/npac/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_DRM_ACCEL_NPAC_CLIENT) += npac_drv.o diff --git a/drivers/accel/npac/npac_drv.c b/drivers/accel/npac/npac_drv.c new file mode 100644 index 000000000000..7516382ba74b --- /dev/null +++ b/drivers/accel/npac/npac_drv.c @@ -0,0 +1,218 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Copyright (C) 2026 Texas Instruments Incorporated - https://www.ti.com/ + */ + +#include <drm/drm_accel.h> +#include <drm/drm_drv.h> +#include <drm/drm_file.h> +#include <drm/drm_gem.h> +#include <drm/drm_ioctl.h> +#include <linux/completion.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/rpmsg.h> + +#define NPAC_RPMSG_SERVICE_NAME "ti.npac" +#define NPAC_ACK_TIMEOUT_MS 1000 + +/** + * enum npac_acl_cmd - IOCTL command numbers for NPAC ACL operations. + */ +enum npac_acl_cmd { + /** @NPAC_ACL_ADD_RULE: Add an ACL rule. */ + NPAC_ACL_ADD_RULE, + + /** @NPAC_ACL_DELETE_RULE: Delete an ACL rule. */ + NPAC_ACL_DELETE_RULE, +}; + +/** + * enum npac_acl_match_type - Match field selector for an ACL rule. + */ +enum npac_acl_match_type { + /** @NPAC_ACL_MATCH_SRC_IPV4: Match on source IPv4 address. */ + NPAC_ACL_MATCH_SRC_IPV4 = 1, + + /** @NPAC_ACL_MATCH_DST_IPV4: Match on destination IPv4 address. */ + NPAC_ACL_MATCH_DST_IPV4, + + /** @NPAC_ACL_MATCH_SRC_MAC: Match on source MAC address. */ + NPAC_ACL_MATCH_SRC_MAC, + + /** @NPAC_ACL_MATCH_DST_MAC: Match on destination MAC address. */ + NPAC_ACL_MATCH_DST_MAC, +}; + +/** + * enum npac_acl_verdict - Action to apply when an ACL rule matches. + */ +enum npac_acl_verdict { + /** @NPAC_ACL_VERDICT_ALLOW: Accept the matched packet. */ + NPAC_ACL_VERDICT_ALLOW = 1, + + /** @NPAC_ACL_VERDICT_DROP: Drop the matched packet. */ + NPAC_ACL_VERDICT_DROP, +}; + +/* Sized for the largest match field: a 6-byte MAC address. */ +#define NPAC_ACL_MATCH_VALUE_MAX 6 + +struct npac_acl_offload_rule { + __u32 match_type; + __u32 verdict; + __u8 match_value[NPAC_ACL_MATCH_VALUE_MAX]; +}; + +#define DRM_IOCTL_NPAC_ACL_ADD_RULE \ + DRM_IOWR(DRM_COMMAND_BASE + NPAC_ACL_ADD_RULE, struct npac_acl_offload_rule) + +#define DRM_IOCTL_NPAC_ACL_DELETE_RULE \ + DRM_IOWR(DRM_COMMAND_BASE + NPAC_ACL_DELETE_RULE, struct npac_acl_offload_rule) + +struct npac_device { + struct drm_device drm; + struct rpmsg_device *rpdev; + struct mutex req_lock; /* lock for request */ + struct completion ack; +}; + +static inline struct npac_device *drm_to_npac_device(struct drm_device *dev) +{ + return container_of(dev, struct npac_device, drm); +} + +static int npac_add_rule_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct npac_device *npac = drm_to_npac_device(dev); + struct npac_acl_offload_rule *rule = data; + int ret; + + dev_dbg(dev->dev, "add rule ioctl received\n"); + + mutex_lock(&npac->req_lock); + reinit_completion(&npac->ack); + ret = rpmsg_send(npac->rpdev->ept, rule, sizeof(*rule)); + if (ret) { + dev_err(dev->dev, "rpmsg_send failed: %d\n", ret); + mutex_unlock(&npac->req_lock); + return ret; + } + if (!wait_for_completion_timeout(&npac->ack, + msecs_to_jiffies(NPAC_ACK_TIMEOUT_MS))) { + dev_err(dev->dev, "ack timed out\n"); + mutex_unlock(&npac->req_lock); + return -ETIMEDOUT; + } + mutex_unlock(&npac->req_lock); + return 0; +} + +static int npac_delete_rule_ioctl(struct drm_device *dev, void *data, + struct drm_file *file) +{ + struct npac_device *npac = drm_to_npac_device(dev); + struct npac_acl_offload_rule *rule = data; + int ret; + + dev_dbg(dev->dev, "delete rule ioctl received\n"); + + mutex_lock(&npac->req_lock); + reinit_completion(&npac->ack); + ret = rpmsg_send(npac->rpdev->ept, rule, sizeof(*rule)); + if (ret) { + dev_err(dev->dev, "rpmsg_send failed: %d\n", ret); + mutex_unlock(&npac->req_lock); + return ret; + } + if (!wait_for_completion_timeout(&npac->ack, + msecs_to_jiffies(NPAC_ACK_TIMEOUT_MS))) { + dev_err(dev->dev, "ack timed out\n"); + mutex_unlock(&npac->req_lock); + return -ETIMEDOUT; + } + mutex_unlock(&npac->req_lock); + return 0; +} + +static const struct drm_ioctl_desc npac_drm_ioctls[] = { + DRM_IOCTL_DEF_DRV(NPAC_ACL_ADD_RULE, npac_add_rule_ioctl, DRM_ROOT_ONLY), + DRM_IOCTL_DEF_DRV(NPAC_ACL_DELETE_RULE, npac_delete_rule_ioctl, DRM_ROOT_ONLY), +}; + +DEFINE_DRM_ACCEL_FOPS(npac_fops); + +static const struct drm_driver npac_drm_driver = { + .driver_features = DRIVER_COMPUTE_ACCEL, + .ioctls = npac_drm_ioctls, + .num_ioctls = ARRAY_SIZE(npac_drm_ioctls), + .fops = &npac_fops, + .name = "npac", + .desc = "NPAC Client Driver", +}; + +static int npac_cb(struct rpmsg_device *rpdev, void *data, int len, + void *priv, u32 src) +{ + struct npac_device *npac = dev_get_drvdata(&rpdev->dev); + + dev_dbg(&rpdev->dev, "ack received\n"); + complete(&npac->ack); + return 0; +} + +static int npac_probe(struct rpmsg_device *rpdev) +{ + struct npac_device *npac; + int ret; + + npac = devm_drm_dev_alloc(&rpdev->dev, &npac_drm_driver, + struct npac_device, drm); + if (IS_ERR(npac)) + return PTR_ERR(npac); + + npac->rpdev = rpdev; + mutex_init(&npac->req_lock); + init_completion(&npac->ack); + dev_set_drvdata(&rpdev->dev, npac); + + ret = drm_dev_register(&npac->drm, 0); + if (ret) { + dev_err(&rpdev->dev, "Failed to register DRM accel device: %d\n", ret); + return ret; + } + + dev_info(&rpdev->dev, "NPAC Client driver probed\n"); + return 0; +} + +static void npac_remove(struct rpmsg_device *rpdev) +{ + struct npac_device *npac = dev_get_drvdata(&rpdev->dev); + + drm_dev_unplug(&npac->drm); + + dev_info(&rpdev->dev, "NPAC Client Driver removed\n"); +} + +static struct rpmsg_device_id npac_id_table[] = { + { .name = NPAC_RPMSG_SERVICE_NAME }, + {}, +}; +MODULE_DEVICE_TABLE(rpmsg, npac_id_table); + +static struct rpmsg_driver npac_driver = { + .drv.name = KBUILD_MODNAME, + .id_table = npac_id_table, + .probe = npac_probe, + .callback = npac_cb, + .remove = npac_remove, +}; + +module_rpmsg_driver(npac_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("NPAC Client Driver"); +MODULE_AUTHOR("Jaspinder Budhal <[email protected]>"); -- 2.34.1
