HE-MEM is one of the host exerciser modules in OFS FPGA, which is used to test local memory with built-in traffic generator. This driver initialize the module and report test result.
Signed-off-by: Wei Huang <wei.hu...@intel.com> Acked-by: Tianfei Zhang <tianfei.zh...@intel.com> --- v2: move source files to ifpga and rename --- drivers/raw/ifpga/afu_pmd_he_mem.c | 183 +++++++++++++++++++++++++++++++++++++ drivers/raw/ifpga/afu_pmd_he_mem.h | 46 ++++++++++ drivers/raw/ifpga/meson.build | 2 +- drivers/raw/ifpga/rte_pmd_afu.h | 7 ++ 4 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 drivers/raw/ifpga/afu_pmd_he_mem.c create mode 100644 drivers/raw/ifpga/afu_pmd_he_mem.h diff --git a/drivers/raw/ifpga/afu_pmd_he_mem.c b/drivers/raw/ifpga/afu_pmd_he_mem.c new file mode 100644 index 0000000..0f57a03 --- /dev/null +++ b/drivers/raw/ifpga/afu_pmd_he_mem.c @@ -0,0 +1,183 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2022 Intel Corporation + */ + +#include <errno.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <poll.h> +#include <sys/eventfd.h> +#include <sys/ioctl.h> + +#include <rte_eal.h> +#include <rte_malloc.h> +#include <rte_memcpy.h> +#include <rte_io.h> +#include <rte_vfio.h> +#include <rte_bus_pci.h> +#include <rte_bus_ifpga.h> +#include <rte_rawdev.h> + +#include "afu_pmd_core.h" +#include "afu_pmd_he_mem.h" + +static int he_mem_tg_test(struct afu_rawdev *dev) +{ + struct he_mem_tg_priv *priv = NULL; + struct rte_pmd_afu_he_mem_tg_cfg *cfg = NULL; + struct he_mem_tg_ctx *ctx = NULL; + uint64_t value = 0x12345678; + uint64_t cap = 0; + uint64_t channel_mask = 0; + int i, t = 0; + + if (!dev) + return -EINVAL; + + priv = (struct he_mem_tg_priv *)dev->priv; + if (!priv) + return -ENOENT; + + cfg = &priv->he_mem_tg_cfg; + ctx = &priv->he_mem_tg_ctx; + + IFPGA_RAWDEV_PMD_DEBUG("Channel mask: 0x%x", cfg->channel_mask); + + rte_write64(value, ctx->addr + MEM_TG_SCRATCHPAD); + cap = rte_read64(ctx->addr + MEM_TG_SCRATCHPAD); + IFPGA_RAWDEV_PMD_DEBUG("Scratchpad value: 0x%"PRIx64, cap); + if (cap != value) { + IFPGA_RAWDEV_PMD_ERR("Test scratchpad register failed"); + return -EIO; + } + + cap = rte_read64(ctx->addr + MEM_TG_CTRL); + IFPGA_RAWDEV_PMD_DEBUG("Capability: 0x%"PRIx64, cap); + + channel_mask = cfg->channel_mask & cap; + /* start traffic generators */ + rte_write64(channel_mask, ctx->addr + MEM_TG_CTRL); + + /* check test status */ + while (t < MEM_TG_TIMEOUT_MS) { + value = rte_read64(ctx->addr + MEM_TG_STAT); + for (i = 0; i < NUM_MEM_TG_CHANNELS; i++) { + if (channel_mask & (1 << i)) { + if (TGACTIVE(value, i)) + continue; + printf("TG channel %d test %s\n", i, + TGPASS(value, i) ? "pass" : + TGTIMEOUT(value, i) ? "timeout" : + TGFAIL(value, i) ? "fail" : "error"); + channel_mask &= ~(1 << i); + } + } + if (!channel_mask) + break; + rte_delay_ms(MEM_TG_POLL_INTERVAL_MS); + t += MEM_TG_POLL_INTERVAL_MS; + } + + if (channel_mask) { + IFPGA_RAWDEV_PMD_ERR("Timeout 0x%04lx", (unsigned long)value); + return channel_mask; + } + + return 0; +} + +static int he_mem_tg_init(struct afu_rawdev *dev) +{ + struct he_mem_tg_priv *priv = NULL; + struct he_mem_tg_ctx *ctx = NULL; + + if (!dev) + return -EINVAL; + + priv = (struct he_mem_tg_priv *)dev->priv; + if (!priv) { + priv = rte_zmalloc(NULL, sizeof(struct he_mem_tg_priv), 0); + if (!priv) + return -ENOMEM; + dev->priv = priv; + } + + ctx = &priv->he_mem_tg_ctx; + ctx->addr = (uint8_t *)dev->addr; + + return 0; +} + +static int he_mem_tg_config(struct afu_rawdev *dev, void *config, + size_t config_size) +{ + struct he_mem_tg_priv *priv = NULL; + + if (!dev || !config || !config_size) + return -EINVAL; + + priv = (struct he_mem_tg_priv *)dev->priv; + if (!priv) + return -ENOENT; + + if (config_size != sizeof(struct rte_pmd_afu_he_mem_tg_cfg)) + return -EINVAL; + + rte_memcpy(&priv->he_mem_tg_cfg, config, sizeof(priv->he_mem_tg_cfg)); + + return 0; +} + +static int he_mem_tg_close(struct afu_rawdev *dev) +{ + if (!dev) + return -EINVAL; + + rte_free(dev->priv); + dev->priv = NULL; + + return 0; +} + +static int he_mem_tg_dump(struct afu_rawdev *dev, FILE *f) +{ + struct he_mem_tg_priv *priv = NULL; + struct he_mem_tg_ctx *ctx = NULL; + + if (!dev) + return -EINVAL; + + priv = (struct he_mem_tg_priv *)dev->priv; + if (!priv) + return -ENOENT; + + if (!f) + f = stdout; + + ctx = &priv->he_mem_tg_ctx; + + fprintf(f, "addr:\t\t%p\n", (void *)ctx->addr); + + return 0; +} + +static struct afu_ops he_mem_tg_ops = { + .init = he_mem_tg_init, + .config = he_mem_tg_config, + .start = NULL, + .stop = NULL, + .test = he_mem_tg_test, + .close = he_mem_tg_close, + .dump = he_mem_tg_dump, + .reset = NULL +}; + +struct afu_rawdev_drv he_mem_tg_drv = { + .uuid = { HE_MEM_TG_UUID_L, HE_MEM_TG_UUID_H }, + .ops = &he_mem_tg_ops +}; + +AFU_PMD_REGISTER(he_mem_tg_drv); diff --git a/drivers/raw/ifpga/afu_pmd_he_mem.h b/drivers/raw/ifpga/afu_pmd_he_mem.h new file mode 100644 index 0000000..5549687 --- /dev/null +++ b/drivers/raw/ifpga/afu_pmd_he_mem.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2022 Intel Corporation + */ + +#ifndef _AFU_PMD_HE_MEM_H_ +#define _AFU_PMD_HE_MEM_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "afu_pmd_core.h" +#include "rte_pmd_afu.h" + +#define HE_MEM_TG_UUID_L 0xa3dc5b831f5cecbb +#define HE_MEM_TG_UUID_H 0x4dadea342c7848cb + +#define NUM_MEM_TG_CHANNELS 4 +#define MEM_TG_TIMEOUT_MS 5000 +#define MEM_TG_POLL_INTERVAL_MS 10 + +/* MEM-TG registers definition */ +#define MEM_TG_SCRATCHPAD 0x28 +#define MEM_TG_CTRL 0x30 +#define TGCONTROL(n) (1 << (n)) +#define MEM_TG_STAT 0x38 +#define TGSTATUS(v, n) (((v) >> (n << 2)) & 0xf) +#define TGPASS(v, n) (((v) >> ((n << 2) + 3)) & 0x1) +#define TGFAIL(v, n) (((v) >> ((n << 2) + 2)) & 0x1) +#define TGTIMEOUT(v, n) (((v) >> ((n << 2) + 1)) & 0x1) +#define TGACTIVE(v, n) (((v) >> (n << 2)) & 0x1) + +struct he_mem_tg_ctx { + uint8_t *addr; +}; + +struct he_mem_tg_priv { + struct rte_pmd_afu_he_mem_tg_cfg he_mem_tg_cfg; + struct he_mem_tg_ctx he_mem_tg_ctx; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _AFU_PMD_HE_MEM_H_ */ diff --git a/drivers/raw/ifpga/meson.build b/drivers/raw/ifpga/meson.build index 629ff8a..dc6941d 100644 --- a/drivers/raw/ifpga/meson.build +++ b/drivers/raw/ifpga/meson.build @@ -14,7 +14,7 @@ deps += ['ethdev', 'rawdev', 'pci', 'bus_pci', 'kvargs', 'bus_vdev', 'bus_ifpga', 'net', 'net_i40e', 'net_ipn3ke'] sources = files('ifpga_rawdev.c', 'rte_pmd_ifpga.c', 'afu_pmd_core.c', - 'afu_pmd_n3000.c', 'afu_pmd_he_lpbk.c') + 'afu_pmd_n3000.c', 'afu_pmd_he_lpbk.c', 'afu_pmd_he_mem.c') includes += include_directories('base') includes += include_directories('../../net/ipn3ke') diff --git a/drivers/raw/ifpga/rte_pmd_afu.h b/drivers/raw/ifpga/rte_pmd_afu.h index 19b3902..213e854 100644 --- a/drivers/raw/ifpga/rte_pmd_afu.h +++ b/drivers/raw/ifpga/rte_pmd_afu.h @@ -104,6 +104,13 @@ struct rte_pmd_afu_he_lpbk_cfg { uint32_t freq_mhz; }; +/** + * HE-MEM-TG AFU configuration data structure. + */ +struct rte_pmd_afu_he_mem_tg_cfg { + uint32_t channel_mask; /* mask of traffic generator channel */ +}; + #ifdef __cplusplus } #endif -- 1.8.3.1