blob: 4e9df04ea9e22dfa1e3eb7bcf3571376f45ac08a [file] [log] [blame]
/* SPDX-License-Identifier: Apache-2.0
* Copyright (c) 2022 Cisco Systems, Inc.
* Copyright (c) 2022 Intel and/or its affiliates.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <vlib/vlib.h>
#include <vlib/pci/pci.h>
#include <vlib/dma/dma.h>
#include <vnet/plugin/plugin.h>
#include <vpp/app/version.h>
#include <vppinfra/linux/sysfs.h>
#include <dma_intel/dsa_intel.h>
VLIB_REGISTER_LOG_CLASS (intel_dsa_log, static) = {
.class_name = "intel_dsa",
};
intel_dsa_main_t intel_dsa_main;
void
intel_dsa_assign_channels (vlib_main_t *vm)
{
intel_dsa_main_t *idm = &intel_dsa_main;
intel_dsa_channel_t *ch, **chv = 0;
u16 n_threads;
int n;
vec_foreach_index (n, idm->channels)
vec_append (chv, idm->channels[n]);
vec_validate (idm->dsa_threads, vlib_get_n_threads () - 1);
if (vec_len (chv) == 0)
{
dsa_log_debug ("No DSA channels found");
goto done;
}
if (vec_len (chv) >= vlib_get_n_threads ())
n_threads = 1;
else
n_threads = vlib_get_n_threads () % vec_len (chv) ?
vlib_get_n_threads () / vec_len (chv) + 1 :
vlib_get_n_threads () / vec_len (chv);
for (int i = 0; i < vlib_get_n_threads (); i++)
{
vlib_main_t *tvm = vlib_get_main_by_index (i);
ch = *vec_elt_at_index (chv, i / n_threads);
idm->dsa_threads[i].ch = ch;
ch->n_threads = n_threads;
dsa_log_debug ("Assigning channel %u/%u to thread %u (numa %u)", ch->did,
ch->qid, i, tvm->numa_node);
}
done:
/* free */
vec_free (chv);
}
static clib_error_t *
intel_dsa_map_region (intel_dsa_channel_t *ch)
{
static clib_error_t *error = NULL;
/* map one page */
uword size = 0x1000;
uword offset = 0;
char path[256] = { 0 };
snprintf (path, sizeof (path), "%s/wq%d.%d", DSA_DEV_PATH, ch->did, ch->qid);
int fd = open (path, O_RDWR);
if (fd < 0)
return clib_error_return (0, "failed to open dsa device %s", path);
ch->portal =
clib_mem_vm_map_shared (0, size, fd, offset, "%s", (char *) path);
if (ch->portal == CLIB_MEM_VM_MAP_FAILED)
{
error = clib_error_return (0, "mmap portal %s failed", path);
close (fd);
return error;
}
return NULL;
}
static clib_error_t *
intel_dsa_get_info (intel_dsa_channel_t *ch, clib_error_t **error)
{
clib_error_t *err;
u8 *tmpstr;
u8 *dev_dir_name = 0, *wq_dir_name = 0;
u8 *f = 0;
dev_dir_name = format (0, "%s/dsa%d", SYS_DSA_PATH, ch->did);
vec_reset_length (f);
f = format (f, "%v/numa_node%c", dev_dir_name, 0);
err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
if (err)
goto error;
ch->numa = atoi ((char *) tmpstr);
wq_dir_name = format (0, "%s/%U", SYS_DSA_PATH, format_intel_dsa_addr, ch);
vec_reset_length (f);
f = format (f, "%v/max_transfer_size%c", wq_dir_name, 0);
err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
if (err)
goto error;
ch->max_transfer_size = atoi ((char *) tmpstr);
vec_reset_length (f);
f = format (f, "%v/max_batch_size%c", wq_dir_name, 0);
err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
if (err)
goto error;
ch->max_transfers = atoi ((char *) tmpstr);
vec_reset_length (f);
f = format (f, "%v/size%c", wq_dir_name, 0);
err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
if (err)
goto error;
ch->size = atoi ((char *) tmpstr);
vec_reset_length (f);
f = format (f, "%v/type%c", wq_dir_name, 0);
err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
if (err)
goto error;
if (tmpstr)
{
if (!clib_strcmp ((char *) tmpstr, "enabled"))
ch->type = INTEL_DSA_DEVICE_TYPE_UNKNOWN;
else if (!clib_strcmp ((char *) tmpstr, "user"))
ch->type = INTEL_DSA_DEVICE_TYPE_USER;
else if (!clib_strcmp ((char *) tmpstr, "mdev"))
ch->type = INTEL_DSA_DEVICE_TYPE_KERNEL;
else
ch->type = INTEL_DSA_DEVICE_TYPE_UNKNOWN;
vec_free (tmpstr);
}
vec_reset_length (f);
f = format (f, "%v/state%c", wq_dir_name, 0);
err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
if (err)
goto error;
if (tmpstr)
{
if (!clib_strcmp ((char *) tmpstr, "enabled"))
ch->state = 1;
else
ch->state = 0;
vec_free (tmpstr);
}
vec_reset_length (f);
f = format (f, "%v/ats_disable%c", wq_dir_name, 0);
err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
if (err)
goto error;
ch->ats_disable = atoi ((char *) tmpstr);
vec_reset_length (f);
f = format (f, "%v/block_on_fault%c", wq_dir_name, 0);
err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
if (err)
goto error;
ch->block_on_fault = atoi ((char *) tmpstr);
vec_reset_length (f);
f = format (f, "%v/mode%c", wq_dir_name, 0);
err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
if (err)
goto error;
if (tmpstr)
{
if (!clib_strcmp ((char *) tmpstr, "dedicated"))
ch->mode = 1;
else
ch->mode = 0;
vec_free (tmpstr);
}
vec_free (f);
vec_free (dev_dir_name);
vec_free (wq_dir_name);
return NULL;
error:
vec_free (f);
vec_free (dev_dir_name);
vec_free (wq_dir_name);
return err;
}
clib_error_t *
intel_dsa_add_channel (vlib_main_t *vm, intel_dsa_channel_t *ch)
{
intel_dsa_main_t *dm = &intel_dsa_main;
clib_error_t *err = 0;
if (intel_dsa_map_region (ch))
return clib_error_return (0, "dsa open device failed");
if (intel_dsa_get_info (ch, &err))
return clib_error_return (err, "dsa info not scanned");
vec_validate (dm->channels, ch->numa);
vec_add1 (dm->channels[ch->numa], ch);
return err;
}
static clib_error_t *
dsa_config (vlib_main_t *vm, unformat_input_t *input)
{
clib_error_t *error = 0;
intel_dsa_channel_t *ch;
u8 did, qid;
if (intel_dsa_main.lock == 0)
clib_spinlock_init (&(intel_dsa_main.lock));
if ((error = vlib_dma_register_backend (vm, &intel_dsa_backend)))
goto done;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (input, "dev wq%d.%d", &did, &qid))
{
ch = clib_mem_alloc_aligned (sizeof (*ch), CLIB_CACHE_LINE_BYTES);
clib_memset (ch, 0, sizeof (*ch));
ch->did = did;
ch->qid = qid;
if (intel_dsa_add_channel (vm, ch))
clib_mem_free (ch);
}
else if (unformat_skip_white_space (input))
;
else
{
error = clib_error_return (0, "unknown input `%U'",
format_unformat_error, input);
goto done;
}
}
done:
return error;
}
VLIB_CONFIG_FUNCTION (dsa_config, "dsa");
clib_error_t *
intel_dsa_num_workers_change (vlib_main_t *vm)
{
intel_dsa_assign_channels (vm);
return 0;
}
VLIB_NUM_WORKERS_CHANGE_FN (intel_dsa_num_workers_change);
VLIB_PLUGIN_REGISTER () = {
.version = VPP_BUILD_VER,
.description = "Intel DSA Backend",
};