4cbc8b20c7
The unformat type for "%d" should be u32 or int, otherwise the 'did' in high stack address will be overflow to zero by the 'qid' which is in the low stack address. Like input "dev wq3.2" will return "did=0, qid=2". Type: fix Signed-off-by: Haiyue Wang <haiyue.wang@intel.com> Change-Id: I0fe1d5b03e2c47e0a7925193e2c2f1ccc31d3e90
273 lines
6.5 KiB
C
273 lines
6.5 KiB
C
/* 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;
|
|
u32 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",
|
|
};
|