xref: /dpdk/lib/acl/acl_run_neon.h (revision e9fd1ebf981f361844aea9ec94e17f4bda5e1479)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2015 Cavium, Inc
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson 
5*e9fd1ebfSTyler Retzlaff #include <stdalign.h>
6*e9fd1ebfSTyler Retzlaff 
799a2dd95SBruce Richardson #include "acl_run.h"
899a2dd95SBruce Richardson #include "acl_vect.h"
999a2dd95SBruce Richardson 
10*e9fd1ebfSTyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) struct _neon_acl_const {
1199a2dd95SBruce Richardson 	rte_xmm_t xmm_shuffle_input;
1299a2dd95SBruce Richardson 	rte_xmm_t xmm_index_mask;
1399a2dd95SBruce Richardson 	rte_xmm_t range_base;
14*e9fd1ebfSTyler Retzlaff } neon_acl_const = {
1599a2dd95SBruce Richardson 	{
1699a2dd95SBruce Richardson 		.u32 = {0x00000000, 0x04040404, 0x08080808, 0x0c0c0c0c}
1799a2dd95SBruce Richardson 	},
1899a2dd95SBruce Richardson 	{
1999a2dd95SBruce Richardson 		.u32 = {RTE_ACL_NODE_INDEX, RTE_ACL_NODE_INDEX,
2099a2dd95SBruce Richardson 		RTE_ACL_NODE_INDEX, RTE_ACL_NODE_INDEX}
2199a2dd95SBruce Richardson 	},
2299a2dd95SBruce Richardson 	{
2399a2dd95SBruce Richardson 		.u32 = {0xffffff00, 0xffffff04, 0xffffff08, 0xffffff0c}
2499a2dd95SBruce Richardson 	},
2599a2dd95SBruce Richardson };
2699a2dd95SBruce Richardson 
2799a2dd95SBruce Richardson /*
2899a2dd95SBruce Richardson  * Resolve priority for multiple results (neon version).
2999a2dd95SBruce Richardson  * This consists comparing the priority of the current traversal with the
3099a2dd95SBruce Richardson  * running set of results for the packet.
3199a2dd95SBruce Richardson  * For each result, keep a running array of the result (rule number) and
3299a2dd95SBruce Richardson  * its priority for each category.
3399a2dd95SBruce Richardson  */
3499a2dd95SBruce Richardson static inline void
resolve_priority_neon(uint64_t transition,int n,const struct rte_acl_ctx * ctx,struct parms * parms,const struct rte_acl_match_results * p,uint32_t categories)3599a2dd95SBruce Richardson resolve_priority_neon(uint64_t transition, int n, const struct rte_acl_ctx *ctx,
3699a2dd95SBruce Richardson 		      struct parms *parms,
3799a2dd95SBruce Richardson 		      const struct rte_acl_match_results *p,
3899a2dd95SBruce Richardson 		      uint32_t categories)
3999a2dd95SBruce Richardson {
4099a2dd95SBruce Richardson 	uint32_t x;
4199a2dd95SBruce Richardson 	int32x4_t results, priority, results1, priority1;
4299a2dd95SBruce Richardson 	uint32x4_t selector;
4399a2dd95SBruce Richardson 	int32_t *saved_results, *saved_priority;
4499a2dd95SBruce Richardson 
4599a2dd95SBruce Richardson 	for (x = 0; x < categories; x += RTE_ACL_RESULTS_MULTIPLIER) {
4699a2dd95SBruce Richardson 		saved_results = (int32_t *)(&parms[n].cmplt->results[x]);
4799a2dd95SBruce Richardson 		saved_priority = (int32_t *)(&parms[n].cmplt->priority[x]);
4899a2dd95SBruce Richardson 
4999a2dd95SBruce Richardson 		/* get results and priorities for completed trie */
5099a2dd95SBruce Richardson 		results = vld1q_s32(
5199a2dd95SBruce Richardson 			(const int32_t *)&p[transition].results[x]);
5299a2dd95SBruce Richardson 		priority = vld1q_s32(
5399a2dd95SBruce Richardson 			(const int32_t *)&p[transition].priority[x]);
5499a2dd95SBruce Richardson 
5599a2dd95SBruce Richardson 		/* if this is not the first completed trie */
5699a2dd95SBruce Richardson 		if (parms[n].cmplt->count != ctx->num_tries) {
5799a2dd95SBruce Richardson 			/* get running best results and their priorities */
5899a2dd95SBruce Richardson 			results1 = vld1q_s32(saved_results);
5999a2dd95SBruce Richardson 			priority1 = vld1q_s32(saved_priority);
6099a2dd95SBruce Richardson 
6199a2dd95SBruce Richardson 			/* select results that are highest priority */
6299a2dd95SBruce Richardson 			selector = vcgtq_s32(priority1, priority);
6399a2dd95SBruce Richardson 			results = vbslq_s32(selector, results1, results);
6499a2dd95SBruce Richardson 			priority = vbslq_s32(selector, priority1, priority);
6599a2dd95SBruce Richardson 		}
6699a2dd95SBruce Richardson 
6799a2dd95SBruce Richardson 		/* save running best results and their priorities */
6899a2dd95SBruce Richardson 		vst1q_s32(saved_results, results);
6999a2dd95SBruce Richardson 		vst1q_s32(saved_priority, priority);
7099a2dd95SBruce Richardson 	}
7199a2dd95SBruce Richardson }
7299a2dd95SBruce Richardson 
7399a2dd95SBruce Richardson /*
7499a2dd95SBruce Richardson  * Check for any match in 4 transitions
7599a2dd95SBruce Richardson  */
7699a2dd95SBruce Richardson static __rte_always_inline uint32_t
check_any_match_x4(uint64_t val[])7799a2dd95SBruce Richardson check_any_match_x4(uint64_t val[])
7899a2dd95SBruce Richardson {
7999a2dd95SBruce Richardson 	return (val[0] | val[1] | val[2] | val[3]) & RTE_ACL_NODE_MATCH;
8099a2dd95SBruce Richardson }
8199a2dd95SBruce Richardson 
8299a2dd95SBruce Richardson static __rte_always_inline void
acl_match_check_x4(int slot,const struct rte_acl_ctx * ctx,struct parms * parms,struct acl_flow_data * flows,uint64_t transitions[])8399a2dd95SBruce Richardson acl_match_check_x4(int slot, const struct rte_acl_ctx *ctx, struct parms *parms,
8499a2dd95SBruce Richardson 		   struct acl_flow_data *flows, uint64_t transitions[])
8599a2dd95SBruce Richardson {
8699a2dd95SBruce Richardson 	while (check_any_match_x4(transitions)) {
8799a2dd95SBruce Richardson 		transitions[0] = acl_match_check(transitions[0], slot, ctx,
8899a2dd95SBruce Richardson 			parms, flows, resolve_priority_neon);
8999a2dd95SBruce Richardson 		transitions[1] = acl_match_check(transitions[1], slot + 1, ctx,
9099a2dd95SBruce Richardson 			parms, flows, resolve_priority_neon);
9199a2dd95SBruce Richardson 		transitions[2] = acl_match_check(transitions[2], slot + 2, ctx,
9299a2dd95SBruce Richardson 			parms, flows, resolve_priority_neon);
9399a2dd95SBruce Richardson 		transitions[3] = acl_match_check(transitions[3], slot + 3, ctx,
9499a2dd95SBruce Richardson 			parms, flows, resolve_priority_neon);
9599a2dd95SBruce Richardson 	}
9699a2dd95SBruce Richardson }
9799a2dd95SBruce Richardson 
9899a2dd95SBruce Richardson /*
9999a2dd95SBruce Richardson  * Process 4 transitions (in 2 NEON Q registers) in parallel
10099a2dd95SBruce Richardson  */
10199a2dd95SBruce Richardson static __rte_always_inline int32x4_t
transition4(int32x4_t next_input,const uint64_t * trans,uint64_t transitions[])10299a2dd95SBruce Richardson transition4(int32x4_t next_input, const uint64_t *trans, uint64_t transitions[])
10399a2dd95SBruce Richardson {
10499a2dd95SBruce Richardson 	int32x4x2_t tr_hi_lo;
10599a2dd95SBruce Richardson 	int32x4_t t, in, r;
10699a2dd95SBruce Richardson 	uint32x4_t index_msk, node_type, addr;
10799a2dd95SBruce Richardson 	uint32x4_t dfa_msk, mask, quad_ofs, dfa_ofs;
10899a2dd95SBruce Richardson 
10999a2dd95SBruce Richardson 	/* Move low 32 into tr_hi_lo.val[0] and high 32 into tr_hi_lo.val[1] */
11099a2dd95SBruce Richardson 	tr_hi_lo = vld2q_s32((const int32_t *)transitions);
11199a2dd95SBruce Richardson 
11299a2dd95SBruce Richardson 	/* Calculate the address (array index) for all 4 transitions. */
11399a2dd95SBruce Richardson 
11499a2dd95SBruce Richardson 	index_msk = vld1q_u32((const uint32_t *)&neon_acl_const.xmm_index_mask);
11599a2dd95SBruce Richardson 
11699a2dd95SBruce Richardson 	/* Calc node type and node addr */
11799a2dd95SBruce Richardson 	node_type = vbicq_s32(tr_hi_lo.val[0], index_msk);
11899a2dd95SBruce Richardson 	addr = vandq_s32(tr_hi_lo.val[0], index_msk);
11999a2dd95SBruce Richardson 
12099a2dd95SBruce Richardson 	/* t = 0 */
12199a2dd95SBruce Richardson 	t = veorq_s32(node_type, node_type);
12299a2dd95SBruce Richardson 
12399a2dd95SBruce Richardson 	/* mask for DFA type(0) nodes */
12499a2dd95SBruce Richardson 	dfa_msk = vceqq_u32(node_type, t);
12599a2dd95SBruce Richardson 
12699a2dd95SBruce Richardson 	mask = vld1q_s32((const int32_t *)&neon_acl_const.xmm_shuffle_input);
12799a2dd95SBruce Richardson 	in = vqtbl1q_u8((uint8x16_t)next_input, (uint8x16_t)mask);
12899a2dd95SBruce Richardson 
12999a2dd95SBruce Richardson 	/* DFA calculations. */
13099a2dd95SBruce Richardson 	r = vshrq_n_u32(in, 30); /* div by 64 */
13199a2dd95SBruce Richardson 	mask = vld1q_s32((const int32_t *)&neon_acl_const.range_base);
13299a2dd95SBruce Richardson 	r = vaddq_u8(r, mask);
13399a2dd95SBruce Richardson 	t = vshrq_n_u32(in, 24);
13499a2dd95SBruce Richardson 	r = vqtbl1q_u8((uint8x16_t)tr_hi_lo.val[1], (uint8x16_t)r);
13599a2dd95SBruce Richardson 	dfa_ofs = vsubq_s32(t, r);
13699a2dd95SBruce Richardson 
13799a2dd95SBruce Richardson 	/* QUAD/SINGLE calculations. */
13899a2dd95SBruce Richardson 	t = vcgtq_s8(in, tr_hi_lo.val[1]);
13999a2dd95SBruce Richardson 	t = vabsq_s8(t);
14099a2dd95SBruce Richardson 	t = vpaddlq_u8(t);
14199a2dd95SBruce Richardson 	quad_ofs = vpaddlq_u16(t);
14299a2dd95SBruce Richardson 
14399a2dd95SBruce Richardson 	/* blend DFA and QUAD/SINGLE. */
14499a2dd95SBruce Richardson 	t = vbslq_u8(dfa_msk, dfa_ofs, quad_ofs);
14599a2dd95SBruce Richardson 
14699a2dd95SBruce Richardson 	/* calculate address for next transitions */
14799a2dd95SBruce Richardson 	addr = vaddq_u32(addr, t);
14899a2dd95SBruce Richardson 
14999a2dd95SBruce Richardson 	/* Fill next transitions */
15099a2dd95SBruce Richardson 	transitions[0] = trans[vgetq_lane_u32(addr, 0)];
15199a2dd95SBruce Richardson 	transitions[1] = trans[vgetq_lane_u32(addr, 1)];
15299a2dd95SBruce Richardson 	transitions[2] = trans[vgetq_lane_u32(addr, 2)];
15399a2dd95SBruce Richardson 	transitions[3] = trans[vgetq_lane_u32(addr, 3)];
15499a2dd95SBruce Richardson 
15599a2dd95SBruce Richardson 	return vshrq_n_u32(next_input, CHAR_BIT);
15699a2dd95SBruce Richardson }
15799a2dd95SBruce Richardson 
15899a2dd95SBruce Richardson /*
15999a2dd95SBruce Richardson  * Execute trie traversal with 8 traversals in parallel
16099a2dd95SBruce Richardson  */
16199a2dd95SBruce Richardson static inline int
search_neon_8(const struct rte_acl_ctx * ctx,const uint8_t ** data,uint32_t * results,uint32_t total_packets,uint32_t categories)16299a2dd95SBruce Richardson search_neon_8(const struct rte_acl_ctx *ctx, const uint8_t **data,
16399a2dd95SBruce Richardson 	      uint32_t *results, uint32_t total_packets, uint32_t categories)
16499a2dd95SBruce Richardson {
16599a2dd95SBruce Richardson 	int n;
16699a2dd95SBruce Richardson 	struct acl_flow_data flows;
16799a2dd95SBruce Richardson 	uint64_t index_array[8];
16899a2dd95SBruce Richardson 	struct completion cmplt[8];
16999a2dd95SBruce Richardson 	struct parms parms[8];
17099a2dd95SBruce Richardson 	int32x4_t input0, input1;
17199a2dd95SBruce Richardson 
17299a2dd95SBruce Richardson 	acl_set_flow(&flows, cmplt, RTE_DIM(cmplt), data, results,
17399a2dd95SBruce Richardson 		     total_packets, categories, ctx->trans_table);
17499a2dd95SBruce Richardson 
17599a2dd95SBruce Richardson 	for (n = 0; n < 8; n++) {
17699a2dd95SBruce Richardson 		cmplt[n].count = 0;
17799a2dd95SBruce Richardson 		index_array[n] = acl_start_next_trie(&flows, parms, n, ctx);
17899a2dd95SBruce Richardson 	}
17999a2dd95SBruce Richardson 
18099a2dd95SBruce Richardson 	 /* Check for any matches. */
18199a2dd95SBruce Richardson 	acl_match_check_x4(0, ctx, parms, &flows, &index_array[0]);
18299a2dd95SBruce Richardson 	acl_match_check_x4(4, ctx, parms, &flows, &index_array[4]);
18399a2dd95SBruce Richardson 
18499a2dd95SBruce Richardson 	while (flows.started > 0) {
18599a2dd95SBruce Richardson 		/* Gather 4 bytes of input data for each stream. */
18699a2dd95SBruce Richardson 		input0 = vdupq_n_s32(GET_NEXT_4BYTES(parms, 0));
18799a2dd95SBruce Richardson 		input1 = vdupq_n_s32(GET_NEXT_4BYTES(parms, 4));
18899a2dd95SBruce Richardson 
18999a2dd95SBruce Richardson 		input0 = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 1), input0, 1);
19099a2dd95SBruce Richardson 		input1 = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 5), input1, 1);
19199a2dd95SBruce Richardson 
19299a2dd95SBruce Richardson 		input0 = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 2), input0, 2);
19399a2dd95SBruce Richardson 		input1 = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 6), input1, 2);
19499a2dd95SBruce Richardson 
19599a2dd95SBruce Richardson 		input0 = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 3), input0, 3);
19699a2dd95SBruce Richardson 		input1 = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 7), input1, 3);
19799a2dd95SBruce Richardson 
19899a2dd95SBruce Richardson 		/* Process the 4 bytes of input on each stream. */
19999a2dd95SBruce Richardson 
20099a2dd95SBruce Richardson 		input0 = transition4(input0, flows.trans, &index_array[0]);
20199a2dd95SBruce Richardson 		input1 = transition4(input1, flows.trans, &index_array[4]);
20299a2dd95SBruce Richardson 
20399a2dd95SBruce Richardson 		input0 = transition4(input0, flows.trans, &index_array[0]);
20499a2dd95SBruce Richardson 		input1 = transition4(input1, flows.trans, &index_array[4]);
20599a2dd95SBruce Richardson 
20699a2dd95SBruce Richardson 		input0 = transition4(input0, flows.trans, &index_array[0]);
20799a2dd95SBruce Richardson 		input1 = transition4(input1, flows.trans, &index_array[4]);
20899a2dd95SBruce Richardson 
20999a2dd95SBruce Richardson 		input0 = transition4(input0, flows.trans, &index_array[0]);
21099a2dd95SBruce Richardson 		input1 = transition4(input1, flows.trans, &index_array[4]);
21199a2dd95SBruce Richardson 
21299a2dd95SBruce Richardson 		 /* Check for any matches. */
21399a2dd95SBruce Richardson 		acl_match_check_x4(0, ctx, parms, &flows, &index_array[0]);
21499a2dd95SBruce Richardson 		acl_match_check_x4(4, ctx, parms, &flows, &index_array[4]);
21599a2dd95SBruce Richardson 	}
21699a2dd95SBruce Richardson 
21799a2dd95SBruce Richardson 	return 0;
21899a2dd95SBruce Richardson }
21999a2dd95SBruce Richardson 
22099a2dd95SBruce Richardson /*
22199a2dd95SBruce Richardson  * Execute trie traversal with 4 traversals in parallel
22299a2dd95SBruce Richardson  */
22399a2dd95SBruce Richardson static inline int
search_neon_4(const struct rte_acl_ctx * ctx,const uint8_t ** data,uint32_t * results,int total_packets,uint32_t categories)22499a2dd95SBruce Richardson search_neon_4(const struct rte_acl_ctx *ctx, const uint8_t **data,
22599a2dd95SBruce Richardson 	      uint32_t *results, int total_packets, uint32_t categories)
22699a2dd95SBruce Richardson {
22799a2dd95SBruce Richardson 	int n;
22899a2dd95SBruce Richardson 	struct acl_flow_data flows;
22999a2dd95SBruce Richardson 	uint64_t index_array[4];
23099a2dd95SBruce Richardson 	struct completion cmplt[4];
23199a2dd95SBruce Richardson 	struct parms parms[4];
23299a2dd95SBruce Richardson 	int32x4_t input;
23399a2dd95SBruce Richardson 
23499a2dd95SBruce Richardson 	acl_set_flow(&flows, cmplt, RTE_DIM(cmplt), data, results,
23599a2dd95SBruce Richardson 		     total_packets, categories, ctx->trans_table);
23699a2dd95SBruce Richardson 
23799a2dd95SBruce Richardson 	for (n = 0; n < 4; n++) {
23899a2dd95SBruce Richardson 		cmplt[n].count = 0;
23999a2dd95SBruce Richardson 		index_array[n] = acl_start_next_trie(&flows, parms, n, ctx);
24099a2dd95SBruce Richardson 	}
24199a2dd95SBruce Richardson 
24299a2dd95SBruce Richardson 	/* Check for any matches. */
24399a2dd95SBruce Richardson 	acl_match_check_x4(0, ctx, parms, &flows, index_array);
24499a2dd95SBruce Richardson 
24599a2dd95SBruce Richardson 	while (flows.started > 0) {
24699a2dd95SBruce Richardson 		/* Gather 4 bytes of input data for each stream. */
24799a2dd95SBruce Richardson 		input = vdupq_n_s32(GET_NEXT_4BYTES(parms, 0));
24899a2dd95SBruce Richardson 		input = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 1), input, 1);
24999a2dd95SBruce Richardson 		input = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 2), input, 2);
25099a2dd95SBruce Richardson 		input = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 3), input, 3);
25199a2dd95SBruce Richardson 
25299a2dd95SBruce Richardson 		/* Process the 4 bytes of input on each stream. */
25399a2dd95SBruce Richardson 		input = transition4(input, flows.trans, index_array);
25499a2dd95SBruce Richardson 		input = transition4(input, flows.trans, index_array);
25599a2dd95SBruce Richardson 		input = transition4(input, flows.trans, index_array);
25699a2dd95SBruce Richardson 		input = transition4(input, flows.trans, index_array);
25799a2dd95SBruce Richardson 
25899a2dd95SBruce Richardson 		/* Check for any matches. */
25999a2dd95SBruce Richardson 		acl_match_check_x4(0, ctx, parms, &flows, index_array);
26099a2dd95SBruce Richardson 	}
26199a2dd95SBruce Richardson 
26299a2dd95SBruce Richardson 	return 0;
26399a2dd95SBruce Richardson }
264