dpdk/lib/acl/acl_run_neon.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2015 Cavium, Inc
   3 */
   4
   5#include "acl_run.h"
   6#include "acl_vect.h"
   7
   8struct _neon_acl_const {
   9        rte_xmm_t xmm_shuffle_input;
  10        rte_xmm_t xmm_index_mask;
  11        rte_xmm_t range_base;
  12} neon_acl_const __rte_cache_aligned = {
  13        {
  14                .u32 = {0x00000000, 0x04040404, 0x08080808, 0x0c0c0c0c}
  15        },
  16        {
  17                .u32 = {RTE_ACL_NODE_INDEX, RTE_ACL_NODE_INDEX,
  18                RTE_ACL_NODE_INDEX, RTE_ACL_NODE_INDEX}
  19        },
  20        {
  21                .u32 = {0xffffff00, 0xffffff04, 0xffffff08, 0xffffff0c}
  22        },
  23};
  24
  25/*
  26 * Resolve priority for multiple results (neon version).
  27 * This consists comparing the priority of the current traversal with the
  28 * running set of results for the packet.
  29 * For each result, keep a running array of the result (rule number) and
  30 * its priority for each category.
  31 */
  32static inline void
  33resolve_priority_neon(uint64_t transition, int n, const struct rte_acl_ctx *ctx,
  34                      struct parms *parms,
  35                      const struct rte_acl_match_results *p,
  36                      uint32_t categories)
  37{
  38        uint32_t x;
  39        int32x4_t results, priority, results1, priority1;
  40        uint32x4_t selector;
  41        int32_t *saved_results, *saved_priority;
  42
  43        for (x = 0; x < categories; x += RTE_ACL_RESULTS_MULTIPLIER) {
  44                saved_results = (int32_t *)(&parms[n].cmplt->results[x]);
  45                saved_priority = (int32_t *)(&parms[n].cmplt->priority[x]);
  46
  47                /* get results and priorities for completed trie */
  48                results = vld1q_s32(
  49                        (const int32_t *)&p[transition].results[x]);
  50                priority = vld1q_s32(
  51                        (const int32_t *)&p[transition].priority[x]);
  52
  53                /* if this is not the first completed trie */
  54                if (parms[n].cmplt->count != ctx->num_tries) {
  55                        /* get running best results and their priorities */
  56                        results1 = vld1q_s32(saved_results);
  57                        priority1 = vld1q_s32(saved_priority);
  58
  59                        /* select results that are highest priority */
  60                        selector = vcgtq_s32(priority1, priority);
  61                        results = vbslq_s32(selector, results1, results);
  62                        priority = vbslq_s32(selector, priority1, priority);
  63                }
  64
  65                /* save running best results and their priorities */
  66                vst1q_s32(saved_results, results);
  67                vst1q_s32(saved_priority, priority);
  68        }
  69}
  70
  71/*
  72 * Check for any match in 4 transitions
  73 */
  74static __rte_always_inline uint32_t
  75check_any_match_x4(uint64_t val[])
  76{
  77        return (val[0] | val[1] | val[2] | val[3]) & RTE_ACL_NODE_MATCH;
  78}
  79
  80static __rte_always_inline void
  81acl_match_check_x4(int slot, const struct rte_acl_ctx *ctx, struct parms *parms,
  82                   struct acl_flow_data *flows, uint64_t transitions[])
  83{
  84        while (check_any_match_x4(transitions)) {
  85                transitions[0] = acl_match_check(transitions[0], slot, ctx,
  86                        parms, flows, resolve_priority_neon);
  87                transitions[1] = acl_match_check(transitions[1], slot + 1, ctx,
  88                        parms, flows, resolve_priority_neon);
  89                transitions[2] = acl_match_check(transitions[2], slot + 2, ctx,
  90                        parms, flows, resolve_priority_neon);
  91                transitions[3] = acl_match_check(transitions[3], slot + 3, ctx,
  92                        parms, flows, resolve_priority_neon);
  93        }
  94}
  95
  96/*
  97 * Process 4 transitions (in 2 NEON Q registers) in parallel
  98 */
  99static __rte_always_inline int32x4_t
 100transition4(int32x4_t next_input, const uint64_t *trans, uint64_t transitions[])
 101{
 102        int32x4x2_t tr_hi_lo;
 103        int32x4_t t, in, r;
 104        uint32x4_t index_msk, node_type, addr;
 105        uint32x4_t dfa_msk, mask, quad_ofs, dfa_ofs;
 106
 107        /* Move low 32 into tr_hi_lo.val[0] and high 32 into tr_hi_lo.val[1] */
 108        tr_hi_lo = vld2q_s32((const int32_t *)transitions);
 109
 110        /* Calculate the address (array index) for all 4 transitions. */
 111
 112        index_msk = vld1q_u32((const uint32_t *)&neon_acl_const.xmm_index_mask);
 113
 114        /* Calc node type and node addr */
 115        node_type = vbicq_s32(tr_hi_lo.val[0], index_msk);
 116        addr = vandq_s32(tr_hi_lo.val[0], index_msk);
 117
 118        /* t = 0 */
 119        t = veorq_s32(node_type, node_type);
 120
 121        /* mask for DFA type(0) nodes */
 122        dfa_msk = vceqq_u32(node_type, t);
 123
 124        mask = vld1q_s32((const int32_t *)&neon_acl_const.xmm_shuffle_input);
 125        in = vqtbl1q_u8((uint8x16_t)next_input, (uint8x16_t)mask);
 126
 127        /* DFA calculations. */
 128        r = vshrq_n_u32(in, 30); /* div by 64 */
 129        mask = vld1q_s32((const int32_t *)&neon_acl_const.range_base);
 130        r = vaddq_u8(r, mask);
 131        t = vshrq_n_u32(in, 24);
 132        r = vqtbl1q_u8((uint8x16_t)tr_hi_lo.val[1], (uint8x16_t)r);
 133        dfa_ofs = vsubq_s32(t, r);
 134
 135        /* QUAD/SINGLE calculations. */
 136        t = vcgtq_s8(in, tr_hi_lo.val[1]);
 137        t = vabsq_s8(t);
 138        t = vpaddlq_u8(t);
 139        quad_ofs = vpaddlq_u16(t);
 140
 141        /* blend DFA and QUAD/SINGLE. */
 142        t = vbslq_u8(dfa_msk, dfa_ofs, quad_ofs);
 143
 144        /* calculate address for next transitions */
 145        addr = vaddq_u32(addr, t);
 146
 147        /* Fill next transitions */
 148        transitions[0] = trans[vgetq_lane_u32(addr, 0)];
 149        transitions[1] = trans[vgetq_lane_u32(addr, 1)];
 150        transitions[2] = trans[vgetq_lane_u32(addr, 2)];
 151        transitions[3] = trans[vgetq_lane_u32(addr, 3)];
 152
 153        return vshrq_n_u32(next_input, CHAR_BIT);
 154}
 155
 156/*
 157 * Execute trie traversal with 8 traversals in parallel
 158 */
 159static inline int
 160search_neon_8(const struct rte_acl_ctx *ctx, const uint8_t **data,
 161              uint32_t *results, uint32_t total_packets, uint32_t categories)
 162{
 163        int n;
 164        struct acl_flow_data flows;
 165        uint64_t index_array[8];
 166        struct completion cmplt[8];
 167        struct parms parms[8];
 168        int32x4_t input0, input1;
 169
 170        acl_set_flow(&flows, cmplt, RTE_DIM(cmplt), data, results,
 171                     total_packets, categories, ctx->trans_table);
 172
 173        for (n = 0; n < 8; n++) {
 174                cmplt[n].count = 0;
 175                index_array[n] = acl_start_next_trie(&flows, parms, n, ctx);
 176        }
 177
 178         /* Check for any matches. */
 179        acl_match_check_x4(0, ctx, parms, &flows, &index_array[0]);
 180        acl_match_check_x4(4, ctx, parms, &flows, &index_array[4]);
 181
 182        while (flows.started > 0) {
 183                /* Gather 4 bytes of input data for each stream. */
 184                input0 = vdupq_n_s32(GET_NEXT_4BYTES(parms, 0));
 185                input1 = vdupq_n_s32(GET_NEXT_4BYTES(parms, 4));
 186
 187                input0 = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 1), input0, 1);
 188                input1 = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 5), input1, 1);
 189
 190                input0 = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 2), input0, 2);
 191                input1 = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 6), input1, 2);
 192
 193                input0 = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 3), input0, 3);
 194                input1 = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 7), input1, 3);
 195
 196                /* Process the 4 bytes of input on each stream. */
 197
 198                input0 = transition4(input0, flows.trans, &index_array[0]);
 199                input1 = transition4(input1, flows.trans, &index_array[4]);
 200
 201                input0 = transition4(input0, flows.trans, &index_array[0]);
 202                input1 = transition4(input1, flows.trans, &index_array[4]);
 203
 204                input0 = transition4(input0, flows.trans, &index_array[0]);
 205                input1 = transition4(input1, flows.trans, &index_array[4]);
 206
 207                input0 = transition4(input0, flows.trans, &index_array[0]);
 208                input1 = transition4(input1, flows.trans, &index_array[4]);
 209
 210                 /* Check for any matches. */
 211                acl_match_check_x4(0, ctx, parms, &flows, &index_array[0]);
 212                acl_match_check_x4(4, ctx, parms, &flows, &index_array[4]);
 213        }
 214
 215        return 0;
 216}
 217
 218/*
 219 * Execute trie traversal with 4 traversals in parallel
 220 */
 221static inline int
 222search_neon_4(const struct rte_acl_ctx *ctx, const uint8_t **data,
 223              uint32_t *results, int total_packets, uint32_t categories)
 224{
 225        int n;
 226        struct acl_flow_data flows;
 227        uint64_t index_array[4];
 228        struct completion cmplt[4];
 229        struct parms parms[4];
 230        int32x4_t input;
 231
 232        acl_set_flow(&flows, cmplt, RTE_DIM(cmplt), data, results,
 233                     total_packets, categories, ctx->trans_table);
 234
 235        for (n = 0; n < 4; n++) {
 236                cmplt[n].count = 0;
 237                index_array[n] = acl_start_next_trie(&flows, parms, n, ctx);
 238        }
 239
 240        /* Check for any matches. */
 241        acl_match_check_x4(0, ctx, parms, &flows, index_array);
 242
 243        while (flows.started > 0) {
 244                /* Gather 4 bytes of input data for each stream. */
 245                input = vdupq_n_s32(GET_NEXT_4BYTES(parms, 0));
 246                input = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 1), input, 1);
 247                input = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 2), input, 2);
 248                input = vsetq_lane_s32(GET_NEXT_4BYTES(parms, 3), input, 3);
 249
 250                /* Process the 4 bytes of input on each stream. */
 251                input = transition4(input, flows.trans, index_array);
 252                input = transition4(input, flows.trans, index_array);
 253                input = transition4(input, flows.trans, index_array);
 254                input = transition4(input, flows.trans, index_array);
 255
 256                /* Check for any matches. */
 257                acl_match_check_x4(0, ctx, parms, &flows, index_array);
 258        }
 259
 260        return 0;
 261}
 262