numam-dpdk/drivers/bus/auxiliary/auxiliary_common.c
Harman Kalra d61138d4f0 drivers: remove direct access to interrupt handle
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>
2021-10-25 21:20:12 +02:00

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);