[Accel-config] [PATCH v4 4/7] accel-config/test: add create and apply delta record operation support

Tony Zhu <tony.zhu at intel.com> Mon, 21 Feb 2022 09:34:20 +0800
Newsgroups dev.linux.lists.accel-config
Message-ID <[email protected]>
Do creating delta record and then do apply delta operation test. Delta Record
Address is the address of a delta record that was created by a Create Delta
Record operation that completed with Result equal to 1.

Signed-off-by: Tony Zhu <tony.zhu(a)intel.com>
---
 test/dsa.c      | 170 ++++++++++++++++++++++++++++++++++++++++++++++++
 test/dsa.h      |  16 +++++
 test/dsa_test.c | 126 ++++++++++++++++++++++++++++++++++-
 test/prep.c     | 116 +++++++++++++++++++++++++++++++++
 4 files changed, 427 insertions(+), 1 deletion(-)

diff --git a/test/dsa.c b/test/dsa.c
index 1ac925b..a4d9b64 100644
--- a/test/dsa.c
+++ b/test/dsa.c
@@ -388,6 +388,41 @@ int init_dualcast(struct task *tsk, int tflags, int opcode, unsigned long xfer_s
 	return DSA_STATUS_OK;
 }
 
+int init_cr_delta(struct task *tsk, int tflags, int opcode, unsigned long xfer_size)
+{
+	unsigned long force_align = ADDR_ALIGNMENT;
+	unsigned long delta_size;
+
+	tsk->pattern = 0x1234;
+	tsk->pattern2 = 0x1233;
+	tsk->opcode = opcode;
+	tsk->test_flags = tflags;
+	tsk->xfer_size = xfer_size;
+
+	tsk->src1 = aligned_alloc(force_align, tsk->xfer_size);
+	if (!tsk->src1)
+		return -ENOMEM;
+	memset_pattern(tsk->src1, tsk->pattern, tsk->xfer_size);
+
+	tsk->src2 = aligned_alloc(force_align, tsk->xfer_size);
+	if (!tsk->src2)
+		return -ENOMEM;
+	memset_pattern(tsk->src2, tsk->pattern2, tsk->xfer_size);
+	delta_size = 2 * xfer_size;
+
+	tsk->delta1 = aligned_alloc(force_align, delta_size);
+	if (!tsk->delta1)
+		return -ENOMEM;
+
+	if (opcode == DSA_OPCODE_AP_DELTA) {
+		tsk->dst1 = aligned_alloc(force_align, tsk->xfer_size);
+		if (!tsk->dst1)
+			return -ENOMEM;
+	}
+
+	return DSA_STATUS_OK;
+}
+
 /* this function is re-used by batch task */
 int init_task(struct task *tsk, int tflags, int opcode,
 	      unsigned long xfer_size)
@@ -418,6 +453,11 @@ int init_task(struct task *tsk, int tflags, int opcode,
 	case DSA_OPCODE_DUALCAST:
 		rc = init_dualcast(tsk, tflags, opcode, xfer_size);
 		break;
+
+	case DSA_OPCODE_AP_DELTA:
+	case DSA_OPCODE_CR_DELTA:
+		rc = init_cr_delta(tsk, tflags, opcode, xfer_size);
+		break;
 	}
 
 	if (rc != DSA_STATUS_OK) {
@@ -1115,6 +1155,118 @@ int dsa_dualcast_multi_task_nodes(struct dsa_context *ctx)
 	return ret;
 }
 
