Commit a6867721 authored by Krzysztof Karas's avatar Krzysztof Karas Committed by Konrad Sztyber
Browse files

lib/idxd: add DIX generate



Add spdk_idxd_submit_dix_generate() function to submit DIX generate
operation to DSA.
Additionally, enable support for this operation in accel_dsa module.

Change-Id: I99e7c6d0441599fbac092e059ed6394882c51fb9
Signed-off-by: default avatarKrzysztof Karas <krzysztof.karas@intel.com>
Signed-off-by: default avatarSlawomir Ptak <slawomir.ptak@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/24312


Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com>
Reviewed-by: default avatarShuhei Matsumoto <smatsumoto@nvidia.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent da8ecf81
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -389,6 +389,30 @@ int spdk_idxd_submit_dif_strip(struct spdk_idxd_io_channel *chan,
			       uint32_t num_blocks, const struct spdk_dif_ctx *ctx, int flags,
			       spdk_idxd_req_cb cb_fn, void *cb_arg);

/**
 * Build and submit DIX Generate request.
 *
 * This function will build DIX Generate descriptor and then immediately submit
 * by writing to the proper device portal.
 *
 * \param chan IDXD channel to submit the request.
 * \param siov Source iovecs.
 * \param siovcnt Number of elements in siov.
 * \param mdiov Metadata iovec for generated protection information.
 * \param num_blocks Number of data blocks to process.
 * \param ctx DIX context. Contains the DIX configuration values, including the reference
 *	Application Tag and initial value of the Reference Tag to insert.
 * \param flags Flags, optional flags that can vary per operation.
 * \param cb_fn Callback function which will be called upon request completion.
 * \param cb_arg Opaque value which will be passed as a parameter to the cb_fn.
 *
 * \return 0 on success, negative errno on failure.
 */
int spdk_idxd_submit_dix_generate(struct spdk_idxd_io_channel *chan, struct iovec *siov,
				  size_t siovcnt, struct iovec *mdiov, uint32_t num_blocks,
				  const struct spdk_dif_ctx *ctx, int flags,
				  spdk_idxd_req_cb cb_fn, void *cb_arg);

/**
 * Build and submit an IDXD raw request.
 *
+1 −1
Original line number Diff line number Diff line
@@ -7,7 +7,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk

SO_VER := 12
SO_MINOR := 0
SO_MINOR := 1

C_SRCS = idxd.c idxd_user.c
ifeq ($(CONFIG_IDXD_KERNEL),y)
+177 −0
Original line number Diff line number Diff line
@@ -1302,6 +1302,8 @@ idxd_get_dif_flags(const struct spdk_dif_ctx *ctx, uint8_t *flags)
		return -EINVAL;
	}

	assert(ctx->md_interleave);

	switch (ctx->guard_interval) {
	case DATA_BLOCK_SIZE_512:
		*flags = IDXD_DIF_FLAG_DIF_BLOCK_SIZE_512;
@@ -1855,6 +1857,181 @@ error:
	return rc;
}

static inline int
idxd_get_dix_flags(const struct spdk_dif_ctx *ctx, uint8_t *flags)
{
	uint32_t data_block_size = ctx->block_size;

	assert(!ctx->md_interleave);

	if (flags == NULL) {
		SPDK_ERRLOG("Flag should be non-null");
		return -EINVAL;
	}

	switch (data_block_size) {
	case DATA_BLOCK_SIZE_512:
		*flags = IDXD_DIF_FLAG_DIF_BLOCK_SIZE_512;
		break;
	case DATA_BLOCK_SIZE_4096:
		*flags = IDXD_DIF_FLAG_DIF_BLOCK_SIZE_4096;
		break;
	default:
		SPDK_ERRLOG("Invalid DIX block size %d\n", data_block_size);
		return -EINVAL;
	}

	return 0;
}

static inline int
idxd_validate_dix_generate_params(const struct spdk_dif_ctx *ctx)
{
	/* Check for required DIF flags. Intel DSA is able to only generate all DIF fields. */
	if (!(ctx->dif_flags & SPDK_DIF_FLAGS_GUARD_CHECK))  {
		SPDK_ERRLOG("Guard check flag must be set.\n");
		return -EINVAL;
	}

	if (!(ctx->dif_flags & SPDK_DIF_FLAGS_APPTAG_CHECK))  {
		SPDK_ERRLOG("Application Tag check flag must be set.\n");
		return -EINVAL;
	}

	if (!(ctx->dif_flags & SPDK_DIF_FLAGS_REFTAG_CHECK))  {
		SPDK_ERRLOG("Reference Tag check flag must be set.\n");
		return -EINVAL;
	}

	/* Check byte offset from the start of the whole data buffer */
	if (ctx->data_offset != 0) {
		SPDK_ERRLOG("Byte offset from the start of the whole data buffer must be set to 0.");
		return -EINVAL;
	}

	/* Check seed value for guard computation */
	if (ctx->guard_seed != 0) {
		SPDK_ERRLOG("Seed value for guard computation must be set to 0.");
		return -EINVAL;
	}

	/* Check for supported metadata sizes */
	if (ctx->md_size != METADATA_SIZE_8)  {
		SPDK_ERRLOG("Metadata size %d is not supported.\n", ctx->md_size);
		return -EINVAL;
	}

	/* Check for supported DIF PI formats */
	if (ctx->dif_pi_format != SPDK_DIF_PI_FORMAT_16) {
		SPDK_ERRLOG("DIF PI format %d is not supported.\n", ctx->dif_pi_format);
		return -EINVAL;
	}

	/* Check for supported DIF block sizes */
	if (ctx->block_size != DATA_BLOCK_SIZE_512 &&
	    ctx->block_size != DATA_BLOCK_SIZE_4096) {
		SPDK_ERRLOG("DIF block size %d is not supported.\n", ctx->block_size);
		return -EINVAL;
	}

	return 0;
}

