d61138d4f0
Removing direct access to interrupt handle structure fields, rather use respective get set APIs for the same. Making changes to all the drivers access the interrupt handle fields. Signed-off-by: Harman Kalra <hkalra@marvell.com> Acked-by: Hyong Youb Kim <hyonkim@cisco.com> Signed-off-by: David Marchand <david.marchand@redhat.com> Tested-by: Raslan Darawsheh <rasland@nvidia.com>
425 lines
9.5 KiB
C
425 lines
9.5 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright (c) 2021 NVIDIA Corporation & Affiliates
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <inttypes.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <sys/queue.h>
|
|
#include <rte_errno.h>
|
|
#include <rte_interrupts.h>
|
|
#include <rte_log.h>
|
|
#include <rte_bus.h>
|
|
#include <rte_per_lcore.h>
|
|
#include <rte_memory.h>
|
|
#include <rte_eal.h>
|
|
#include <rte_eal_paging.h>
|
|
#include <rte_lcore.h>
|
|
#include <rte_string_fns.h>
|
|
#include <rte_common.h>
|
|
#include <rte_devargs.h>
|
|
|
|
#include "private.h"
|
|
#include "rte_bus_auxiliary.h"
|
|
|
|
static struct rte_devargs *
|
|
auxiliary_devargs_lookup(const char *name)
|
|
{
|
|
struct rte_devargs *devargs;
|
|
|
|
RTE_EAL_DEVARGS_FOREACH(RTE_BUS_AUXILIARY_NAME, devargs) {
|
|
if (strcmp(devargs->name, name) == 0)
|
|
return devargs;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Test whether the auxiliary device exist.
|
|
*
|
|
* Stub for OS not supporting auxiliary bus.
|
|
*/
|
|
__rte_weak bool
|
|
auxiliary_dev_exists(const char *name)
|
|
{
|
|
RTE_SET_USED(name);
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* Scan the devices in the auxiliary bus.
|
|
*
|
|
* Stub for OS not supporting auxiliary bus.
|
|
*/
|
|
__rte_weak int
|
|
auxiliary_scan(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Update a device's devargs being scanned.
|
|
*/
|
|
void
|
|
auxiliary_on_scan(struct rte_auxiliary_device *aux_dev)
|
|
{
|
|
aux_dev->device.devargs = auxiliary_devargs_lookup(aux_dev->name);
|
|
}
|
|
|
|
/*
|
|
* Match the auxiliary driver and device using driver function.
|
|
*/
|
|
bool
|
|
auxiliary_match(const struct rte_auxiliary_driver *aux_drv,
|
|
const struct rte_auxiliary_device *aux_dev)
|
|
{
|
|
if (aux_drv->match == NULL)
|
|
return false;
|
|
return aux_drv->match(aux_dev->name);
|
|
}
|
|
|
|
/*
|
|
* Call the probe() function of the driver.
|
|
*/
|
|
static int
|
|
rte_auxiliary_probe_one_driver(struct rte_auxiliary_driver *drv,
|
|
struct rte_auxiliary_device *dev)
|
|
{
|
|
enum rte_iova_mode iova_mode;
|
|
int ret;
|
|
|
|
if (drv == NULL || dev == NULL)
|
|
return -EINVAL;
|
|
|
|
/* Check if driver supports it. */
|
|
if (!auxiliary_match(drv, dev))
|
|
/* Match of device and driver failed */
|
|
return 1;
|
|
|
|
/* No initialization when marked as blocked, return without error. */
|
|
if (dev->device.devargs != NULL &&
|
|
dev->device.devargs->policy == RTE_DEV_BLOCKED) {
|
|
AUXILIARY_LOG(INFO, "Device is blocked, not initializing");
|
|
return -1;
|
|
}
|
|
|
|
if (dev->device.numa_node < 0) {
|
|
if (rte_socket_count() > 1)
|
|
AUXILIARY_LOG(INFO, "Device %s is not NUMA-aware, defaulting socket to 0",
|
|
dev->name);
|
|
dev->device.numa_node = 0;
|
|
}
|
|
|
|
iova_mode = rte_eal_iova_mode();
|
|
if ((drv->drv_flags & RTE_AUXILIARY_DRV_NEED_IOVA_AS_VA) > 0 &&
|
|
iova_mode != RTE_IOVA_VA) {
|
|
AUXILIARY_LOG(ERR, "Driver %s expecting VA IOVA mode but current mode is PA, not initializing",
|
|
drv->driver.name);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Allocate interrupt instance */
|
|
dev->intr_handle =
|
|
rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
|
|
if (dev->intr_handle == NULL) {
|
|
AUXILIARY_LOG(ERR, "Could not allocate interrupt instance for device %s",
|
|
dev->name);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
dev->driver = drv;
|
|
|
|
AUXILIARY_LOG(INFO, "Probe auxiliary driver: %s device: %s (NUMA node %i)",
|
|
drv->driver.name, dev->name, dev->device.numa_node);
|
|
ret = drv->probe(drv, dev);
|
|
if (ret != 0) {
|
|
dev->driver = NULL;
|
|
rte_intr_instance_free(dev->intr_handle);
|
|
dev->intr_handle = NULL;
|
|
} else {
|
|
dev->device.driver = &drv->driver;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Call the remove() function of the driver.
|
|
*/
|
|
static int
|
|
rte_auxiliary_driver_remove_dev(struct rte_auxiliary_device *dev)
|
|
{
|
|
struct rte_auxiliary_driver *drv;
|
|
int ret = 0;
|
|
|
|
if (dev == NULL)
|
|
return -EINVAL;
|
|
|
|
drv = dev->driver;
|
|
|
|
AUXILIARY_LOG(DEBUG, "Driver %s remove auxiliary device %s on NUMA node %i",
|
|
drv->driver.name, dev->name, dev->device.numa_node);
|
|
|
|
if (drv->remove != NULL) {
|
|
ret = drv->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 drivers 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 *drv;
|
|
int rc;
|
|
|
|
if (dev == NULL)
|
|
return -EINVAL;
|
|
|
|
FOREACH_DRIVER_ON_AUXILIARY_BUS(drv) {
|
|
if (!drv->match(dev->name))
|
|
continue;
|
|
|
|
rc = rte_auxiliary_probe_one_driver(drv, 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 to try to probe 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_AUXILIARY_BUS(dev) {
|
|
probed++;
|
|
|
|
ret = auxiliary_probe_all_drivers(dev);
|
|
if (ret < 0) {
|
|
if (ret != -EEXIST) {
|
|
AUXILIARY_LOG(ERR, "Requested device %s cannot be used",
|
|
dev->name);
|
|
rte_errno = errno;
|
|
failed++;
|
|
}
|
|
ret = 0;
|
|
}
|
|
}
|
|
|
|
return (probed && probed == failed) ? -1 : 0;
|
|
}
|
|
|
|
static int
|
|
auxiliary_parse(const char *name, void *addr)
|
|
{
|
|
struct rte_auxiliary_driver *drv = NULL;
|
|
const char **out = addr;
|
|
|
|
/* Allow empty device name "auxiliary:" to bypass entire bus scan. */
|
|
if (strlen(name) == 0)
|
|
return 0;
|
|
|
|
FOREACH_DRIVER_ON_AUXILIARY_BUS(drv) {
|
|
if (drv->match(name))
|
|
break;
|
|
}
|
|
if (drv != NULL && addr != NULL)
|
|
*out = name;
|
|
return drv != NULL ? 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 *aux_dev)
|
|
{
|
|
TAILQ_INSERT_TAIL(&auxiliary_bus.device_list, aux_dev, next);
|
|
}
|
|
|
|
/* Insert a device into a predefined position in auxiliary bus */
|
|
void
|
|
auxiliary_insert_device(struct rte_auxiliary_device *exist_aux_dev,
|
|
struct rte_auxiliary_device *new_aux_dev)
|
|
{
|
|
TAILQ_INSERT_BEFORE(exist_aux_dev, new_aux_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)
|
|
{
|
|
if (!auxiliary_dev_exists(dev->name))
|
|
return -ENOENT;
|
|
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_driver_remove_dev(adev);
|
|
if (ret == 0) {
|
|
rte_auxiliary_remove_device(adev);
|
|
rte_devargs_remove(dev->devargs);
|
|
rte_intr_instance_free(adev->intr_handle);
|
|
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 *aux_dev = RTE_DEV_TO_AUXILIARY(dev);
|
|
|
|
if (dev == NULL || aux_dev->driver == NULL) {
|
|
rte_errno = EINVAL;
|
|
return -1;
|
|
}
|
|
if (aux_dev->driver->dma_map == NULL) {
|
|
rte_errno = ENOTSUP;
|
|
return -1;
|
|
}
|
|
return aux_dev->driver->dma_map(aux_dev, addr, iova, len);
|
|
}
|
|
|
|
static int
|
|
auxiliary_dma_unmap(struct rte_device *dev, void *addr, uint64_t iova,
|
|
size_t len)
|
|
{
|
|
struct rte_auxiliary_device *aux_dev = RTE_DEV_TO_AUXILIARY(dev);
|
|
|
|
if (dev == NULL || aux_dev->driver == NULL) {
|
|
rte_errno = EINVAL;
|
|
return -1;
|
|
}
|
|
if (aux_dev->driver->dma_unmap == NULL) {
|
|
rte_errno = ENOTSUP;
|
|
return -1;
|
|
}
|
|
return aux_dev->driver->dma_unmap(aux_dev, addr, iova, len);
|
|
}
|
|
|
|
bool
|
|
auxiliary_is_ignored_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_AUXILIARY_BUS(drv) {
|
|
if ((drv->drv_flags & RTE_AUXILIARY_DRV_NEED_IOVA_AS_VA) > 0)
|
|
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_DEFAULT(auxiliary_bus_logtype, NOTICE);
|