+int dsa_wait_cr_delta(struct dsa_context *ctx, struct task *tsk)
+{
+	struct dsa_hw_desc *desc = tsk->desc;
+	struct dsa_completion_record *comp = tsk->comp;
+	int rc;
+
+again:
+	rc = dsa_wait_on_desc_timeout(comp, ms_timeout);
+	if (rc < 0) {
+		err("memcpy desc timeout\n");
+		return DSA_STATUS_TIMEOUT;
+	}
+
+	/* re-submit if PAGE_FAULT reported by HW && BOF is off */
+	if (stat_val(comp->status) == DSA_COMP_PAGE_FAULT_NOBOF &&
+	    !(desc->flags & IDXD_OP_FLAG_BOF)) {
+		dsa_reprep_cr_delta(ctx, tsk);
+		goto again;
+	}
+
+	return DSA_STATUS_OK;
+}
+
+int dsa_cr_delta_multi_task_nodes(struct dsa_context *ctx)
+{
+	struct task_node *tsk_node = ctx->multi_task_node;
+	int ret = DSA_STATUS_OK;
+
+	while (tsk_node) {
+		tsk_node->tsk->dflags = IDXD_OP_FLAG_CRAV | IDXD_OP_FLAG_RCR;
+		if ((tsk_node->tsk->test_flags & TEST_FLAGS_BOF) && ctx->bof)
+			tsk_node->tsk->dflags |= IDXD_OP_FLAG_BOF;
+
+		dsa_prep_cr_delta(tsk_node->tsk);
+		tsk_node = tsk_node->next;
+	}
+
+	info("Submitted all cr delta jobs\n");
+	tsk_node = ctx->multi_task_node;
+	while (tsk_node) {
+		dsa_desc_submit(ctx, tsk_node->tsk->desc);
+		tsk_node = tsk_node->next;
+	}
+
+	tsk_node = ctx->multi_task_node;
+	while (tsk_node) {
+		ret = dsa_wait_cr_delta(ctx, tsk_node->tsk);
+		if (ret != DSA_STATUS_OK)
+			info("Desc: %p failed with ret: %d\n",
+			     tsk_node->tsk->desc, tsk_node->tsk->comp->status);
+		tsk_node = tsk_node->next;
+	}
+
+	return ret;
+}
+
+int dsa_wait_ap_delta(struct dsa_context *ctx, struct task *tsk)
+{
+	struct dsa_hw_desc *desc = tsk->desc;
+	struct dsa_completion_record *comp = tsk->comp;
+	int rc;
+
+again:
+	rc = dsa_wait_on_desc_timeout(comp, ms_timeout);
+	if (rc < 0) {
+		err("memcpy desc timeout\n");
+		return DSA_STATUS_TIMEOUT;
+	}
+
+	/* re-submit if PAGE_FAULT reported by HW && BOF is off */
+	if (stat_val(comp->status) == DSA_COMP_PAGE_FAULT_NOBOF &&
+	    !(desc->flags & IDXD_OP_FLAG_BOF)) {
+		dsa_reprep_ap_delta(ctx, tsk);
+		goto again;
+	}
+
+	return DSA_STATUS_OK;
+}
+
+int dsa_ap_delta_multi_task_nodes(struct dsa_context *ctx)
+{
+	struct task_node *tsk_node = ctx->multi_task_node;
+	int ret = DSA_STATUS_OK;
+
+	while (tsk_node) {
+		tsk_node->tsk->dflags = IDXD_OP_FLAG_CRAV | IDXD_OP_FLAG_RCR;
+		if ((tsk_node->tsk->test_flags & TEST_FLAGS_BOF) && ctx->bof)
+			tsk_node->tsk->dflags |= IDXD_OP_FLAG_BOF;
+
+		dsa_prep_ap_delta(tsk_node->tsk);
+		tsk_node = tsk_node->next;
+	}
+
+	info("Submitted all ap delta jobs\n");
+	tsk_node = ctx->multi_task_node;
+	while (tsk_node) {
+		dsa_desc_submit(ctx, tsk_node->tsk->desc);
+		tsk_node = tsk_node->next;
+	}
+
+	tsk_node = ctx->multi_task_node;
+	while (tsk_node) {
+		ret = dsa_wait_ap_delta(ctx, tsk_node->tsk);
+		if (ret != DSA_STATUS_OK)
+			info("Desc: %p failed with ret: %d\n",
+			     tsk_node->tsk->desc, tsk_node->tsk->comp->status);
+		tsk_node = tsk_node->next;
+	}
+
+	return ret;
+}
+
 /* mismatch_expected: expect mismatched buffer with success status 0x1 */
 int task_result_verify(struct task *tsk, int mismatch_expected)
 {
@@ -1141,6 +1293,9 @@ int task_result_verify(struct task *tsk, int mismatch_expected)
 	case DSA_OPCODE_DUALCAST:
 		rc = task_result_verify_dualcast(tsk, mismatch_expected);
 		return rc;
+	case DSA_OPCODE_AP_DELTA:
+		rc = task_result_verify_ap_delta(tsk, mismatch_expected);
+		return rc;
 	}
 
 	info("test with op %d passed\n", tsk->opcode);