int
spdk_idxd_submit_dix_generate(struct spdk_idxd_io_channel *chan, struct iovec *siov,
			      size_t siovcnt, struct iovec *mdiov, uint32_t num_blocks,
			      const struct spdk_dif_ctx *ctx, int flags,
			      spdk_idxd_req_cb cb_fn, void *cb_arg)
{
	struct idxd_hw_desc *desc;
	struct idxd_ops *first_op = NULL, *op = NULL;
	uint64_t src_seg_addr, src_seg_len;
	uint64_t md_seg_addr, md_seg_len;
	uint32_t num_blocks_done = 0;
	uint8_t dif_flags = 0;
	uint16_t app_tag_mask = 0;
	int rc, count = 0;
	size_t i;

	rc = idxd_validate_dix_generate_params(ctx);
	if (rc) {
		return rc;
	}

	rc = idxd_get_dix_flags(ctx, &dif_flags);
	if (rc) {
		return rc;
	}

	rc = idxd_get_app_tag_mask(ctx, &app_tag_mask);
	if (rc) {
		return rc;
	}

	rc = _idxd_setup_batch(chan);
	if (rc) {
		return rc;
	}

	md_seg_len = mdiov->iov_len;
	md_seg_addr = (uint64_t)mdiov->iov_base;

	if (md_seg_len % ctx->md_size != 0) {
		SPDK_ERRLOG("The metadata buffer length (%ld) is not a multiple of metadata size.\n",
			    md_seg_len);
		return -EINVAL;
	}

	for (i = 0; i < siovcnt; i++) {
		src_seg_addr = (uint64_t)siov[i].iov_base;
		src_seg_len = siov[i].iov_len;

		if (src_seg_len % ctx->block_size != 0) {
			SPDK_ERRLOG("The source buffer length (%ld) is not a multiple of block size (%d).\n",
				    src_seg_len, ctx->block_size);
			goto error;
		}

		if (first_op == NULL) {
			rc = _idxd_prep_batch_cmd(chan, cb_fn, cb_arg, flags, &desc, &op);
			if (rc) {
				goto error;
			}

			first_op = op;
		} else {
			rc = _idxd_prep_batch_cmd(chan, NULL, NULL, flags, &desc, &op);
			if (rc) {
				goto error;
			}

			first_op->count++;
			op->parent = first_op;
		}

		count++;

		desc->opcode = IDXD_OPCODE_DIX_GEN;
		desc->src_addr = src_seg_addr;
		desc->dst_addr = md_seg_addr;
		desc->xfer_size = src_seg_len;
		desc->dix_gen.flags = dif_flags;
		desc->dix_gen.app_tag_seed = ctx->app_tag;
		desc->dix_gen.app_tag_mask = ~ctx->apptag_mask;
		desc->dix_gen.ref_tag_seed = (uint32_t)ctx->init_ref_tag + num_blocks_done;

		num_blocks_done += src_seg_len / ctx->block_size;

		md_seg_addr = (uint64_t)mdiov->iov_base + (num_blocks_done * ctx->md_size);
	}

	return _idxd_flush_batch(chan);

error:
	chan->batch->index -= count;
	return rc;
}

int
spdk_idxd_submit_raw_desc(struct spdk_idxd_io_channel *chan,
			  struct idxd_hw_desc *_desc,
+1 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
	spdk_idxd_submit_dif_check;
	spdk_idxd_submit_dif_insert;
	spdk_idxd_submit_dif_strip;
	spdk_idxd_submit_dix_generate;
	spdk_idxd_submit_raw_desc;
	spdk_idxd_process_events;
	spdk_idxd_get_channel;
+9 −0
Original line number Diff line number Diff line
@@ -278,6 +278,11 @@ _process_single_task(struct spdk_io_channel *ch, struct spdk_accel_task *task)
			rc = 0;
		}
		break;
	case SPDK_ACCEL_OPC_DIX_GENERATE:
		rc = spdk_idxd_submit_dix_generate(chan->chan, task->s.iovs, task->s.iovcnt,
						   task->d.iovs, task->dif.num_blocks,
						   task->dif.ctx, flags, dsa_done, idxd_task);
		break;
	default:
		assert(false);
		rc = -EINVAL;
@@ -391,6 +396,10 @@ dsa_supports_opcode(enum spdk_accel_opcode opc)
	case SPDK_ACCEL_OPC_DIF_VERIFY:
	case SPDK_ACCEL_OPC_DIF_GENERATE_COPY:
	case SPDK_ACCEL_OPC_DIF_VERIFY_COPY:
	/* In theory, DIX Generate could work without the iommu, but iommu is required
	 * for consistency with other DIF operations.
	 */
	case SPDK_ACCEL_OPC_DIX_GENERATE:
		/* Supported only if the IOMMU is enabled */
		return spdk_iommu_is_enabled();
	default: