numam-dpdk/lib/gpudev/gpudev.c
Elena Agostini 1fd3de64ff gpudev: fix page alignment in communication list
Memory allocated for CPU mapping the status flag
in the communication list should be aligned to the
GPU page size, which can be different of CPU page alignment.

The GPU page size is added to the GPU info,
and is used when creating a communication list.

Fixes: 9b8cae4d99 ("gpudev: use CPU mapping in communication list")

Signed-off-by: Elena Agostini <eagostini@nvidia.com>
2022-03-09 00:14:55 +01:00

1092 lines
23 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) 2021 NVIDIA Corporation & Affiliates
*/
#include <rte_eal.h>
#include <rte_tailq.h>
#include <rte_string_fns.h>
#include <rte_memzone.h>
#include <rte_malloc.h>
#include <rte_errno.h>
#include <rte_log.h>
#include <rte_eal_paging.h>
#include "rte_gpudev.h"
#include "gpudev_driver.h"
/* Logging */
RTE_LOG_REGISTER_DEFAULT(gpu_logtype, NOTICE);
#define GPU_LOG(level, ...) \
rte_log(RTE_LOG_ ## level, gpu_logtype, RTE_FMT("gpu: " \
RTE_FMT_HEAD(__VA_ARGS__, ) "\n", RTE_FMT_TAIL(__VA_ARGS__, )))
/* Set any driver error as EPERM */
#define GPU_DRV_RET(function) \
((function != 0) ? -(rte_errno = EPERM) : (rte_errno = 0))
/* Array of devices */
static struct rte_gpu *gpus;
/* Number of currently valid devices */
static int16_t gpu_max;
/* Number of currently valid devices */
static int16_t gpu_count;
/* Shared memory between processes. */
static const char *GPU_MEMZONE = "rte_gpu_shared";
static struct {
__extension__ struct rte_gpu_mpshared gpus[0];
} *gpu_shared_mem;
/* Event callback object */
struct rte_gpu_callback {
TAILQ_ENTRY(rte_gpu_callback) next;
rte_gpu_callback_t *function;
void *user_data;
enum rte_gpu_event event;
};
static rte_rwlock_t gpu_callback_lock = RTE_RWLOCK_INITIALIZER;
static void gpu_free_callbacks(struct rte_gpu *dev);
int
rte_gpu_init(size_t dev_max)
{
if (dev_max == 0 || dev_max > INT16_MAX) {
GPU_LOG(ERR, "invalid array size");
rte_errno = EINVAL;
return -rte_errno;
}
/* No lock, it must be called before or during first probing. */
if (gpus != NULL) {
GPU_LOG(ERR, "already initialized");
rte_errno = EBUSY;
return -rte_errno;
}
gpus = calloc(dev_max, sizeof(struct rte_gpu));
if (gpus == NULL) {
GPU_LOG(ERR, "cannot initialize library");
rte_errno = ENOMEM;
return -rte_errno;
}
gpu_max = dev_max;
return 0;
}
uint16_t
rte_gpu_count_avail(void)
{
return gpu_count;
}
bool
rte_gpu_is_valid(int16_t dev_id)
{
if (dev_id >= 0 && dev_id < gpu_max &&
gpus[dev_id].process_state == RTE_GPU_STATE_INITIALIZED)
return true;
return false;
}
static bool
gpu_match_parent(int16_t dev_id, int16_t parent)
{
if (parent == RTE_GPU_ID_ANY)
return true;
return gpus[dev_id].mpshared->info.parent == parent;
}
int16_t
rte_gpu_find_next(int16_t dev_id, int16_t parent)
{
if (dev_id < 0)
dev_id = 0;
while (dev_id < gpu_max &&
(gpus[dev_id].process_state == RTE_GPU_STATE_UNUSED ||
!gpu_match_parent(dev_id, parent)))
dev_id++;
if (dev_id >= gpu_max)
return RTE_GPU_ID_NONE;
return dev_id;
}
static int16_t
gpu_find_free_id(void)
{
int16_t dev_id;
for (dev_id = 0; dev_id < gpu_max; dev_id++) {
if (gpus[dev_id].process_state == RTE_GPU_STATE_UNUSED)
return dev_id;
}
return RTE_GPU_ID_NONE;
}
static struct rte_gpu *
gpu_get_by_id(int16_t dev_id)
{
if (!rte_gpu_is_valid(dev_id))
return NULL;
return &gpus[dev_id];
}
struct rte_gpu *
rte_gpu_get_by_name(const char *name)
{
int16_t dev_id;
struct rte_gpu *dev;
if (name == NULL) {
rte_errno = EINVAL;
return NULL;
}
RTE_GPU_FOREACH(dev_id) {
dev = &gpus[dev_id];
if (strncmp(name, dev->mpshared->name, RTE_DEV_NAME_MAX_LEN) == 0)
return dev;
}
return NULL;
}
static int
gpu_shared_mem_init(void)
{
const struct rte_memzone *memzone;
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
memzone = rte_memzone_reserve(GPU_MEMZONE,
sizeof(*gpu_shared_mem) +
sizeof(*gpu_shared_mem->gpus) * gpu_max,
SOCKET_ID_ANY, 0);
} else {
memzone = rte_memzone_lookup(GPU_MEMZONE);
}
if (memzone == NULL) {
GPU_LOG(ERR, "cannot initialize shared memory");
rte_errno = ENOMEM;
return -rte_errno;
}
gpu_shared_mem = memzone->addr;
return 0;
}
struct rte_gpu *
rte_gpu_allocate(const char *name)
{
int16_t dev_id;
struct rte_gpu *dev;
if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
GPU_LOG(ERR, "only primary process can allocate device");
rte_errno = EPERM;
return NULL;
}
if (name == NULL) {
GPU_LOG(ERR, "allocate device without a name");
rte_errno = EINVAL;
return NULL;
}
/* implicit initialization of library before adding first device */
if (gpus == NULL && rte_gpu_init(RTE_GPU_DEFAULT_MAX) < 0)
return NULL;
/* initialize shared memory before adding first device */
if (gpu_shared_mem == NULL && gpu_shared_mem_init() < 0)
return NULL;
if (rte_gpu_get_by_name(name) != NULL) {
GPU_LOG(ERR, "device with name %s already exists", name);
rte_errno = EEXIST;
return NULL;
}
dev_id = gpu_find_free_id();
if (dev_id == RTE_GPU_ID_NONE) {
GPU_LOG(ERR, "reached maximum number of devices");
rte_errno = ENOENT;
return NULL;
}
dev = &gpus[dev_id];
memset(dev, 0, sizeof(*dev));
dev->mpshared = &gpu_shared_mem->gpus[dev_id];
memset(dev->mpshared, 0, sizeof(*dev->mpshared));
if (rte_strscpy(dev->mpshared->name, name, RTE_DEV_NAME_MAX_LEN) < 0) {
GPU_LOG(ERR, "device name too long: %s", name);
rte_errno = ENAMETOOLONG;
return NULL;
}
dev->mpshared->info.name = dev->mpshared->name;
dev->mpshared->info.dev_id = dev_id;
dev->mpshared->info.numa_node = -1;
dev->mpshared->info.parent = RTE_GPU_ID_NONE;
TAILQ_INIT(&dev->callbacks);
__atomic_fetch_add(&dev->mpshared->process_refcnt, 1, __ATOMIC_RELAXED);
gpu_count++;
GPU_LOG(DEBUG, "new device %s (id %d) of total %d",
name, dev_id, gpu_count);
return dev;
}
struct rte_gpu *
rte_gpu_attach(const char *name)
{
int16_t dev_id;
struct rte_gpu *dev;
struct rte_gpu_mpshared *shared_dev;
if (rte_eal_process_type() != RTE_PROC_SECONDARY) {
GPU_LOG(ERR, "only secondary process can attach device");
rte_errno = EPERM;
return NULL;
}
if (name == NULL) {
GPU_LOG(ERR, "attach device without a name");
rte_errno = EINVAL;
return NULL;
}
/* implicit initialization of library before adding first device */
if (gpus == NULL && rte_gpu_init(RTE_GPU_DEFAULT_MAX) < 0)
return NULL;
/* initialize shared memory before adding first device */
if (gpu_shared_mem == NULL && gpu_shared_mem_init() < 0)
return NULL;
for (dev_id = 0; dev_id < gpu_max; dev_id++) {
shared_dev = &gpu_shared_mem->gpus[dev_id];
if (strncmp(name, shared_dev->name, RTE_DEV_NAME_MAX_LEN) == 0)
break;
}
if (dev_id >= gpu_max) {
GPU_LOG(ERR, "device with name %s not found", name);
rte_errno = ENOENT;
return NULL;
}
dev = &gpus[dev_id];
memset(dev, 0, sizeof(*dev));
TAILQ_INIT(&dev->callbacks);
dev->mpshared = shared_dev;
__atomic_fetch_add(&dev->mpshared->process_refcnt, 1, __ATOMIC_RELAXED);
gpu_count++;
GPU_LOG(DEBUG, "attached device %s (id %d) of total %d",
name, dev_id, gpu_count);
return dev;
}
int16_t
rte_gpu_add_child(const char *name, int16_t parent, uint64_t child_context)
{
struct rte_gpu *dev;
if (!rte_gpu_is_valid(parent)) {
GPU_LOG(ERR, "add child to invalid parent ID %d", parent);
rte_errno = ENODEV;
return -rte_errno;
}
dev = rte_gpu_allocate(name);
if (dev == NULL)
return -rte_errno;
dev->mpshared->info.parent = parent;
dev->mpshared->info.context = child_context;
rte_gpu_complete_new(dev);
return dev->mpshared->info.dev_id;
}
void
rte_gpu_complete_new(struct rte_gpu *dev)
{
if (dev == NULL)
return;
dev->process_state = RTE_GPU_STATE_INITIALIZED;
rte_gpu_notify(dev, RTE_GPU_EVENT_NEW);
}
int
rte_gpu_release(struct rte_gpu *dev)
{
int16_t dev_id, child;
if (dev == NULL) {
rte_errno = ENODEV;
return -rte_errno;
}
dev_id = dev->mpshared->info.dev_id;
RTE_GPU_FOREACH_CHILD(child, dev_id) {
GPU_LOG(ERR, "cannot release device %d with child %d",
dev_id, child);
rte_errno = EBUSY;
return -rte_errno;
}
GPU_LOG(DEBUG, "free device %s (id %d)",
dev->mpshared->info.name, dev->mpshared->info.dev_id);
rte_gpu_notify(dev, RTE_GPU_EVENT_DEL);
gpu_free_callbacks(dev);
dev->process_state = RTE_GPU_STATE_UNUSED;
__atomic_fetch_sub(&dev->mpshared->process_refcnt, 1, __ATOMIC_RELAXED);
gpu_count--;
return 0;
}
int
rte_gpu_close(int16_t dev_id)
{
int firsterr, binerr;
int *lasterr = &firsterr;
struct rte_gpu *dev;
dev = gpu_get_by_id(dev_id);
if (dev == NULL) {
GPU_LOG(ERR, "close invalid device ID %d", dev_id);
rte_errno = ENODEV;
return -rte_errno;
}
if (dev->ops.dev_close != NULL) {
*lasterr = GPU_DRV_RET(dev->ops.dev_close(dev));
if (*lasterr != 0)
lasterr = &binerr;
}
*lasterr = rte_gpu_release(dev);
rte_errno = -firsterr;
return firsterr;
}
int
rte_gpu_callback_register(int16_t dev_id, enum rte_gpu_event event,
rte_gpu_callback_t *function, void *user_data)
{
int16_t next_dev, last_dev;
struct rte_gpu_callback_list *callbacks;
struct rte_gpu_callback *callback;
if (!rte_gpu_is_valid(dev_id) && dev_id != RTE_GPU_ID_ANY) {
GPU_LOG(ERR, "register callback of invalid ID %d", dev_id);
rte_errno = ENODEV;
return -rte_errno;
}
if (function == NULL) {
GPU_LOG(ERR, "cannot register callback without function");
rte_errno = EINVAL;
return -rte_errno;
}
if (dev_id == RTE_GPU_ID_ANY) {
next_dev = 0;
last_dev = gpu_max - 1;
} else {
next_dev = last_dev = dev_id;
}
rte_rwlock_write_lock(&gpu_callback_lock);
do {
callbacks = &gpus[next_dev].callbacks;
/* check if not already registered */
TAILQ_FOREACH(callback, callbacks, next) {
if (callback->event == event &&
callback->function == function &&
callback->user_data == user_data) {
GPU_LOG(INFO, "callback already registered");
return 0;
}
}
callback = malloc(sizeof(*callback));
if (callback == NULL) {
GPU_LOG(ERR, "cannot allocate callback");
return -ENOMEM;
}
callback->function = function;
callback->user_data = user_data;
callback->event = event;
TAILQ_INSERT_TAIL(callbacks, callback, next);
} while (++next_dev <= last_dev);
rte_rwlock_write_unlock(&gpu_callback_lock);
return 0;
}
int
rte_gpu_callback_unregister(int16_t dev_id, enum rte_gpu_event event,
rte_gpu_callback_t *function, void *user_data)
{
int16_t next_dev, last_dev;
struct rte_gpu_callback_list *callbacks;
struct rte_gpu_callback *callback, *nextcb;
if (!rte_gpu_is_valid(dev_id) && dev_id != RTE_GPU_ID_ANY) {
GPU_LOG(ERR, "unregister callback of invalid ID %d", dev_id);
rte_errno = ENODEV;
return -rte_errno;
}
if (function == NULL) {
GPU_LOG(ERR, "cannot unregister callback without function");
rte_errno = EINVAL;
return -rte_errno;
}
if (dev_id == RTE_GPU_ID_ANY) {
next_dev = 0;
last_dev = gpu_max - 1;
} else {
next_dev = last_dev = dev_id;
}
rte_rwlock_write_lock(&gpu_callback_lock);
do {
callbacks = &gpus[next_dev].callbacks;
RTE_TAILQ_FOREACH_SAFE(callback, callbacks, next, nextcb) {
if (callback->event != event ||
callback->function != function ||
(callback->user_data != user_data &&
user_data != (void *)-1))
continue;
TAILQ_REMOVE(callbacks, callback, next);
free(callback);
}
} while (++next_dev <= last_dev);
rte_rwlock_write_unlock(&gpu_callback_lock);
return 0;
}
static void
gpu_free_callbacks(struct rte_gpu *dev)
{
struct rte_gpu_callback_list *callbacks;
struct rte_gpu_callback *callback, *nextcb;
callbacks = &dev->callbacks;
rte_rwlock_write_lock(&gpu_callback_lock);
RTE_TAILQ_FOREACH_SAFE(callback, callbacks, next, nextcb) {
TAILQ_REMOVE(callbacks, callback, next);
free(callback);
}
rte_rwlock_write_unlock(&gpu_callback_lock);
}
void
rte_gpu_notify(struct rte_gpu *dev, enum rte_gpu_event event)
{
int16_t dev_id;
struct rte_gpu_callback *callback;
dev_id = dev->mpshared->info.dev_id;
rte_rwlock_read_lock(&gpu_callback_lock);
TAILQ_FOREACH(callback, &dev->callbacks, next) {
if (callback->event != event || callback->function == NULL)
continue;
callback->function(dev_id, event, callback->user_data);
}
rte_rwlock_read_unlock(&gpu_callback_lock);
}
int
rte_gpu_info_get(int16_t dev_id, struct rte_gpu_info *info)
{
struct rte_gpu *dev;
dev = gpu_get_by_id(dev_id);
if (dev == NULL) {
GPU_LOG(ERR, "query invalid device ID %d", dev_id);
rte_errno = ENODEV;
return -rte_errno;
}
if (info == NULL) {
GPU_LOG(ERR, "query without storage");
rte_errno = EINVAL;
return -rte_errno;
}
if (dev->ops.dev_info_get == NULL) {
*info = dev->mpshared->info;
return 0;
}
return GPU_DRV_RET(dev->ops.dev_info_get(dev, info));
}
void *
rte_gpu_mem_alloc(int16_t dev_id, size_t size, unsigned int align)
{
struct rte_gpu *dev;
void *ptr;
int ret;
dev = gpu_get_by_id(dev_id);
if (dev == NULL) {
GPU_LOG(ERR, "alloc mem for invalid device ID %d", dev_id);
rte_errno = ENODEV;
return NULL;
}
if (dev->ops.mem_alloc == NULL) {
GPU_LOG(ERR, "mem allocation not supported");
rte_errno = ENOTSUP;
return NULL;
}
if (size == 0) /* dry-run */
return NULL;
if (align && !rte_is_power_of_2(align)) {
GPU_LOG(ERR, "requested alignment is not a power of two %u", align);
rte_errno = EINVAL;
return NULL;
}
ret = dev->ops.mem_alloc(dev, size, align, &ptr);
switch (ret) {
case 0:
return ptr;
case -ENOMEM:
case -E2BIG:
rte_errno = -ret;
return NULL;
default:
rte_errno = -EPERM;
return NULL;
}
}
int
rte_gpu_mem_free(int16_t dev_id, void *ptr)
{
struct rte_gpu *dev;
dev = gpu_get_by_id(dev_id);
if (dev == NULL) {
GPU_LOG(ERR, "free mem for invalid device ID %d", dev_id);
rte_errno = ENODEV;
return -rte_errno;
}
if (dev->ops.mem_free == NULL) {
rte_errno = ENOTSUP;
return -rte_errno;
}
if (ptr == NULL) /* dry-run */
return 0;
return GPU_DRV_RET(dev->ops.mem_free(dev, ptr));
}
int
rte_gpu_mem_register(int16_t dev_id, size_t size, void *ptr)
{
struct rte_gpu *dev;
dev = gpu_get_by_id(dev_id);
if (dev == NULL) {
GPU_LOG(ERR, "alloc mem for invalid device ID %d", dev_id);
rte_errno = ENODEV;
return -rte_errno;
}
if (dev->ops.mem_register == NULL) {
GPU_LOG(ERR, "mem registration not supported");
rte_errno = ENOTSUP;
return -rte_errno;
}
if (ptr == NULL || size == 0) /* dry-run */
return 0;
return GPU_DRV_RET(dev->ops.mem_register(dev, size, ptr));
}
int
rte_gpu_mem_unregister(int16_t dev_id, void *ptr)
{
struct rte_gpu *dev;
dev = gpu_get_by_id(dev_id);
if (dev == NULL) {
GPU_LOG(ERR, "unregister mem for invalid device ID %d", dev_id);
rte_errno = ENODEV;
return -rte_errno;
}
if (dev->ops.mem_unregister == NULL) {
rte_errno = ENOTSUP;
return -rte_errno;
}
if (ptr == NULL) /* dry-run */
return 0;
return GPU_DRV_RET(dev->ops.mem_unregister(dev, ptr));
}
void *
rte_gpu_mem_cpu_map(int16_t dev_id, size_t size, void *ptr)
{
struct rte_gpu *dev;
void *ptr_out;
int ret;
dev = gpu_get_by_id(dev_id);
if (dev == NULL) {
GPU_LOG(ERR, "mem CPU map for invalid device ID %d", dev_id);
rte_errno = ENODEV;
return NULL;
}
if (dev->ops.mem_cpu_map == NULL) {
GPU_LOG(ERR, "mem CPU map not supported");
rte_errno = ENOTSUP;
return NULL;
}
if (ptr == NULL || size == 0) /* dry-run */
return NULL;
ret = GPU_DRV_RET(dev->ops.mem_cpu_map(dev, size, ptr, &ptr_out));
switch (ret) {
case 0:
return ptr_out;
case -ENOMEM:
case -E2BIG:
rte_errno = -ret;
return NULL;
default:
rte_errno = -EPERM;
return NULL;
}
}
int
rte_gpu_mem_cpu_unmap(int16_t dev_id, void *ptr)
{
struct rte_gpu *dev;
dev = gpu_get_by_id(dev_id);
if (dev == NULL) {
GPU_LOG(ERR, "cpu_unmap mem for invalid device ID %d", dev_id);
rte_errno = ENODEV;
return -rte_errno;
}
if (dev->ops.mem_cpu_unmap == NULL) {
rte_errno = ENOTSUP;
return -rte_errno;
}
if (ptr == NULL) /* dry-run */
return 0;
return GPU_DRV_RET(dev->ops.mem_cpu_unmap(dev, ptr));
}
int
rte_gpu_wmb(int16_t dev_id)
{
struct rte_gpu *dev;
dev = gpu_get_by_id(dev_id);
if (dev == NULL) {
GPU_LOG(ERR, "memory barrier for invalid device ID %d", dev_id);
rte_errno = ENODEV;
return -rte_errno;
}
if (dev->ops.wmb == NULL) {
rte_errno = ENOTSUP;
return -rte_errno;
}
return GPU_DRV_RET(dev->ops.wmb(dev));
}
int
rte_gpu_comm_create_flag(uint16_t dev_id, struct rte_gpu_comm_flag *devflag,
enum rte_gpu_comm_flag_type mtype)
{
size_t flag_size;
int ret;
if (devflag == NULL) {
rte_errno = EINVAL;
return -rte_errno;
}
if (mtype != RTE_GPU_COMM_FLAG_CPU) {
rte_errno = EINVAL;
return -rte_errno;
}
flag_size = sizeof(uint32_t);
devflag->ptr = rte_zmalloc(NULL, flag_size, 0);
if (devflag->ptr == NULL) {
rte_errno = ENOMEM;
return -rte_errno;
}
ret = rte_gpu_mem_register(dev_id, flag_size, devflag->ptr);
if (ret < 0) {
rte_errno = ENOMEM;
return -rte_errno;
}
devflag->mtype = mtype;
devflag->dev_id = dev_id;
return 0;
}
int
rte_gpu_comm_destroy_flag(struct rte_gpu_comm_flag *devflag)
{
int ret;
if (devflag == NULL) {
rte_errno = EINVAL;
return -rte_errno;
}
ret = rte_gpu_mem_unregister(devflag->dev_id, devflag->ptr);
if (ret < 0) {
rte_errno = EINVAL;
return -1;
}
rte_free(devflag->ptr);
return 0;
}
int
rte_gpu_comm_set_flag(struct rte_gpu_comm_flag *devflag, uint32_t val)
{
if (devflag == NULL) {
rte_errno = EINVAL;
return -rte_errno;
}
if (devflag->mtype != RTE_GPU_COMM_FLAG_CPU) {
rte_errno = EINVAL;
return -rte_errno;
}
RTE_GPU_VOLATILE(*devflag->ptr) = val;
return 0;
}
int
rte_gpu_comm_get_flag_value(struct rte_gpu_comm_flag *devflag, uint32_t *val)
{
if (devflag == NULL) {
rte_errno = EINVAL;
return -rte_errno;
}
if (devflag->mtype != RTE_GPU_COMM_FLAG_CPU) {
rte_errno = EINVAL;
return -rte_errno;
}
*val = RTE_GPU_VOLATILE(*devflag->ptr);
return 0;
}
struct rte_gpu_comm_list *
rte_gpu_comm_create_list(uint16_t dev_id,
uint32_t num_comm_items)
{
struct rte_gpu_comm_list *comm_list;
uint32_t idx_l;
int ret;
struct rte_gpu *dev;
struct rte_gpu_info info;
if (num_comm_items == 0) {
rte_errno = EINVAL;
return NULL;
}
dev = gpu_get_by_id(dev_id);
if (dev == NULL) {
GPU_LOG(ERR, "memory barrier for invalid device ID %d", dev_id);
rte_errno = ENODEV;
return NULL;
}
ret = rte_gpu_info_get(dev_id, &info);
if (ret < 0) {
rte_errno = ENODEV;
return NULL;
}
comm_list = rte_zmalloc(NULL,
sizeof(struct rte_gpu_comm_list) * num_comm_items, 0);
if (comm_list == NULL) {
rte_errno = ENOMEM;
return NULL;
}
ret = rte_gpu_mem_register(dev_id,
sizeof(struct rte_gpu_comm_list) * num_comm_items, comm_list);
if (ret < 0) {
rte_errno = ENOMEM;
return NULL;
}
/*
* Use GPU memory CPU map feature if enabled in the driver
* to allocate the status flags of the list.
* Allocating this flag in GPU memory will reduce
* the latency when GPU workload is polling this flag.
*/
comm_list[0].status_d = rte_gpu_mem_alloc(dev_id,
sizeof(enum rte_gpu_comm_list_status) * num_comm_items,
info.page_size);
if (ret < 0) {
rte_errno = ENOMEM;
return NULL;
}
comm_list[0].status_h = rte_gpu_mem_cpu_map(dev_id,
sizeof(enum rte_gpu_comm_list_status) * num_comm_items,
comm_list[0].status_d);
if (comm_list[0].status_h == NULL) {
/*
* If CPU mapping is not supported by driver
* use regular CPU registered memory.
*/
comm_list[0].status_h = rte_zmalloc(NULL,
sizeof(enum rte_gpu_comm_list_status) * num_comm_items, 0);
if (comm_list[0].status_h == NULL) {
rte_errno = ENOMEM;
return NULL;
}
ret = rte_gpu_mem_register(dev_id,
sizeof(enum rte_gpu_comm_list_status) * num_comm_items,
comm_list[0].status_h);
if (ret < 0) {
rte_errno = ENOMEM;
return NULL;
}
comm_list[0].status_d = comm_list[0].status_h;
}
for (idx_l = 0; idx_l < num_comm_items; idx_l++) {
comm_list[idx_l].pkt_list = rte_zmalloc(NULL,
sizeof(struct rte_gpu_comm_pkt) * RTE_GPU_COMM_LIST_PKTS_MAX, 0);
if (comm_list[idx_l].pkt_list == NULL) {
rte_errno = ENOMEM;
return NULL;
}
ret = rte_gpu_mem_register(dev_id,
sizeof(struct rte_gpu_comm_pkt) * RTE_GPU_COMM_LIST_PKTS_MAX,
comm_list[idx_l].pkt_list);
if (ret < 0) {
rte_errno = ENOMEM;
return NULL;
}
comm_list[idx_l].num_pkts = 0;
comm_list[idx_l].dev_id = dev_id;
comm_list[idx_l].mbufs = rte_zmalloc(NULL,
sizeof(struct rte_mbuf *) * RTE_GPU_COMM_LIST_PKTS_MAX, 0);
if (comm_list[idx_l].mbufs == NULL) {
rte_errno = ENOMEM;
return NULL;
}
if (idx_l > 0) {
comm_list[idx_l].status_h = &(comm_list[0].status_h[idx_l]);
comm_list[idx_l].status_d = &(comm_list[0].status_d[idx_l]);
ret = rte_gpu_comm_set_status(&comm_list[idx_l], RTE_GPU_COMM_LIST_FREE);
if (ret < 0) {
rte_errno = ENOMEM;
return NULL;
}
}
}
return comm_list;
}
int
rte_gpu_comm_destroy_list(struct rte_gpu_comm_list *comm_list,
uint32_t num_comm_items)
{
uint32_t idx_l;
int ret;
uint16_t dev_id;
if (comm_list == NULL) {
rte_errno = EINVAL;
return -rte_errno;
}
dev_id = comm_list[0].dev_id;
for (idx_l = 0; idx_l < num_comm_items; idx_l++) {
ret = rte_gpu_mem_unregister(dev_id, comm_list[idx_l].pkt_list);
if (ret < 0) {
rte_errno = EINVAL;
return -1;
}
rte_free(comm_list[idx_l].pkt_list);
rte_free(comm_list[idx_l].mbufs);
}
ret = rte_gpu_mem_unregister(dev_id, comm_list);
if (ret < 0) {
rte_errno = EINVAL;
return -1;
}
ret = rte_gpu_mem_cpu_unmap(dev_id, comm_list[0].status_d);
if (ret == 0) {
rte_gpu_mem_free(dev_id, comm_list[0].status_d);
} else {
rte_gpu_mem_unregister(dev_id, comm_list[0].status_h);
rte_free(comm_list[0].status_h);
}
rte_free(comm_list);
return 0;
}
int
rte_gpu_comm_populate_list_pkts(struct rte_gpu_comm_list *comm_list_item,
struct rte_mbuf **mbufs, uint32_t num_mbufs)
{
uint32_t idx;
int ret;
if (comm_list_item == NULL || comm_list_item->pkt_list == NULL ||
mbufs == NULL || num_mbufs > RTE_GPU_COMM_LIST_PKTS_MAX) {
rte_errno = EINVAL;
return -rte_errno;
}
for (idx = 0; idx < num_mbufs; idx++) {
/* support only unchained mbufs */
if (unlikely((mbufs[idx]->nb_segs > 1) ||
(mbufs[idx]->next != NULL) ||
(mbufs[idx]->data_len != mbufs[idx]->pkt_len))) {
rte_errno = ENOTSUP;
return -rte_errno;
}
comm_list_item->pkt_list[idx].addr =
rte_pktmbuf_mtod_offset(mbufs[idx], uintptr_t, 0);
comm_list_item->pkt_list[idx].size = mbufs[idx]->pkt_len;
comm_list_item->mbufs[idx] = mbufs[idx];
}
RTE_GPU_VOLATILE(comm_list_item->num_pkts) = num_mbufs;
rte_gpu_wmb(comm_list_item->dev_id);
ret = rte_gpu_comm_set_status(comm_list_item, RTE_GPU_COMM_LIST_READY);
if (ret < 0) {
rte_errno = EINVAL;
return -rte_errno;
}
return 0;
}
int
rte_gpu_comm_set_status(struct rte_gpu_comm_list *comm_list_item,
enum rte_gpu_comm_list_status status)
{
if (comm_list_item == NULL) {
rte_errno = EINVAL;
return -rte_errno;
}
RTE_GPU_VOLATILE(comm_list_item->status_h[0]) = status;
return 0;
}
int
rte_gpu_comm_get_status(struct rte_gpu_comm_list *comm_list_item,
enum rte_gpu_comm_list_status *status)
{
if (comm_list_item == NULL || status == NULL) {
rte_errno = EINVAL;
return -rte_errno;
}
*status = RTE_GPU_VOLATILE(comm_list_item->status_h[0]);
return 0;
}
int
rte_gpu_comm_cleanup_list(struct rte_gpu_comm_list *comm_list_item)
{
uint32_t idx = 0;
enum rte_gpu_comm_list_status status;
int ret;
if (comm_list_item == NULL) {
rte_errno = EINVAL;
return -rte_errno;
}
ret = rte_gpu_comm_get_status(comm_list_item, &status);
if (ret < 0) {
rte_errno = EINVAL;
return -rte_errno;
}
if (status == RTE_GPU_COMM_LIST_READY) {
GPU_LOG(ERR, "packet list is still in progress");
rte_errno = EINVAL;
return -rte_errno;
}
for (idx = 0; idx < RTE_GPU_COMM_LIST_PKTS_MAX; idx++) {
if (comm_list_item->pkt_list[idx].addr == 0)
break;
comm_list_item->pkt_list[idx].addr = 0;
comm_list_item->pkt_list[idx].size = 0;
comm_list_item->mbufs[idx] = NULL;
}
ret = rte_gpu_comm_set_status(comm_list_item, RTE_GPU_COMM_LIST_FREE);
if (ret < 0) {
rte_errno = EINVAL;
return -rte_errno;
}
RTE_GPU_VOLATILE(comm_list_item->num_pkts) = 0;
rte_mb();
return 0;
}