@@ -1260,6 +1415,21 @@ int task_result_verify_dualcast(struct task *tsk, int mismatch_expected)
 	return DSA_STATUS_OK;
 }
 
+int task_result_verify_ap_delta(struct task *tsk, int mismatch_expected)
+{
+	int rc;
+	int data_size = (tsk->comp->status == DSA_COMP_SUCCESS) ?
+			 tsk->desc->xfer_size : tsk->comp->bytes_completed;
+
+	rc = memcmp((unsigned char *)tsk->desc->dst_addr,
+		    (unsigned char *)tsk->desc->src2_addr, data_size);
+	if (rc) {
+		err("apply delta mismatch, memcmp rc %d\n", rc);
+		return -ENXIO;
+	}
+	return DSA_STATUS_OK;
+}
+
 int batch_result_verify(struct batch_task *btsk, int bof)
 {
 	uint8_t core_stat, sub_stat;
diff --git a/test/dsa.h b/test/dsa.h
index 59b3ef5..51e9b1c 100644
--- a/test/dsa.h
+++ b/test/dsa.h
@@ -43,6 +43,7 @@
 
 #define ADDR_ALIGNMENT 32
 
+#define MIN_DELTA_RECORD_SIZE 80
 /* helper macro to get lower 6 bits (ret code) from completion status */
 #define stat_val(status) ((status) & DSA_COMP_STAT_CODE_MASK)
 
@@ -58,6 +59,7 @@ struct task {
 	void *src2;
 	void *dst1;
 	void *dst2;
+	void *delta1;
 	uint64_t pattern;
 	uint64_t pattern2;
 	uint64_t xfer_size;
@@ -235,6 +237,7 @@ int init_memfill(struct task *tsk, int tflags, int opcode, unsigned long xfer_si
 int init_compare(struct task *tsk, int tflags, int opcode, unsigned long xfer_size);
 int init_compval(struct task *tsk, int tflags, int opcode, unsigned long xfer_size);
 int init_dualcast(struct task *tsk, int tflags, int opcode, unsigned long xfer_size);
+int init_cr_delta(struct task *tsk, int tflags, int opcode, unsigned long xfer_size);
 int init_task(struct task *tsk, int tflags, int opcode,
 	      unsigned long xfer_size);
 
@@ -259,6 +262,12 @@ int dsa_wait_compval(struct dsa_context *ctx, struct task *tsk);
 int dsa_dualcast_multi_task_nodes(struct dsa_context *ctx);
 int dsa_wait_dualcast(struct dsa_context *ctx, struct task *tsk);
 
+int dsa_cr_delta_multi_task_nodes(struct dsa_context *ctx);
+int dsa_wait_cr_delta(struct dsa_context *ctx, struct task *tsk);
+
+int dsa_ap_delta_multi_task_nodes(struct dsa_context *ctx);
+int dsa_wait_ap_delta(struct dsa_context *ctx, struct task *tsk);
+
 void dsa_prep_noop(struct task *tsk);
 void dsa_prep_drain(struct task *tsk);
 void dsa_prep_memcpy(struct task *tsk);
@@ -271,6 +280,10 @@ void dsa_prep_compval(struct task *tsk);
 void dsa_reprep_compval(struct dsa_context *ctx, struct task *tsk);
 void dsa_prep_dualcast(struct task *tsk);
 void dsa_reprep_dualcast(struct dsa_context *ctx, struct task *tsk);
+void dsa_prep_cr_delta(struct task *tsk);
+void dsa_reprep_cr_delta(struct dsa_context *ctx, struct task *tsk);
+void dsa_prep_ap_delta(struct task *tsk);
+void dsa_reprep_ap_delta(struct dsa_context *ctx, struct task *tsk);
 
 int task_result_verify(struct task *tsk, int mismatch_expected);
 int task_result_verify_task_nodes(struct dsa_context *ctx, int mismatch_expected);
@@ -279,6 +292,7 @@ int task_result_verify_memfill(struct task *tsk, int mismatch_expected);
 int task_result_verify_compare(struct task *tsk, int mismatch_expected);
 int task_result_verify_compval(struct task *tsk, int mismatch_expected);
 int task_result_verify_dualcast(struct task *tsk, int mismatch_expected);
+int task_result_verify_ap_delta(struct task *tsk, int mismatch_expected);
 int batch_result_verify(struct batch_task *btsk, int bof);
 
 int alloc_batch_task(struct dsa_context *ctx, unsigned int task_num, int num_itr);
@@ -292,6 +306,8 @@ void dsa_prep_batch_memfill(struct batch_task *btsk);
 void dsa_prep_batch_compare(struct batch_task *btsk);
 void dsa_prep_batch_compval(struct batch_task *btsk);
 void dsa_prep_batch_dualcast(struct batch_task *btsk);
+void dsa_prep_batch_cr_delta(struct batch_task *btsk);
+void dsa_prep_batch_ap_delta(struct batch_task *btsk);
 int dsa_wait_batch(struct batch_task *btsk);
 
 void dsa_free(struct dsa_context *ctx);
diff --git a/test/dsa_test.c b/test/dsa_test.c
index 82f624d..0ba5b6c 100644
--- a/test/dsa_test.c
+++ b/test/dsa_test.c
@@ -94,6 +94,15 @@ static int test_batch(struct dsa_context *ctx, size_t buf_size,
 			case DSA_OPCODE_DUALCAST:
 				dsa_prep_batch_dualcast(btsk_node->btsk);
 				break;
+
+			case DSA_OPCODE_CR_DELTA:
+				dsa_prep_batch_cr_delta(btsk_node->btsk);
+				break;
+
+			case DSA_OPCODE_AP_DELTA:
+				dsa_prep_batch_cr_delta(btsk_node->btsk);
+				break;
+
 			default:
 				err("Unsupported op %#x\n", bopcode);
 				return -EINVAL;
@@ -118,14 +127,52 @@ static int test_batch(struct dsa_context *ctx, size_t buf_size,
 		btsk_node = ctx->multi_btask_node;
 		while (btsk_node) {
 			rc = dsa_wait_batch(btsk_node->btsk);
-			if (rc != DSA_STATUS_OK)
+			if (rc != DSA_STATUS_OK) {
 				err("batch failed stat %d\n", rc);
+				return rc;
+			}
 			btsk_node = btsk_node->next;
 		}
 
+		/* ap delta test. First run cr delta, then run ap delta */
+		if (bopcode == DSA_OPCODE_AP_DELTA) {
+			btsk_node = ctx->multi_btask_node;
+			while (btsk_node) {
+				dsa_prep_batch_ap_delta(btsk_node->btsk);
+				btsk_node = btsk_node->next;
+			}
+
+			btsk_node = ctx->multi_btask_node;
+			while (btsk_node) {
+				dsa_prep_batch(btsk_node->btsk, dflags);
+				dump_sub_desc(btsk_node->btsk);
+				btsk_node = btsk_node->next;
+			}
+
+			btsk_node = ctx->multi_btask_node;
+			while (btsk_node) {
+				dsa_desc_submit(ctx, btsk_node->btsk->core_task->desc);
+				btsk_node = btsk_node->next;
+			}
+
+			btsk_node = ctx->multi_btask_node;
+			while (btsk_node) {
+				rc = dsa_wait_batch(btsk_node->btsk);
+				if (rc != DSA_STATUS_OK) {
+					err("batch failed stat %d\n", rc);
+					return rc;
+				}
+				btsk_node = btsk_node->next;
+			}
+		}
+
 		btsk_node = ctx->multi_btask_node;
 		while (btsk_node) {
 			rc = batch_result_verify(btsk_node->btsk, dflags & IDXD_OP_FLAG_BOF);
+			if (rc != DSA_STATUS_OK) {
+				err("batch verification failed stat %d\n", rc);
+				return rc;
+			}
 			btsk_node = btsk_node->next;
 		}
 
@@ -340,6 +387,76 @@ static int test_memory(struct dsa_context *ctx, size_t buf_size,
 	return rc;
 }
 
+static int test_delta(struct dsa_context *ctx, size_t buf_size,
+		      int tflags, uint32_t opcode, int num_desc)
+{
+	struct task_node *tsk_node;
+	int rc = DSA_STATUS_OK;
+	int itr = num_desc, i = 0, range = 0;
+
+	info("testmemory: opcode %d len %#lx tflags %#x num_desc %ld\n",
+	     opcode, buf_size, tflags, num_desc);
+
+	ctx->is_batch = 0;
+
+	if (ctx->dedicated == ACCFG_WQ_SHARED)
+		range = ctx->threshold;
+	else
+		range = ctx->wq_size - 1;
+
+	while (itr > 0 && rc == DSA_STATUS_OK) {
+		i = (itr < range) ? itr : range;
+		/* Allocate memory to all the task nodes, desc, completion record*/
+		rc = alloc_multiple_tasks(ctx, i);
+		if (rc != DSA_STATUS_OK)
+			return rc;
+
+		/* allocate memory to src and dest buffers and fill in the desc for all the nodes*/
+		tsk_node = ctx->multi_task_node;
+		while (tsk_node) {
+			tsk_node->tsk->xfer_size = buf_size;
+
+			rc = init_task(tsk_node->tsk, tflags, opcode, buf_size);
+			if (rc != DSA_STATUS_OK)
+				return rc;
+
+			tsk_node = tsk_node->next;
+		}
+
+		switch (opcode) {
+		case DSA_OPCODE_CR_DELTA:
+			rc = dsa_cr_delta_multi_task_nodes(ctx);
+			if (rc != DSA_STATUS_OK)
+				return rc;
+			break;
+
+		case DSA_OPCODE_AP_DELTA:
+			rc = dsa_cr_delta_multi_task_nodes(ctx);
+			if (rc != DSA_STATUS_OK)
+				return rc;
+
+			rc = dsa_ap_delta_multi_task_nodes(ctx);
+			if (rc != DSA_STATUS_OK)
+				return rc;
+			break;
+
+		default:
+			err("Unsupported op %#x\n", opcode);
+			return -EINVAL;
+		}
+
+		/* Verification of all the nodes*/
+		rc = task_result_verify_task_nodes(ctx, 0);
+		if (rc != DSA_STATUS_OK)
+			return rc;
+
+		dsa_free_task(ctx);
+		itr = itr - range;
+	}
+
+	return rc;
+}
+
 int main(int argc, char *argv[])
 {
 	struct dsa_context *dsa;
@@ -445,6 +562,13 @@ int main(int argc, char *argv[])
 			goto error;
 		break;
 
+	case DSA_OPCODE_CR_DELTA:
+	case DSA_OPCODE_AP_DELTA:
+		rc = test_delta(dsa, buf_size, tflags, opcode, num_desc);
+		if (rc != DSA_STATUS_OK)
+			goto error;
+		break;
+
 	default:
 		rc = -EINVAL;
 		break;
diff --git a/test/prep.c b/test/prep.c
index c39ff11..3c3701e 100644
--- a/test/prep.c
+++ b/test/prep.c
@@ -318,6 +318,122 @@ void dsa_prep_batch_dualcast(struct batch_task *btsk)
 	}
 }
 
+void dsa_prep_batch_cr_delta(struct batch_task *btsk)
+{
+	int i;
+	struct task *sub_task;
+
+	for (i = 0; i < btsk->task_num; i++) {
+		sub_task = &btsk->sub_tasks[i];
+		if (sub_task->opcode == DSA_OPCODE_AP_DELTA)
+			sub_task->opcode = DSA_OPCODE_CR_DELTA;
+		dsa_prep_desc_common(sub_task->desc, sub_task->opcode,
+				     (uint64_t)(sub_task->src2),
+				     (uint64_t)(sub_task->src1),
+				     sub_task->xfer_size,
+				     sub_task->dflags);
+		sub_task->desc->completion_addr = (uint64_t)(sub_task->comp);
+		sub_task->desc->delta_addr = (uint64_t)sub_task->delta1;
+		sub_task->desc->max_delta_size = 2 * sub_task->xfer_size;
+		sub_task->comp->status = 0;
+	}
+}
+
+void dsa_prep_cr_delta(struct task *tsk)
+{
+	info("preparing descriptor for cr delta\n");
+
+	if (tsk->opcode == DSA_OPCODE_AP_DELTA)
+		tsk->opcode = DSA_OPCODE_CR_DELTA;
+	dsa_prep_desc_common(tsk->desc, tsk->opcode, (uint64_t)(tsk->src2),
+			     (uint64_t)(tsk->src1), tsk->xfer_size, tsk->dflags);
+	tsk->desc->completion_addr = (uint64_t)(tsk->comp);
+	tsk->desc->max_delta_size = 2 * tsk->xfer_size;//need to made configurable
+	tsk->desc->delta_addr = (uint64_t)tsk->delta1;
+	if (tsk->desc->max_delta_size < MIN_DELTA_RECORD_SIZE)
+		tsk->desc->max_delta_size = MIN_DELTA_RECORD_SIZE;
+	tsk->comp->status = 0;
+}
+
+void dsa_reprep_cr_delta(struct dsa_context *ctx, struct task *tsk)
+{
+	struct dsa_completion_record *compl = tsk->comp;
+	struct dsa_hw_desc *hw = tsk->desc;
+
+	info("PF addr %#lx dir %d bc %#x\n",
+	     compl->fault_addr, compl->result,
+	     compl->bytes_completed);
+
+	hw->xfer_size -= compl->bytes_completed;
+
+	hw->src_addr += compl->bytes_completed;
+	hw->dst_addr += compl->bytes_completed;
+
+	resolve_page_fault(compl->fault_addr, compl->status);
+
+	compl->status = 0;
+
+	dsa_desc_submit(ctx, hw);
+}
+
+void dsa_prep_ap_delta(struct task *tsk)
+{
+	info("preparing descriptor for ap delta\n");
+
+	if (tsk->opcode == DSA_OPCODE_CR_DELTA)
+		tsk->opcode = DSA_OPCODE_AP_DELTA;
+	dsa_prep_desc_common(tsk->desc, tsk->opcode, (uint64_t)(tsk->dst1),
+			     (uint64_t)(tsk->delta1), tsk->xfer_size, tsk->dflags);
+	tsk->desc->completion_addr = (uint64_t)(tsk->comp);
+	tsk->desc->delta_addr = 0;
+	tsk->desc->delta_rec_size = tsk->comp->delta_rec_size;
+	tsk->desc->max_delta_size = 0;
+	tsk->comp->status = 0;
+}
+
+void dsa_reprep_ap_delta(struct dsa_context *ctx, struct task *tsk)
+{
+	struct dsa_completion_record *compl = tsk->comp;
+	struct dsa_hw_desc *hw = tsk->desc;
+
+	info("PF addr %#lx dir %d bc %#x\n",
+	     compl->fault_addr, compl->result,
+	     compl->bytes_completed);
+
+	hw->xfer_size -= compl->bytes_completed;
+
+	hw->src_addr += compl->bytes_completed;
+	hw->dst_addr += compl->bytes_completed;
+
+	resolve_page_fault(compl->fault_addr, compl->status);
+
+	compl->status = 0;
+
+	dsa_desc_submit(ctx, hw);
+}
+
+void dsa_prep_batch_ap_delta(struct batch_task *btsk)
+{
+	int i;
+	struct task *sub_task;
+
+	for (i = 0; i < btsk->task_num; i++) {
+		sub_task = &btsk->sub_tasks[i];
+		if (sub_task->opcode == DSA_OPCODE_CR_DELTA)
+			sub_task->opcode = DSA_OPCODE_AP_DELTA;
+		dsa_prep_desc_common(sub_task->desc, sub_task->opcode,
+				     (uint64_t)(sub_task->dst1),
+				     (uint64_t)(sub_task->delta1),
+				     sub_task->xfer_size,
+				     sub_task->dflags);
+		sub_task->desc->completion_addr = (uint64_t)(sub_task->comp);
+		sub_task->desc->delta_addr = 0;
+		sub_task->desc->delta_rec_size = sub_task->comp->delta_rec_size;
+		sub_task->desc->max_delta_size = 0;
+		sub_task->comp->status = 0;
+	}
+}
+
 void dsa_prep_batch(struct batch_task *btsk, unsigned long desc_flags)
 {
 	struct task *ctsk = btsk->core_task;
-- 
2.27.0