From: Jie Liu <[email protected]> Initialize the sxe2 PMD skeleton by implementing the PCI probe and remove functions. This includes the setup and cleanup of a character device used for control path communication between the user space and the hardware.
The character device provides an interface for ioctl-based management operations, supporting device-specific configuration. Signed-off-by: Jie Liu <[email protected]> --- drivers/common/sxe2/meson.build | 2 + drivers/common/sxe2/sxe2_common.c | 636 +++++++++++++++++++++ drivers/common/sxe2/sxe2_common.h | 86 +++ drivers/common/sxe2/sxe2_ioctl_chnl.c | 161 ++++++ drivers/common/sxe2/sxe2_ioctl_chnl.h | 141 +++++ drivers/common/sxe2/sxe2_ioctl_chnl_func.h | 45 ++ 6 files changed, 1071 insertions(+) create mode 100644 drivers/common/sxe2/sxe2_common.c create mode 100644 drivers/common/sxe2/sxe2_common.h create mode 100644 drivers/common/sxe2/sxe2_ioctl_chnl.c create mode 100644 drivers/common/sxe2/sxe2_ioctl_chnl.h create mode 100644 drivers/common/sxe2/sxe2_ioctl_chnl_func.h diff --git a/drivers/common/sxe2/meson.build b/drivers/common/sxe2/meson.build index 09ce556f70..b4ad4ed58d 100644 --- a/drivers/common/sxe2/meson.build +++ b/drivers/common/sxe2/meson.build @@ -15,5 +15,7 @@ cflags += [ deps += ['bus_pci', 'net', 'eal', 'ethdev'] sources = files( + 'sxe2_common.c', 'sxe2_common_log.c', + 'sxe2_ioctl_chnl.c', ) diff --git a/drivers/common/sxe2/sxe2_common.c b/drivers/common/sxe2/sxe2_common.c new file mode 100644 index 0000000000..dfdefb8b78 --- /dev/null +++ b/drivers/common/sxe2/sxe2_common.c @@ -0,0 +1,636 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd. + */ + +#include <rte_version.h> +#include <rte_pci.h> +#include <rte_dev.h> +#include <rte_devargs.h> +#include <rte_class.h> +#include <rte_malloc.h> +#include <rte_errno.h> +#include <rte_fbarray.h> +#include <rte_eal.h> +#include <eal_private.h> +#include <eal_memcfg.h> +#include <bus_driver.h> +#include <bus_pci_driver.h> +#include <eal_export.h> + +#include "sxe2_errno.h" +#include "sxe2_common.h" +#include "sxe2_common_log.h" +#include "sxe2_ioctl_chnl_func.h" + +static TAILQ_HEAD(sxe2_class_drivers, sxe2_class_driver) sxe2_class_drivers_list = + TAILQ_HEAD_INITIALIZER(sxe2_class_drivers_list); + +static TAILQ_HEAD(sxe2_common_devices, sxe2_common_device) sxe2_common_devices_list = + TAILQ_HEAD_INITIALIZER(sxe2_common_devices_list); + +static pthread_mutex_t sxe2_common_devices_list_lock; + +static struct rte_pci_id *sxe2_common_pci_id_table; + +static const struct { + const s8 *name; + u32 class_type; +} sxe2_class_types[] = { + { .name = "eth", .class_type = SXE2_CLASS_TYPE_ETH }, + { .name = "vdpa", .class_type = SXE2_CLASS_TYPE_VDPA }, +}; + +static u32 sxe2_class_name_to_value(const s8 *class_name) +{ + u32 class_type = SXE2_CLASS_TYPE_INVALID; + u32 i; + + for (i = 0; i < RTE_DIM(sxe2_class_types); i++) { + if (strcmp(class_name, sxe2_class_types[i].name) == 0) + class_type = sxe2_class_types[i].class_type; + } + + return class_type; +} + +static struct sxe2_common_device *sxe2_rtedev_to_cdev(struct rte_device *rte_dev) +{ + struct sxe2_common_device *cdev = NULL; + + TAILQ_FOREACH(cdev, &sxe2_common_devices_list, next) { + if (rte_dev == cdev->dev) + goto l_end; + } + + cdev = NULL; +l_end: + return cdev; +} + +static struct sxe2_class_driver *sxe2_class_driver_get(u32 class_type) +{ + struct sxe2_class_driver *cdrv = NULL; + + TAILQ_FOREACH(cdrv, &sxe2_class_drivers_list, next) { + if (cdrv->drv_class == class_type) + goto l_end; + } + + cdrv = NULL; +l_end: + return cdrv; +} + +static s32 sxe2_kvargs_preprocessing(struct sxe2_dev_kvargs_info *kv_info, + const struct rte_devargs *devargs) +{ + const struct rte_kvargs_pair *pair; + struct rte_kvargs *kvlist; + s32 ret = SXE2_ERROR; + u32 i; + + kvlist = rte_kvargs_parse(devargs->args, NULL); + if (kvlist == NULL) { + ret = SXE2_ERR_INVAL; + goto l_end; + } + + for (i = 0; i < kvlist->count; i++) { + pair = &kvlist->pairs[i]; + if (pair->value == NULL || *(pair->value) == '\0') { + PMD_LOG_ERR(COM, "Key %s has no value.", pair->key); + rte_kvargs_free(kvlist); + ret = SXE2_ERR_INVAL; + goto l_end; + } + } + + kv_info->kvlist = kvlist; + ret = SXE2_SUCCESS; + PMD_LOG_DEBUG(COM, "kvargs %d preprocessing success.", + kv_info->kvlist->count); +l_end: + return ret; +} + +static void sxe2_kvargs_free(struct sxe2_dev_kvargs_info *kv_info) +{ + if ((kv_info != NULL) && (kv_info->kvlist != NULL)) { + rte_kvargs_free(kv_info->kvlist); + kv_info->kvlist = NULL; + } +} + +RTE_EXPORT_INTERNAL_SYMBOL(sxe2_kvargs_process) +s32 +sxe2_kvargs_process(struct sxe2_dev_kvargs_info *kv_info, + const s8 *const key_match, arg_handler_t handler, void *opaque_arg) +{ + const struct rte_kvargs_pair *pair; + struct rte_kvargs *kvlist; + u32 i; + s32 ret = SXE2_SUCCESS; + + if ((kv_info == NULL) || (kv_info->kvlist == NULL) || + (key_match == NULL)) { + PMD_LOG_ERR(COM, "Failed to process kvargs, NULL parameter."); + ret = SXE2_ERR_INVAL; + goto l_end; + } + kvlist = kv_info->kvlist; + + for (i = 0; i < kvlist->count; i++) { + pair = &kvlist->pairs[i]; + if (strcmp(pair->key, key_match) == 0) { + ret = (*handler)(pair->key, pair->value, opaque_arg); + if (ret) + goto l_end; + + kv_info->is_used[i] = true; + break; + } + } + +l_end: + return ret; +} + +static s32 sxe2_parse_class_type(const s8 *key, const s8 *value, void *args) +{ + u32 *class_type = (u32 *)args; + s32 ret = SXE2_SUCCESS; + + *class_type = sxe2_class_name_to_value(value); + if (*class_type == SXE2_CLASS_TYPE_INVALID) { + ret = SXE2_ERR_INVAL; + PMD_LOG_ERR(COM, "Unsupported %s type: %s", key, value); + } + + return ret; +} + +static s32 sxe2_common_device_setup(struct sxe2_common_device *cdev) +{ + struct rte_pci_device *pci_dev = RTE_DEV_TO_PCI(cdev->dev); + s32 ret = SXE2_SUCCESS; + + if (rte_eal_process_type() != RTE_PROC_PRIMARY) + goto l_end; + + ret = sxe2_drv_dev_open(cdev, pci_dev); + if (ret != SXE2_SUCCESS) { + PMD_LOG_ERR(COM, "Open pmd chrdev failed, ret=%d", ret); + goto l_end; + } + + ret = sxe2_drv_dev_handshark(cdev); + if (ret != SXE2_SUCCESS) { + PMD_LOG_ERR(COM, "Handshark failed, ret=%d", ret); + goto l_close_dev; + } + + goto l_end; + +l_close_dev: + sxe2_drv_dev_close(cdev); +l_end: + return ret; +} + +static void sxe2_common_device_cleanup(struct sxe2_common_device *cdev) +{ + if (rte_eal_process_type() != RTE_PROC_PRIMARY) + return; + + if (TAILQ_EMPTY(&sxe2_common_devices_list)) + (void)rte_mem_event_callback_unregister("SXE2_MEM_ENVENT_CB", NULL); + + sxe2_drv_dev_close(cdev); +} + +static struct sxe2_common_device *sxe2_common_device_alloc( + struct rte_device *rte_dev, u32 class_type) +{ + struct sxe2_common_device *cdev = NULL; + + cdev = rte_zmalloc("sxe2_common_device", sizeof(*cdev), 0); + if (cdev == NULL) { + PMD_LOG_ERR(COM, "Fail to alloc sxe2 common device."); + goto l_end; + } + cdev->dev = rte_dev; + cdev->class_type = class_type; + cdev->config.kernel_reset = false; + rte_ticketlock_init(&cdev->config.lock); + + (void)pthread_mutex_lock(&sxe2_common_devices_list_lock); + TAILQ_INSERT_TAIL(&sxe2_common_devices_list, cdev, next); + (void)pthread_mutex_unlock(&sxe2_common_devices_list_lock); + +l_end: + return cdev; +} + +static void sxe2_common_device_free(struct sxe2_common_device *cdev) +{ + + (void)pthread_mutex_lock(&sxe2_common_devices_list_lock); + TAILQ_REMOVE(&sxe2_common_devices_list, cdev, next); + (void)pthread_mutex_unlock(&sxe2_common_devices_list_lock); + + rte_free(cdev); +} + +static bool sxe2_dev_is_pci(const struct rte_device *dev) +{ + return strcmp(dev->bus->name, "pci") == 0; +} + +static bool sxe2_dev_pci_id_match(const struct sxe2_class_driver *cdrv, + const struct rte_device *dev) +{ + const struct rte_pci_device *pci_dev; + const struct rte_pci_id *id_table; + bool ret = false; + + if (!sxe2_dev_is_pci(dev)) { + PMD_LOG_ERR(COM, "Device %s is not a PCI device", dev->name); + goto l_end; + } + + pci_dev = RTE_DEV_TO_PCI_CONST(dev); + for (id_table = cdrv->id_table; id_table->vendor_id != 0; + id_table++) { + + if (id_table->vendor_id != pci_dev->id.vendor_id && + id_table->vendor_id != RTE_PCI_ANY_ID) { + continue; + } + if (id_table->device_id != pci_dev->id.device_id && + id_table->device_id != RTE_PCI_ANY_ID) { + continue; + } + if (id_table->subsystem_vendor_id != + pci_dev->id.subsystem_vendor_id && + id_table->subsystem_vendor_id != RTE_PCI_ANY_ID) { + continue; + } + if (id_table->subsystem_device_id != + pci_dev->id.subsystem_device_id && + id_table->subsystem_device_id != RTE_PCI_ANY_ID) { + + continue; + } + if (id_table->class_id != pci_dev->id.class_id && + id_table->class_id != RTE_CLASS_ANY_ID) { + continue; + } + ret = true; + break; + } + +l_end: + return ret; +} + +static s32 sxe2_classes_driver_probe(struct sxe2_common_device *cdev, + struct sxe2_dev_kvargs_info *kv_info, u32 class_type) +{ + struct sxe2_class_driver *cdrv = NULL; + s32 ret = SXE2_ERROR; + + cdrv = sxe2_class_driver_get(class_type); + if (cdrv == NULL) { + PMD_LOG_ERR(COM, "Fail to get class type[%u] driver.", class_type); + goto l_end; + } + + if (!sxe2_dev_pci_id_match(cdrv, cdev->dev)) { + PMD_LOG_ERR(COM, "Fail to match pci id for driver:%s.", cdrv->name); + goto l_end; + } + + ret = cdrv->probe(cdev, kv_info); + if (ret) { + + PMD_LOG_DEBUG(COM, "Fail to probe driver:%s.", cdrv->name); + goto l_end; + } + + cdev->cdrv = cdrv; +l_end: + return ret; +} + +static s32 sxe2_classes_driver_remove(struct sxe2_common_device *cdev) +{ + struct sxe2_class_driver *cdrv = cdev->cdrv; + + return cdrv->remove(cdev); +} + +static s32 sxe2_kvargs_validate(struct sxe2_dev_kvargs_info *kv_info) +{ + s32 ret = SXE2_SUCCESS; + u32 i; + + if (rte_eal_process_type() != RTE_PROC_PRIMARY) + goto l_end; + + if (kv_info == NULL) + goto l_end; + + for (i = 0; i < kv_info->kvlist->count; i++) { + if (kv_info->is_used[i] == 0) { + PMD_LOG_ERR(COM, "Key \"%s\" is unsupported for the class driver.", + kv_info->kvlist->pairs[i].key); + ret = SXE2_ERR_INVAL; + goto l_end; + } + } + +l_end: + return ret; +} + +static s32 sxe2_common_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, + struct rte_pci_device *pci_dev) +{ + struct rte_device *rte_dev = &pci_dev->device; + struct sxe2_common_device *cdev; + struct sxe2_dev_kvargs_info *kv_info_p = NULL; + + u32 class_type = SXE2_CLASS_TYPE_ETH; + s32 ret = SXE2_ERROR; + + PMD_LOG_INFO(COM, "Probe pci device: %s", pci_dev->name); + + cdev = sxe2_rtedev_to_cdev(rte_dev); + if (cdev != NULL) { + PMD_LOG_ERR(COM, "Device %s already probed.", rte_dev->name); + ret = SXE2_ERR_BUSY; + goto l_end; + } + + if ((rte_dev->devargs != NULL) && (rte_dev->devargs->args != NULL)) { + kv_info_p = calloc(1, sizeof(struct sxe2_dev_kvargs_info)); + if (!kv_info_p) { + PMD_LOG_ERR(COM, "Failed to allocate memory for kv_info"); + goto l_end; + } + + ret = sxe2_kvargs_preprocessing(kv_info_p, rte_dev->devargs); + if (ret < 0) { + PMD_LOG_ERR(COM, "Unsupported device args: %s", + rte_dev->devargs->args); + goto l_free_kvargs; + } + + ret = sxe2_kvargs_process(kv_info_p, SXE2_DEVARGS_KEY_CLASS, + sxe2_parse_class_type, &class_type); + if (ret < 0) { + PMD_LOG_ERR(COM, "Unsupported sxe2 driver class: %s", + rte_dev->devargs->args); + goto l_free_args; + } + + } + + cdev = sxe2_common_device_alloc(rte_dev, class_type); + if (cdev == NULL) { + ret = SXE2_ERR_NOMEM; + goto l_free_args; + } + + ret = sxe2_common_device_setup(cdev); + if (ret != SXE2_SUCCESS) + goto l_err_setup; + + ret = sxe2_classes_driver_probe(cdev, kv_info_p, class_type); + if (ret != SXE2_SUCCESS) + goto l_err_probe; + + ret = sxe2_kvargs_validate(kv_info_p); + if (ret != SXE2_SUCCESS) { + PMD_LOG_ERR(COM, "Device args validate failed: %s", + rte_dev->devargs->args); + goto l_err_valid; + } + cdev->kvargs = kv_info_p; + + goto l_end; +l_err_valid: + (void)sxe2_classes_driver_remove(cdev); +l_err_probe: + sxe2_common_device_cleanup(cdev); +l_err_setup: + sxe2_common_device_free(cdev); +l_free_args: + sxe2_kvargs_free(kv_info_p); +l_free_kvargs: + free(kv_info_p); +l_end: + return ret; +} + +static s32 sxe2_common_pci_remove(struct rte_pci_device *pci_dev) +{ + struct sxe2_common_device *cdev; + s32 ret = SXE2_ERROR; + + PMD_LOG_INFO(COM, "Remove pci device: %s", pci_dev->name); + cdev = sxe2_rtedev_to_cdev(&pci_dev->device); + if (cdev == NULL) { + ret = SXE2_ERR_NODEV; + PMD_LOG_ERR(COM, "Fail to get remove device."); + goto l_end; + } + + ret = sxe2_classes_driver_remove(cdev); + if (ret != SXE2_SUCCESS) { + PMD_LOG_ERR(COM, "Fail to remove device: %s", pci_dev->name); + goto l_end; + } + + sxe2_common_device_cleanup(cdev); + + if (cdev->kvargs != NULL) { + sxe2_kvargs_free(cdev->kvargs); + free(cdev->kvargs); + cdev->kvargs = NULL; + } + + sxe2_common_device_free(cdev); + +l_end: + return ret; +} + +static struct rte_pci_driver sxe2_common_pci_driver = { + .driver = { + .name = SXE2_COMMON_PCI_DRIVER_NAME, + }, + .probe = sxe2_common_pci_probe, + .remove = sxe2_common_pci_remove, +}; + +static u32 sxe2_common_pci_id_table_size_get(const struct rte_pci_id *id_table) +{ + u32 table_size = 0; + + while (id_table->vendor_id != 0) { + table_size++; + id_table++; + } + + return table_size; +} + +static bool sxe2_common_pci_id_exists(const struct rte_pci_id *id, + const struct rte_pci_id *id_table, u32 next_idx) +{ + s32 current_size = next_idx - 1; + s32 i; + bool exists = false; + + for (i = 0; i < current_size; i++) { + if ((id->device_id == id_table[i].device_id) && + (id->vendor_id == id_table[i].vendor_id) && + (id->subsystem_vendor_id == id_table[i].subsystem_vendor_id) && + (id->subsystem_device_id == id_table[i].subsystem_device_id)) { + exists = true; + break; + } + } + + return exists; +} + +static void sxe2_common_pci_id_insert(struct rte_pci_id *id_table, + u32 *next_idx, const struct rte_pci_id *insert_table) +{ + for (; insert_table->vendor_id != 0; insert_table++) { + if (!sxe2_common_pci_id_exists(insert_table, id_table, *next_idx)) { + + id_table[*next_idx] = *insert_table; + (*next_idx)++; + } + } +} + +static s32 sxe2_common_pci_id_table_update(const struct rte_pci_id *id_table) +{ + const struct rte_pci_id *id_iter; + struct rte_pci_id *updated_table; + struct rte_pci_id *old_table; + u32 num_ids = 0; + u32 i = 0; + s32 ret = SXE2_SUCCESS; + + old_table = sxe2_common_pci_id_table; + if (old_table) + num_ids = sxe2_common_pci_id_table_size_get(old_table); + + num_ids += sxe2_common_pci_id_table_size_get(id_table); + + num_ids += 1; + + updated_table = calloc(num_ids, sizeof(*updated_table)); + if (!updated_table) { + PMD_LOG_ERR(COM, "Failed to allocate memory for PCI ID table"); + goto l_end; + } + + if (old_table == NULL) { + + for (id_iter = id_table; id_iter->vendor_id != 0; + id_iter++, i++) + updated_table[i] = *id_iter; + } else { + + for (id_iter = old_table; id_iter->vendor_id != 0; + id_iter++, i++) + updated_table[i] = *id_iter; + + sxe2_common_pci_id_insert(updated_table, &i, id_table); + } + + updated_table[i].vendor_id = 0; + sxe2_common_pci_driver.id_table = updated_table; + sxe2_common_pci_id_table = updated_table; + free(old_table); + +l_end: + return ret; +} + +static void sxe2_common_driver_on_register_pci(struct sxe2_class_driver *driver) +{ + if (driver->id_table != NULL) { + if (sxe2_common_pci_id_table_update(driver->id_table) != 0) + return; + } + + if (driver->intr_lsc) + sxe2_common_pci_driver.drv_flags |= RTE_PCI_DRV_INTR_LSC; + if (driver->intr_rmv) + sxe2_common_pci_driver.drv_flags |= RTE_PCI_DRV_INTR_RMV; +} + +RTE_EXPORT_INTERNAL_SYMBOL(sxe2_class_driver_register) +void +sxe2_class_driver_register(struct sxe2_class_driver *driver) +{ + sxe2_common_driver_on_register_pci(driver); + TAILQ_INSERT_TAIL(&sxe2_class_drivers_list, driver, next); +} + +static void sxe2_common_pci_init(void) +{ + const struct rte_pci_id empty_table[] = { + { + .vendor_id = 0 + }, + }; + s32 ret = SXE2_ERROR; + + if (sxe2_common_pci_id_table == NULL) { + ret = sxe2_common_pci_id_table_update(empty_table); + if (ret != SXE2_SUCCESS) + goto l_end; + } + rte_pci_register(&sxe2_common_pci_driver); + +l_end: + return; +} + +static bool sxe2_commoin_inited; + +RTE_EXPORT_INTERNAL_SYMBOL(sxe2_common_init) +void +sxe2_common_init(void) +{ + if (sxe2_commoin_inited) + goto l_end; + + pthread_mutex_init(&sxe2_common_devices_list_lock, NULL); +#ifdef SXE2_DPDK_DEBUG + sxe2_common_log_stream_init(); +#endif + sxe2_common_pci_init(); + sxe2_commoin_inited = true; + +l_end: + return; +} + +RTE_FINI(sxe2_common_pci_finish) +{ + if (sxe2_common_pci_id_table != NULL) { + rte_pci_unregister(&sxe2_common_pci_driver); + free(sxe2_common_pci_id_table); + } +} + +RTE_PMD_EXPORT_NAME(sxe2_common_pci); diff --git a/drivers/common/sxe2/sxe2_common.h b/drivers/common/sxe2/sxe2_common.h new file mode 100644 index 0000000000..f62e00e053 --- /dev/null +++ b/drivers/common/sxe2/sxe2_common.h @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd. + */ + +#ifndef __SXE2_COMMON_H__ +#define __SXE2_COMMON_H__ + +#include <rte_bitops.h> +#include <rte_kvargs.h> +#include <rte_compat.h> +#include <rte_memory.h> +#include <rte_ticketlock.h> + +#include "sxe2_type.h" + +#define SXE2_COMMON_PCI_DRIVER_NAME "sxe2_pci" + +#define SXE2_CDEV_TO_CMD_FD(cdev) \ + ((cdev)->config.cmd_fd) + +#define SXE2_DEVARGS_KEY_CLASS "class" + +struct sxe2_class_driver; + +enum sxe2_class_type { + SXE2_CLASS_TYPE_ETH = 0, + SXE2_CLASS_TYPE_VDPA, + SXE2_CLASS_TYPE_INVALID, +}; + +struct sxe2_common_dev_config { + s32 cmd_fd; + bool support_iommu; + bool kernel_reset; + rte_ticketlock_t lock; +}; + +struct sxe2_common_device { + struct rte_device *dev; + TAILQ_ENTRY(sxe2_common_device) next; + struct sxe2_class_driver *cdrv; + enum sxe2_class_type class_type; + struct sxe2_common_dev_config config; + struct sxe2_dev_kvargs_info *kvargs; +}; + +struct sxe2_dev_kvargs_info { + struct rte_kvargs *kvlist; + bool is_used[RTE_KVARGS_MAX]; +}; + +typedef s32 (sxe2_class_driver_probe_t)(struct sxe2_common_device *scdev, + struct sxe2_dev_kvargs_info *kvargs); + +typedef s32 (sxe2_class_driver_remove_t)(struct sxe2_common_device *scdev); + +struct sxe2_class_driver { + TAILQ_ENTRY(sxe2_class_driver) next; + enum sxe2_class_type drv_class; + const s8 *name; + sxe2_class_driver_probe_t *probe; + sxe2_class_driver_remove_t *remove; + const struct rte_pci_id *id_table; + u32 intr_lsc; + u32 intr_rmv; +}; + +__rte_internal +void +sxe2_common_mem_event_cb(enum rte_mem_event type, + const void *addr, size_t size, void *arg __rte_unused); + +__rte_internal +void +sxe2_class_driver_register(struct sxe2_class_driver *driver); + +__rte_internal +void +sxe2_common_init(void); + +__rte_internal +s32 +sxe2_kvargs_process(struct sxe2_dev_kvargs_info *kv_info, + const s8 *const key_match, arg_handler_t handler, void *opaque_arg); + +#endif diff --git a/drivers/common/sxe2/sxe2_ioctl_chnl.c b/drivers/common/sxe2/sxe2_ioctl_chnl.c new file mode 100644 index 0000000000..db09dd3126 --- /dev/null +++ b/drivers/common/sxe2/sxe2_ioctl_chnl.c @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd. + */ + + #include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <unistd.h> +#include <inttypes.h> +#include <rte_version.h> +#include <eal_export.h> + +#include "sxe2_osal.h" +#include "sxe2_errno.h" +#include "sxe2_common_log.h" +#include "sxe2_ioctl_chnl.h" +#include "sxe2_ioctl_chnl_func.h" + +#define SXE2_CHR_DEV_NAME "/dev/sxe2-dpdk-" + +RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_cmd_close) +void +sxe2_drv_cmd_close(struct sxe2_common_device *cdev) +{ + cdev->config.kernel_reset = true; +} + +RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_cmd_exec) +s32 +sxe2_drv_cmd_exec(struct sxe2_common_device *cdev, + struct sxe2_drv_cmd_params *cmd_params) +{ + s32 cmd_fd; + s32 ret = SXE2_ERR_IO; + + if (cdev->config.kernel_reset) { + ret = SXE2_ERR_PERM; + PMD_LOG_WARN(COM, "kernel reseted, need restart app."); + goto l_end; + } + + cmd_fd = SXE2_CDEV_TO_CMD_FD(cdev); + if (cmd_fd < 0) { + ret = SXE2_ERR_BADF; + PMD_LOG_ERR(COM, "Fail to exec cmd, fd[%d] error", cmd_fd); + goto l_end; + } + + PMD_LOG_DEBUG(COM, "Exec drv cmd fd[%d] trace_id[0x%"PRIx64"]" + "opcode[0x%x] req_len[%d] resp_len[%d]", + cmd_fd, cmd_params->trace_id, cmd_params->opcode, + cmd_params->req_len, cmd_params->resp_len); + + rte_ticketlock_lock(&cdev->config.lock); + ret = ioctl(cmd_fd, SXE2_COM_CMD_PASSTHROUGH, cmd_params); + if (ret < 0) { + PMD_LOG_ERR(COM, "Fail to exec cmd, fd[%d] opcode[0x%x] ret[%d], err:%s", + cmd_fd, cmd_params->opcode, ret, strerror(errno)); + ret = -errno; + rte_ticketlock_unlock(&cdev->config.lock); + goto l_end; + } + rte_ticketlock_unlock(&cdev->config.lock); + +l_end: + return ret; +} + +RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_open) +s32 +sxe2_drv_dev_open(struct sxe2_common_device *cdev, struct rte_pci_device *pci_dev) +{ + s32 ret = SXE2_SUCCESS; + s32 fd = 0; + s8 drv_name[32] = {0}; + + snprintf(drv_name, sizeof(drv_name), + "%s%04"PRIx32":%02"PRIx8":%02"PRIx8".%"PRIx8, + SXE2_CHR_DEV_NAME, + pci_dev->addr.domain, + pci_dev->addr.bus, + pci_dev->addr.devid, + pci_dev->addr.function); + + fd = open(drv_name, O_RDWR); + if (fd < 0) { + ret = SXE2_ERR_BADF; + PMD_LOG_ERR(COM, "Fail to open device:%s, ret=%d, err:%s", + drv_name, ret, strerror(errno)); + goto l_end; + } + + SXE2_CDEV_TO_CMD_FD(cdev) = fd; + + PMD_LOG_INFO(COM, "Successfully opened device:%s, fd=%d", + drv_name, SXE2_CDEV_TO_CMD_FD(cdev)); + +l_end: + return ret; +} + +RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_close) +void +sxe2_drv_dev_close(struct sxe2_common_device *cdev) +{ + s32 fd = SXE2_CDEV_TO_CMD_FD(cdev); + + if (fd > 0) + close(fd); + PMD_LOG_INFO(COM, "closed device fd=%d", fd); + SXE2_CDEV_TO_CMD_FD(cdev) = -1; +} + +RTE_EXPORT_INTERNAL_SYMBOL(sxe2_drv_dev_handshark) +s32 +sxe2_drv_dev_handshark(struct sxe2_common_device *cdev) +{ + s32 ret = SXE2_SUCCESS; + s32 cmd_fd = 0; + struct sxe2_ioctl_cmd_common_hdr cmd_params; + + if (cdev->config.kernel_reset) { + ret = SXE2_ERR_PERM; + PMD_LOG_WARN(COM, "kernel reseted, need restart app."); + goto l_end; + } + + cmd_fd = SXE2_CDEV_TO_CMD_FD(cdev); + if (cmd_fd < 0) { + ret = SXE2_ERR_BADF; + PMD_LOG_ERR(COM, "Failed to exec cmd, fd=%d", cmd_fd); + goto l_end; + } + + PMD_LOG_DEBUG(COM, "Open fd=%d to handshark with kernel", cmd_fd); + + memset(&cmd_params, 0, sizeof(struct sxe2_ioctl_cmd_common_hdr)); + cmd_params.dpdk_ver = SXE2_COM_VER; + cmd_params.msg_len = sizeof(struct sxe2_ioctl_cmd_common_hdr); + + rte_ticketlock_lock(&cdev->config.lock); + ret = ioctl(cmd_fd, SXE2_COM_CMD_HANDSHAKE, &cmd_params); + if (ret < 0) { + PMD_LOG_ERR(COM, "Failed to handshark, fd=%d, ret=%d, err:%s", + cmd_fd, ret, strerror(errno)); + ret = SXE2_ERR_IO; + rte_ticketlock_unlock(&cdev->config.lock); + goto l_end; + } + rte_ticketlock_unlock(&cdev->config.lock); + + if (cmd_params.cap & BIT(SXE2_COM_CAP_IOMMU_MAP)) + cdev->config.support_iommu = true; + else + cdev->config.support_iommu = false; + +l_end: + return ret; +} diff --git a/drivers/common/sxe2/sxe2_ioctl_chnl.h b/drivers/common/sxe2/sxe2_ioctl_chnl.h new file mode 100644 index 0000000000..eedb3d6693 --- /dev/null +++ b/drivers/common/sxe2/sxe2_ioctl_chnl.h @@ -0,0 +1,141 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd. + */ + +#ifndef __SXE2_IOCTL_CHNL_H__ +#define __SXE2_IOCTL_CHNL_H__ + +#ifdef SXE2_DPDK_DRIVER + +#include <rte_version.h> +#include <bus_pci_driver.h> +#include "sxe2_type.h" +#endif + +#ifdef SXE2_LINUX_DRIVER +#ifdef __KERNEL__ +#include <linux/types.h> +#include <linux/ioctl.h> +#endif +#endif + +#include "sxe2_internal_ver.h" + +#define SXE2_COM_INVAL_U32 0xFFFFFFFF + +#define SXE2_COM_PCI_OFFSET_SHIFT 40 + +#define SXE2_COM_PCI_INDEX_TO_OFFSET(index) ((u64)(index) << SXE2_COM_PCI_OFFSET_SHIFT) +#define SXE2_COM_PCI_OFFSET_MASK (((u64)(1) << SXE2_COM_PCI_OFFSET_SHIFT) - 1) +#define SXE2_COM_PCI_OFFSET_GEN(index, off) ((((u64)(index)) << SXE2_COM_PCI_OFFSET_SHIFT) | \ + (((u64)(off)) & SXE2_COM_PCI_OFFSET_MASK)) + +#define SXE2_DRV_TRACE_ID_COUNT_MASK 0x003FFFFFFFFFFFFFLLU + +#define SXE2_DRV_CMD_DFLT_TIMEOUT (30) + +#define SXE2_COM_VER_MAJOR 1 +#define SXE2_COM_VER_MINOR 0 +#define SXE2_COM_VER SXE2_MK_VER(SXE2_COM_VER_MAJOR, SXE2_COM_VER_MINOR) + +enum SXE2_COM_CMD { + SXE2_DEVICE_HANDSHAKE = 1, + SXE2_DEVICE_IO_IRQS_REQ, + SXE2_DEVICE_EVT_IRQ_REQ, + SXE2_DEVICE_RST_IRQ_REQ, + SXE2_DEVICE_EVT_CAUSE_GET, + SXE2_DEVICE_DMA_MAP, + SXE2_DEVICE_DMA_UNMAP, + SXE2_DEVICE_PASSTHROUGH, + SXE2_DEVICE_MAX, +}; + +#define SXE2_CMD_TYPE 'S' + +#define SXE2_COM_CMD_HANDSHAKE _IO(SXE2_CMD_TYPE, SXE2_DEVICE_HANDSHAKE) +#define SXE2_COM_CMD_IO_IRQS_REQ _IO(SXE2_CMD_TYPE, SXE2_DEVICE_IO_IRQS_REQ) +#define SXE2_COM_CMD_EVT_IRQ_REQ _IO(SXE2_CMD_TYPE, SXE2_DEVICE_EVT_IRQ_REQ) +#define SXE2_COM_CMD_RST_IRQ_REQ _IO(SXE2_CMD_TYPE, SXE2_DEVICE_RST_IRQ_REQ) +#define SXE2_COM_CMD_EVT_CAUSE_GET _IO(SXE2_CMD_TYPE, SXE2_DEVICE_EVT_CAUSE_GET) +#define SXE2_COM_CMD_DMA_MAP _IO(SXE2_CMD_TYPE, SXE2_DEVICE_DMA_MAP) +#define SXE2_COM_CMD_DMA_UNMAP _IO(SXE2_CMD_TYPE, SXE2_DEVICE_DMA_UNMAP) +#define SXE2_COM_CMD_PASSTHROUGH _IO(SXE2_CMD_TYPE, SXE2_DEVICE_PASSTHROUGH) + +enum sxe2_com_cap { + SXE2_COM_CAP_IOMMU_MAP = 0, +}; + +struct sxe2_ioctl_cmd_common_hdr { + u32 dpdk_ver; + u32 drv_ver; + u32 msg_len; + u32 cap; + u8 reserved[32]; +}; + +struct sxe2_drv_cmd_params { + u64 trace_id; + u32 timeout; + u32 opcode; + u16 vsi_id; + u16 repr_id; + u32 req_len; + u32 resp_len; + void *req_data; + void *resp_data; + u8 resv[32]; +}; + +struct sxe2_ioctl_irq_set { + u32 cnt; + u8 resv[4]; + u32 base_irq_in_com; + s32 *event_fd; +}; + +enum sxe2_com_event_cause { + SXE2_COM_EC_LINK_CHG = 0, + SXE2_COM_SW_MODE_LEGACY, + SXE2_COM_SW_MODE_SWITCHDEV, + SXE2_COM_FC_ST_CHANGE, + + SXE2_COM_EC_RESET = 62, + SXE2_COM_EC_MAX = 63, +}; + +struct sxe2_ioctl_other_evt_set { + s32 eventfd; + u8 resv[4]; + u64 filter_table; +}; + +struct sxe2_ioctl_other_evt_get { + u64 evt_cause; + u8 resv[8]; +}; + +struct sxe2_ioctl_reset_sub_set { + s32 eventfd; + u8 resv[4]; +}; + +struct sxe2_ioctl_iommu_dma_map { + u64 vaddr; + u64 iova; + u64 size; + u8 resv[4]; +}; + +struct sxe2_ioctl_iommu_dma_unmap { + u64 iova; +}; + +union sxe2_drv_trace_info { + u64 id; + struct { + u64 count : 54; + u64 cpu_id : 10; + } sxe2_drv_trace_id_param; +}; + +#endif diff --git a/drivers/common/sxe2/sxe2_ioctl_chnl_func.h b/drivers/common/sxe2/sxe2_ioctl_chnl_func.h new file mode 100644 index 0000000000..0c3cb9caea --- /dev/null +++ b/drivers/common/sxe2/sxe2_ioctl_chnl_func.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (C), 2025, Wuxi Stars Micro System Technologies Co., Ltd. + */ + +#ifndef __SXE2_IOCTL_CHNL_FUNC_H__ +#define __SXE2_IOCTL_CHNL_FUNC_H__ + +#include <rte_version.h> +#include <bus_pci_driver.h> + +#include "sxe2_type.h" +#include "sxe2_common.h" +#include "sxe2_ioctl_chnl.h" + +#ifdef __cplusplus +extern "C" { +#endif + +__rte_internal +void +sxe2_drv_cmd_close(struct sxe2_common_device *cdev); + +__rte_internal +s32 +sxe2_drv_cmd_exec(struct sxe2_common_device *cdev, + struct sxe2_drv_cmd_params *cmd_params); + +__rte_internal +s32 +sxe2_drv_dev_open(struct sxe2_common_device *cdev, + struct rte_pci_device *pci_dev); + +__rte_internal +void +sxe2_drv_dev_close(struct sxe2_common_device *cdev); + +__rte_internal +s32 +sxe2_drv_dev_handshark(struct sxe2_common_device *cdev); + +#ifdef __cplusplus +} +#endif + +#endif -- 2.47.3

