From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 53FB8A0564; Thu, 11 Mar 2021 14:01:52 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 10E2E22A3E4; Thu, 11 Mar 2021 14:01:52 +0100 (CET) Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by mails.dpdk.org (Postfix) with ESMTP id CBCDE40689 for ; Thu, 11 Mar 2021 14:01:50 +0100 (CET) Received: from Internal Mail-Server by MTLPINE1 (envelope-from xuemingl@nvidia.com) with SMTP; 11 Mar 2021 15:01:45 +0200 Received: from nvidia.com ([172.27.8.79]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 12BD1gSj018339; Thu, 11 Mar 2021 15:01:43 +0200 From: Xueming Li To: NBU-Contact-Thomas Monjalon Cc: dev@dpdk.org, xuemingl@nvidia.com, Parav Pandit , Ray Kinsella , Neil Horman Date: Thu, 11 Mar 2021 21:01:13 +0800 Message-Id: <20210311130113.31382-1-xuemingl@nvidia.com> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [dpdk-dev] [RFC] bus/auxiliary: introduce auxiliary bus X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Auxiliary [1] provides a way to split function into child-devices representing sub-domains of functionality. Each auxiliary_device represents a part of its parent functionality. Auxiliary device is identified by unique device name, sysfs path: /sys/bus/auxiliary/devices/ [1] kernel auxiliary bus document: https://www.kernel.org/doc/html/latest/driver-api/auxiliary_bus.html Signed-off-by: Xueming Li --- MAINTAINERS | 5 + drivers/bus/auxiliary/auxiliary_common.c | 410 ++++++++++++++++++++++ drivers/bus/auxiliary/auxiliary_params.c | 58 +++ drivers/bus/auxiliary/linux/auxiliary.c | 144 ++++++++ drivers/bus/auxiliary/meson.build | 17 + drivers/bus/auxiliary/private.h | 119 +++++++ drivers/bus/auxiliary/rte_bus_auxiliary.h | 193 ++++++++++ drivers/bus/auxiliary/version.map | 11 + drivers/bus/meson.build | 2 +- 9 files changed, 958 insertions(+), 1 deletion(-) create mode 100644 drivers/bus/auxiliary/auxiliary_common.c create mode 100644 drivers/bus/auxiliary/auxiliary_params.c create mode 100644 drivers/bus/auxiliary/linux/auxiliary.c create mode 100644 drivers/bus/auxiliary/meson.build create mode 100644 drivers/bus/auxiliary/private.h create mode 100644 drivers/bus/auxiliary/rte_bus_auxiliary.h create mode 100644 drivers/bus/auxiliary/version.map diff --git a/MAINTAINERS b/MAINTAINERS index e341bc81d5..00db01e471 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -514,6 +514,11 @@ F: doc/guides/mempool/octeontx2.rst Bus Drivers ----------- +Auxiliary bus driver +M: Parav Pandit +M: Xueming Li +F: drivers/bus/auxiliary/ + Intel FPGA bus M: Rosen Xu F: drivers/bus/ifpga/ diff --git a/drivers/bus/auxiliary/auxiliary_common.c b/drivers/bus/auxiliary/auxiliary_common.c new file mode 100644 index 0000000000..14b81dffce --- /dev/null +++ b/drivers/bus/auxiliary/auxiliary_common.c @@ -0,0 +1,410 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Mellanox Technologies, Ltd + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "private.h" +#include "rte_bus_auxiliary.h" + + +#define SYSFS_AUXILIARY_DEVICES "/sys/bus/auxiliary/devices" + +int auxiliary_logtype_bus; + +const char *rte_auxiliary_get_sysfs_path(void) +{ + const char *path = NULL; + +#ifdef RTE_EXEC_ENV_LINUX + path = getenv("SYSFS_AUXILIARY_DEVICES"); + if (path == NULL) + return SYSFS_AUXILIARY_DEVICES; +#endif + + return path; +} + +static struct rte_devargs * +auxiliary_devargs_lookup(const char *name) +{ + struct rte_devargs *devargs; + + RTE_EAL_DEVARGS_FOREACH("auxiliary", devargs) { + if (strcmp(devargs->name, name) == 0) + return devargs; + } + return NULL; +} + +void +auxiliary_on_scan(struct rte_auxiliary_device *dev) +{ + struct rte_devargs *devargs; + + devargs = auxiliary_devargs_lookup(dev->name); + dev->device.devargs = devargs; +} + +/* + * Match the auxiliary Driver and Device using driver function. + */ +bool +auxiliary_match(const struct rte_auxiliary_driver *auxiliary_drv, + const struct rte_auxiliary_device *auxiliary_dev) +{ + if (auxiliary_drv->match == NULL) + return false; + return auxiliary_drv->match(auxiliary_dev->name); +} + +/* + * Call the probe() function of the driver. + */ +static int +rte_auxiliary_probe_one_driver(struct rte_auxiliary_driver *dr, + struct rte_auxiliary_device *dev) +{ + int ret; + bool dev_probed; + + if ((dr == NULL) || (dev == NULL)) + return -EINVAL; + + /* The device is not blocked; Check if driver supports it */ + if (!auxiliary_match(dr, dev)) + /* Match of device and driver failed */ + return 1; + + AUXILIAR_LOG(DEBUG, "Auxiliary device %s on NUMA socket %i\n", + dev->name, dev->device.numa_node); + + /* no initialization when marked as blocked, return without error */ + if (dev->device.devargs != NULL && + dev->device.devargs->policy == RTE_DEV_BLOCKED) { + AUXILIAR_LOG(INFO, " Device is blocked, not initializing\n"); + return -1; + } + + if (dev->device.numa_node < 0) { + AUXILIAR_LOG(WARNING, " Invalid NUMA socket, default to 0\n"); + dev->device.numa_node = 0; + } + + dev_probed = rte_dev_is_probed(&dev->device); + if (dev_probed && !(dr->drv_flags & RTE_AUXILIARY_DRV_PROBE_AGAIN)) { + AUXILIAR_LOG(DEBUG, " Device %s is already probed\n", + dev->device.name); + return -EEXIST; + } + + AUXILIAR_LOG(DEBUG, " Probe driver: %s\n", dr->driver.name); + + if (!dev_probed) { + enum rte_iova_mode iova_mode; + + iova_mode = rte_eal_iova_mode(); + if ((dr->drv_flags & RTE_AUXILIARY_DRV_NEED_IOVA_AS_VA) > 0 && + iova_mode != RTE_IOVA_VA) { + AUXILIAR_LOG(ERR, " Expecting VA IOVA mode but current mode is PA, not initializing\n"); + return -EINVAL; + } + + dev->driver = dr; + } + + AUXILIAR_LOG(INFO, "Probe auxiliary driver: %s device: %s (socket %i)\n", + dr->driver.name, dev->name, dev->device.numa_node); + ret = dr->probe(dr, dev); + if (dev_probed) + return ret; /* no rollback if already succeeded earlier */ + if (ret) + dev->driver = NULL; + else + dev->device.driver = &dr->driver; + + return ret; +} + +/* + * Call the remove() function of the driver. + */ +static int +rte_auxiliary_detach_dev(struct rte_auxiliary_device *dev) +{ + struct rte_auxiliary_driver *dr; + int ret = 0; + + if (dev == NULL) + return -EINVAL; + + dr = dev->driver; + + AUXILIAR_LOG(DEBUG, "Auxiliary device %s on NUMA socket %i\n", + dev->name, dev->device.numa_node); + + AUXILIAR_LOG(DEBUG, " remove driver: %s %s\n", + dev->name, dr->driver.name); + + if (dr->remove) { + ret = dr->remove(dev); + if (ret < 0) + return ret; + } + + /* clear driver structure */ + dev->driver = NULL; + dev->device.driver = NULL; + + return 0; +} + +/* + * Call the probe() function of all registered driver for the given device. + * Return < 0 if initialization failed. + * Return 1 if no driver is found for this device. + */ +static int +auxiliary_probe_all_drivers(struct rte_auxiliary_device *dev) +{ + struct rte_auxiliary_driver *dr = NULL; + int rc = 0; + + if (dev == NULL) + return -EINVAL; + + FOREACH_DRIVER_ON_AUXILIARYBUS(dr) { + if (!dr->match(dev->name)) + continue; + + rc = rte_auxiliary_probe_one_driver(dr, dev); + if (rc < 0) + /* negative value is an error */ + return rc; + if (rc > 0) + /* positive value means driver doesn't support it */ + continue; + return 0; + } + return 1; +} + +/* + * Scan the content of the auxiliary bus, and call the probe() function for + * + * all registered drivers that have a matching entry in its id_table + * for discovered devices. + */ +static int +auxiliary_probe(void) +{ + struct rte_auxiliary_device *dev = NULL; + size_t probed = 0, failed = 0; + int ret = 0; + + FOREACH_DEVICE_ON_AUXILIARYBUS(dev) { + probed++; + + ret = auxiliary_probe_all_drivers(dev); + if (ret < 0) { + if (ret != -EEXIST) { + AUXILIAR_LOG(ERR, "Requested device %s cannot be used\n", + dev->name); + rte_errno = errno; + failed++; + } + ret = 0; + } + } + + return (probed && probed == failed) ? -1 : 0; +} + +static int +auxiliary_parse(const char *name, void *addr) +{ + RTE_SET_USED(addr); + return auxiliary_exists(name) ? 0 : -1; +} + +/* register a driver */ +void +rte_auxiliary_register(struct rte_auxiliary_driver *driver) +{ + TAILQ_INSERT_TAIL(&auxiliary_bus.driver_list, driver, next); + driver->bus = &auxiliary_bus; +} + +/* unregister a driver */ +void +rte_auxiliary_unregister(struct rte_auxiliary_driver *driver) +{ + TAILQ_REMOVE(&auxiliary_bus.driver_list, driver, next); + driver->bus = NULL; +} + +/* Add a device to auxiliary bus */ +void +auxiliary_add_device(struct rte_auxiliary_device *auxiliary_dev) +{ + TAILQ_INSERT_TAIL(&auxiliary_bus.device_list, auxiliary_dev, next); +} + +/* Insert a device into a predefined position in auxiliary bus */ +void +auxiliary_insert_device(struct rte_auxiliary_device *exist_auxiliary_dev, + struct rte_auxiliary_device *new_auxiliary_dev) +{ + TAILQ_INSERT_BEFORE(exist_auxiliary_dev, new_auxiliary_dev, next); +} + +/* Remove a device from auxiliary bus */ +static void +rte_auxiliary_remove_device(struct rte_auxiliary_device *auxiliary_dev) +{ + TAILQ_REMOVE(&auxiliary_bus.device_list, auxiliary_dev, next); +} + +static struct rte_device * +auxiliary_find_device(const struct rte_device *start, rte_dev_cmp_t cmp, + const void *data) +{ + const struct rte_auxiliary_device *pstart; + struct rte_auxiliary_device *adev; + + if (start != NULL) { + pstart = RTE_DEV_TO_AUXILIARY_CONST(start); + adev = TAILQ_NEXT(pstart, next); + } else { + adev = TAILQ_FIRST(&auxiliary_bus.device_list); + } + while (adev != NULL) { + if (cmp(&adev->device, data) == 0) + return &adev->device; + adev = TAILQ_NEXT(adev, next); + } + return NULL; +} + +static int +auxiliary_plug(struct rte_device *dev) +{ + return auxiliary_probe_all_drivers(RTE_DEV_TO_AUXILIARY(dev)); +} + +static int +auxiliary_unplug(struct rte_device *dev) +{ + struct rte_auxiliary_device *adev; + int ret; + + adev = RTE_DEV_TO_AUXILIARY(dev); + ret = rte_auxiliary_detach_dev(adev); + if (ret == 0) { + rte_auxiliary_remove_device(adev); + rte_devargs_remove(dev->devargs); + free(adev); + } + return ret; +} + +static int +auxiliary_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len) +{ + struct rte_auxiliary_device *adev = RTE_DEV_TO_AUXILIARY(dev); + + if (!adev || !adev->driver) { + rte_errno = EINVAL; + return -1; + } + if (adev->driver->dma_map) + return adev->driver->dma_map(adev, addr, iova, len); + rte_errno = ENOTSUP; + return -1; +} + +static int +auxiliary_dma_unmap(struct rte_device *dev, void *addr, uint64_t iova, + size_t len) +{ + struct rte_auxiliary_device *adev = RTE_DEV_TO_AUXILIARY(dev); + + if (!adev || !adev->driver) { + rte_errno = EINVAL; + return -1; + } + if (adev->driver->dma_unmap) + return adev->driver->dma_unmap(adev, addr, iova, len); + rte_errno = ENOTSUP; + return -1; +} + +bool +auxiliary_ignore_device(const char *name) +{ + struct rte_devargs *devargs = auxiliary_devargs_lookup(name); + + switch (auxiliary_bus.bus.conf.scan_mode) { + case RTE_BUS_SCAN_ALLOWLIST: + if (devargs && devargs->policy == RTE_DEV_ALLOWED) + return false; + break; + case RTE_BUS_SCAN_UNDEFINED: + case RTE_BUS_SCAN_BLOCKLIST: + if (devargs == NULL || devargs->policy != RTE_DEV_BLOCKED) + return false; + break; + } + return true; +} + +static enum rte_iova_mode +auxiliary_get_iommu_class(void) +{ + const struct rte_auxiliary_driver *drv; + + FOREACH_DRIVER_ON_AUXILIARYBUS(drv) { + if (drv->drv_flags & RTE_AUXILIARY_DRV_NEED_IOVA_AS_VA) + return RTE_IOVA_VA; + } + + return RTE_IOVA_DC; +} + +struct rte_auxiliary_bus auxiliary_bus = { + .bus = { + .scan = auxiliary_scan, + .probe = auxiliary_probe, + .find_device = auxiliary_find_device, + .plug = auxiliary_plug, + .unplug = auxiliary_unplug, + .parse = auxiliary_parse, + .dma_map = auxiliary_dma_map, + .dma_unmap = auxiliary_dma_unmap, + .get_iommu_class = auxiliary_get_iommu_class, + .dev_iterate = auxiliary_dev_iterate, + }, + .device_list = TAILQ_HEAD_INITIALIZER(auxiliary_bus.device_list), + .driver_list = TAILQ_HEAD_INITIALIZER(auxiliary_bus.driver_list), +}; + +RTE_REGISTER_BUS(auxiliary, auxiliary_bus.bus); +RTE_LOG_REGISTER(auxiliary_logtype_bus, bus.auxiliary, NOTICE); diff --git a/drivers/bus/auxiliary/auxiliary_params.c b/drivers/bus/auxiliary/auxiliary_params.c new file mode 100644 index 0000000000..0e61020f3d --- /dev/null +++ b/drivers/bus/auxiliary/auxiliary_params.c @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Mellanox Technologies, Ltd + */ + +#include + +#include +#include +#include +#include + +#include "private.h" +#include "rte_bus_auxiliary.h" + +enum auxiliary_params { + RTE_AUXILIARY_PARAM_NAME, +}; + +static const char * const auxiliary_params_keys[] = { + [RTE_AUXILIARY_PARAM_NAME] = "name", +}; + +static int +auxiliary_dev_match(const struct rte_device *dev, + const void *_kvlist) +{ + int ret; + const struct rte_kvargs *kvlist = _kvlist; + + ret = rte_kvargs_process(kvlist, + auxiliary_params_keys[RTE_AUXILIARY_PARAM_NAME], + rte_kvargs_strcmp, (void *)(uintptr_t)dev->name); + + return ret != 0 ? -1 : 0; +} + +void * +auxiliary_dev_iterate(const void *start, + const char *str, + const struct rte_dev_iterator *it __rte_unused) +{ + rte_bus_find_device_t find_device; + struct rte_kvargs *kvargs = NULL; + struct rte_device *dev; + + if (str != NULL) { + kvargs = rte_kvargs_parse(str, auxiliary_params_keys); + if (kvargs == NULL) { + RTE_LOG(ERR, EAL, "cannot parse argument list\n"); + rte_errno = EINVAL; + return NULL; + } + } + find_device = auxiliary_bus.bus.find_device; + dev = find_device(start, auxiliary_dev_match, kvargs); + rte_kvargs_free(kvargs); + return dev; +} diff --git a/drivers/bus/auxiliary/linux/auxiliary.c b/drivers/bus/auxiliary/linux/auxiliary.c new file mode 100644 index 0000000000..7852e67b8c --- /dev/null +++ b/drivers/bus/auxiliary/linux/auxiliary.c @@ -0,0 +1,144 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Mellanox Technologies, Ltd + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../rte_bus_auxiliary.h" +#include "../private.h" + + +/** + * @file + * Linux auxiliary probing. + */ + +/* Scan one auxiliary sysfs entry, and fill the devices list from it. */ +static int +auxiliary_scan_one(const char *dirname, const char *name) +{ + struct rte_auxiliary_device *dev; + struct rte_auxiliary_device *dev2; + char filename[PATH_MAX]; + unsigned long tmp; + int ret; + + dev = malloc(sizeof(*dev)); + if (dev == NULL) + return -1; + + memset(dev, 0, sizeof(*dev)); + dev->device.bus = &auxiliary_bus.bus; + strlcpy(dev->name, name, sizeof(dev->name)); + + /* Get numa node, default to 0 if not present */ + snprintf(filename, sizeof(filename), "%s/%s/numa_node", + dirname, name); + if (access(filename, F_OK) != -1) { + if (eal_parse_sysfs_value(filename, &tmp) == 0) + dev->device.numa_node = tmp; + else + dev->device.numa_node = -1; + } else { + dev->device.numa_node = 0; + } + + auxiliary_on_scan(dev); + + /* Device is valid, add in list (sorted) */ + TAILQ_FOREACH(dev2, &auxiliary_bus.device_list, next) { + ret = strcmp(dev->name, dev2->name); + if (ret > 0) + continue; + if (ret < 0) { + auxiliary_insert_device(dev2, dev); + } else { /* already registered */ + if (rte_dev_is_probed(&dev2->device) && + dev2->device.devargs != dev->device.devargs) { + /* To probe device with new devargs. */ + rte_devargs_remove(dev2->device.devargs); + auxiliary_on_scan(dev2); + } + free(dev); + } + return 0; + } + auxiliary_add_device(dev); + return 0; +} + +/* + * Test whether the auxiliary device exist + */ +bool +auxiliary_exists(const char *name) +{ + DIR *dir; + char dirname[PATH_MAX]; + + snprintf(dirname, sizeof(dirname), "%s/%s", + rte_auxiliary_get_sysfs_path(), name); + dir = opendir(rte_auxiliary_get_sysfs_path()); + if (dir == NULL) + return true; + closedir(dir); + return false; +} + +/* + * Scan the content of the auxiliary bus, and the devices in the devices + * list + */ +int +auxiliary_scan(void) +{ + struct dirent *e; + DIR *dir; + char dirname[PATH_MAX]; + struct rte_auxiliary_driver *drv; + + dir = opendir(rte_auxiliary_get_sysfs_path()); + if (dir == NULL) { + AUXILIAR_LOG(ERR, "%s(): opendir failed: %s\n", + __func__, strerror(errno)); + return -1; + } + + while ((e = readdir(dir)) != NULL) { + if (e->d_name[0] == '.') + continue; + + if (auxiliary_ignore_device(e->d_name)) + continue; + + snprintf(dirname, sizeof(dirname), "%s/%s", + rte_auxiliary_get_sysfs_path(), e->d_name); + + /* Ignore if no driver can handle. */ + FOREACH_DRIVER_ON_AUXILIARYBUS(drv) { + if (drv->match(e->d_name)) + break; + } + if (drv == NULL) + continue; + + if (auxiliary_scan_one(dirname, e->d_name) < 0) + goto error; + } + closedir(dir); + return 0; + +error: + closedir(dir); + return -1; +} + diff --git a/drivers/bus/auxiliary/meson.build b/drivers/bus/auxiliary/meson.build new file mode 100644 index 0000000000..0859620ed3 --- /dev/null +++ b/drivers/bus/auxiliary/meson.build @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2021 Mellanox Technologies, Ltd + +if is_linux + headers = files('rte_bus_auxiliary.h') + sources = files('auxiliary_common.c', + 'auxiliary_params.c', + 'linux/auxiliary.c') + includes += include_directories('linux') + deps += ['kvargs'] +endif +if not is_linux + build = false + reason = 'only supported on Linux' + subdir_done() +endif + diff --git a/drivers/bus/auxiliary/private.h b/drivers/bus/auxiliary/private.h new file mode 100644 index 0000000000..b55827c74f --- /dev/null +++ b/drivers/bus/auxiliary/private.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Mellanox Technologies, Ltd + */ + +#ifndef _AUXILIARY_PRIVATE_H_ +#define _AUXILIARY_PRIVATE_H_ + +#include +#include +#include "rte_bus_auxiliary.h" + + +extern struct rte_auxiliary_bus auxiliary_bus; +extern int auxiliary_logtype_bus; + +#define AUXILIAR_LOG(level, fmt, args...) \ + rte_log(RTE_LOG_ ## level, auxiliary_logtype_bus, "%s(): " fmt "\n", \ + __func__, ##args) + +/* Auxiliary bus iterators */ +#define FOREACH_DEVICE_ON_AUXILIARYBUS(p) \ + TAILQ_FOREACH(p, &(auxiliary_bus.device_list), next) + +#define FOREACH_DRIVER_ON_AUXILIARYBUS(p) \ + TAILQ_FOREACH(p, &(auxiliary_bus.driver_list), next) + +/** + * Test whether the auxiliary device exist + * + * @param name + * Auxiliary device name + * @return + * true on exists, false otherwise + */ +bool auxiliary_exists(const char *name); + +/** + * Scan the content of the auxiliary bus, and the devices in the devices + * list + * + * @return + * 0 on success, negative on error + */ +int auxiliary_scan(void); + +/** + * Setup or update device when being scanned. + */ +void auxiliary_on_scan(struct rte_auxiliary_device *dev); + +/** + * Validate whether a device with given auxiliary device should be ignored + * or not. + * + * @param name + * Auxiliary name of device to be validated + * @return + * true: if device is to be ignored, + * false: if device is to be scanned, + */ +bool auxiliary_ignore_device(const char *name); + +/** + * Add an auxiliary device to the auxiliary bus (append to auxiliary Device + * list). This function also updates the bus references of the auxiliary + * Device (and the generic device object embedded within. + * + * @param auxiliary_dev + * AUXILIARY device to add + * @return void + */ +void auxiliary_add_device(struct rte_auxiliary_device *auxiliary_dev); + +/** + * Insert an auxiliary device in the auxiliary bus at a particular location + * in the device list. It also updates the auxiliary bus reference of the + * new devices to be inserted. + * + * @param exist_auxiliary_dev + * Existing auxiliary device in auxiliary bus + * @param new_auxiliary_dev + * AUXILIARY device to be added before exist_auxiliary_dev + * @return void + */ +void auxiliary_insert_device( + struct rte_auxiliary_device *exist_auxiliary_dev, + struct rte_auxiliary_device *new_auxiliary_dev); + +/** + * Match the auxiliary Driver and Device by driver function + * + * @param auxiliary_drv + * auxiliary driver + * @param auxiliary_dev + * auxiliary device to match against the driver + * @return + * the driver can handle the device + */ +bool auxiliary_match(const struct rte_auxiliary_driver *auxiliary_drv, + const struct rte_auxiliary_device *auxiliary_dev); + +/** + * Iterate over internal devices, matching any device against the provided + * string. + * + * @param start + * Iteration starting point. + * @param str + * Device string to match against. + * @param it + * (unused) iterator structure. + * @return + * A pointer to the next matching device if any. + * NULL otherwise. + */ +void *auxiliary_dev_iterate(const void *start, const char *str, + const struct rte_dev_iterator *it); + +#endif /* _AUXILIARY_PRIVATE_H_ */ diff --git a/drivers/bus/auxiliary/rte_bus_auxiliary.h b/drivers/bus/auxiliary/rte_bus_auxiliary.h new file mode 100644 index 0000000000..b778a00749 --- /dev/null +++ b/drivers/bus/auxiliary/rte_bus_auxiliary.h @@ -0,0 +1,193 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2021 Mellanox Technologies, Ltd + */ + +#ifndef _RTE_BUS_AUXILIARY_H_ +#define _RTE_BUS_AUXILIARY_H_ + +/** + * @file + * + * RTE Auxiliary Bus Interface. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +/* Forward declarations */ +struct rte_auxiliary_driver; +struct rte_auxiliary_bus; +struct rte_auxiliary_device; + +/** + * Match function for the driver to decide if device can be handled. + */ +typedef bool(auxiliary_match_t) (const char *); + +/** + * Initialization function for the driver called during auxiliary probing. + */ +typedef int(auxiliary_probe_t) (struct rte_auxiliary_driver*, + struct rte_auxiliary_device*); + +/** + * Uninitialization function for the driver called during hotplugging. + */ +typedef int (auxiliary_remove_t)(struct rte_auxiliary_device *); + +/** + * Driver-specific DMA mapping. After a successful call the device + * will be able to read/write from/to this segment. + * + * @param dev + * Pointer to the auxiliary device. + * @param addr + * Starting virtual address of memory to be mapped. + * @param iova + * Starting IOVA address of memory to be mapped. + * @param len + * Length of memory segment being mapped. + * @return + * - 0 On success. + * - Negative value and rte_errno is set otherwise. + */ +typedef int (auxiliary_dma_map_t)(struct rte_auxiliary_device *dev, void *addr, + uint64_t iova, size_t len); + +/** + * Driver-specific DMA un-mapping. After a successful call the device + * will not be able to read/write from/to this segment. + * + * @param dev + * Pointer to the auxiliary device. + * @param addr + * Starting virtual address of memory to be unmapped. + * @param iova + * Starting IOVA address of memory to be unmapped. + * @param len + * Length of memory segment being unmapped. + * @return + * - 0 On success. + * - Negative value and rte_errno is set otherwise. + */ +typedef int (auxiliary_dma_unmap_t)(struct rte_auxiliary_device *dev, + void *addr, uint64_t iova, size_t len); + +/** + * A structure describing an auxiliary device. + */ +struct rte_auxiliary_device { + TAILQ_ENTRY(rte_auxiliary_device) next; /**< Next probed device. */ + char name[RTE_DEV_NAME_MAX_LEN + 1]; /**< ASCII device name */ + struct rte_device device; /**< Inherit core device */ + struct rte_intr_handle intr_handle; /**< Interrupt handle */ + struct rte_auxiliary_driver *driver; /**< driver used in probing */ +}; + +/** List of auxiliary devices */ +TAILQ_HEAD(rte_auxiliary_device_list, rte_auxiliary_device); +/** List of auxiliary drivers */ +TAILQ_HEAD(rte_auxiliary_driver_list, rte_auxiliary_driver); + +/** + * Structure describing the auxiliary bus + */ +struct rte_auxiliary_bus { + struct rte_bus bus; /**< Inherit the generic class */ + struct rte_auxiliary_device_list device_list; /**< List of devices */ + struct rte_auxiliary_driver_list driver_list; /**< List of drivers */ +}; + +/** + * A structure describing an auxiliary driver. + */ +struct rte_auxiliary_driver { + TAILQ_ENTRY(rte_auxiliary_driver) next; /**< Next in list. */ + struct rte_driver driver; /**< Inherit core driver. */ + struct rte_auxiliary_bus *bus; /**< Auxiliary bus reference. */ + auxiliary_match_t *match; /**< Device match function. */ + auxiliary_probe_t *probe; /**< Device Probe function. */ + auxiliary_remove_t *remove; /**< Device Remove function. */ + auxiliary_dma_map_t *dma_map; /**< Device dma map function. */ + auxiliary_dma_unmap_t *dma_unmap; /**< Device dma unmap function. */ + uint32_t drv_flags; /**< Flags RTE_auxiliary_DRV_*. */ +}; + +/** + * @internal + * Helper macro for drivers that need to convert to struct rte_auxiliary_device. + */ +#define RTE_DEV_TO_AUXILIARY(ptr) \ + container_of(ptr, struct rte_auxiliary_device, device) + +#define RTE_DEV_TO_AUXILIARY_CONST(ptr) \ + container_of(ptr, const struct rte_auxiliary_device, device) + +#define RTE_ETH_DEV_TO_AUXILIARY(eth_dev) \ + RTE_DEV_TO_AUXILIARY((eth_dev)->device) + + +/** Device already probed can be probed again to check for new ports. */ +#define RTE_AUXILIARY_DRV_PROBE_AGAIN 0x0001 +/** Device driver needs IOVA as VA and cannot work with IOVA as PA */ +#define RTE_AUXILIARY_DRV_NEED_IOVA_AS_VA 0x002 + +/** + * Get sysfs pathname of auxiliary devices directory + * + * @return + * Pathname of auxiliary devices directory + */ +__rte_experimental +const char *rte_auxiliary_get_sysfs_path(void); + +/** + * Register an auxiliary driver. + * + * @param driver + * A pointer to a rte_auxiliary_driver structure describing the driver + * to be registered. + */ +__rte_experimental +void rte_auxiliary_register(struct rte_auxiliary_driver *driver); + +/** Helper for auxiliary device registration from driver instance */ +#define RTE_PMD_REGISTER_AUXILIARY(nm, auxiliary_drv) \ + RTE_INIT(auxiliaryinitfn_##nm) \ + { \ + (auxiliary_drv).driver.name = RTE_STR(nm); \ + rte_auxiliary_register(&auxiliary_drv); \ + } \ + RTE_PMD_EXPORT_NAME(nm, __COUNTER__) + +/** + * Unregister an auxiliary driver. + * + * @param driver + * A pointer to a rte_auxiliary_driver structure describing the driver + * to be unregistered. + */ +__rte_experimental +void rte_auxiliary_unregister(struct rte_auxiliary_driver *driver); + +#ifdef __cplusplus +} +#endif + +#endif /* _RTE_BUS_AUXILIARY_H_ */ diff --git a/drivers/bus/auxiliary/version.map b/drivers/bus/auxiliary/version.map new file mode 100644 index 0000000000..e012955b8f --- /dev/null +++ b/drivers/bus/auxiliary/version.map @@ -0,0 +1,11 @@ +DPDK_21 { + local: *; +}; + +EXPERIMENTAL { + global: + + rte_auxiliary_get_sysfs_path; + rte_auxiliary_register; + rte_auxiliary_unregister; +}; diff --git a/drivers/bus/meson.build b/drivers/bus/meson.build index 2e7727af08..d581003f7d 100644 --- a/drivers/bus/meson.build +++ b/drivers/bus/meson.build @@ -1,5 +1,5 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright(c) 2017 Intel Corporation -drivers = ['dpaa', 'fslmc', 'ifpga', 'pci', 'vdev', 'vmbus'] +drivers = ['auxiliary', 'dpaa', 'fslmc', 'ifpga', 'pci', 'vdev', 'vmbus'] std_deps = ['eal'] -- 2.25.1