regex/mlx5: check DevX register write
[dpdk.git] / drivers / regex / mlx5 / mlx5_rxp.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2020 Mellanox Technologies, Ltd
3  */
4
5 #include <rte_log.h>
6 #include <rte_errno.h>
7 #include <rte_malloc.h>
8 #include <rte_regexdev.h>
9 #include <rte_regexdev_core.h>
10 #include <rte_regexdev_driver.h>
11
12 #include <mlx5_glue.h>
13 #include <mlx5_devx_cmds.h>
14 #include <mlx5_prm.h>
15 #include <mlx5_common_os.h>
16
17 #include "mlx5_regex.h"
18 #include "mlx5_regex_utils.h"
19 #include "mlx5_rxp_csrs.h"
20 #include "mlx5_rxp.h"
21
22 #define MLX5_REGEX_MAX_MATCHES MLX5_RXP_MAX_MATCHES
23 #define MLX5_REGEX_MAX_PAYLOAD_SIZE MLX5_RXP_MAX_JOB_LENGTH
24 #define MLX5_REGEX_MAX_RULES_PER_GROUP UINT32_MAX
25 #define MLX5_REGEX_MAX_GROUPS MLX5_RXP_MAX_SUBSETS
26
27 /* Private Declarations */
28 static int
29 rxp_poll_csr_for_value(struct ibv_context *ctx, uint32_t *value,
30                        uint32_t address, uint32_t expected_value,
31                        uint32_t expected_mask, uint32_t timeout_ms, uint8_t id);
32 static int
33 mlnx_set_database(struct mlx5_regex_priv *priv, uint8_t id, uint8_t db_to_use);
34 static int
35 mlnx_resume_database(struct mlx5_regex_priv *priv, uint8_t id);
36 static int
37 mlnx_update_database(struct mlx5_regex_priv *priv, uint8_t id);
38 static int
39 program_rxp_rules(struct mlx5_regex_priv *priv,
40                   struct mlx5_rxp_ctl_rules_pgm *rules, uint8_t id);
41 static int
42 rxp_init_eng(struct mlx5_regex_priv *priv, uint8_t id);
43 static int
44 write_private_rules(struct mlx5_regex_priv *priv,
45                     struct mlx5_rxp_ctl_rules_pgm *rules,
46                     uint8_t id);
47 static int
48 write_shared_rules(struct mlx5_regex_priv *priv,
49                    struct mlx5_rxp_ctl_rules_pgm *rules, uint32_t count,
50                    uint8_t db_to_program);
51 static int
52 rxp_db_setup(struct mlx5_regex_priv *priv);
53 static void
54 rxp_dump_csrs(struct ibv_context *ctx, uint8_t id);
55 static int
56 rxp_write_rules_via_cp(struct ibv_context *ctx,
57                        struct mlx5_rxp_rof_entry *rules,
58                        int count, uint8_t id);
59 static int
60 rxp_flush_rules(struct ibv_context *ctx, struct mlx5_rxp_rof_entry *rules,
61                 int count, uint8_t id);
62 static int
63 rxp_start_engine(struct ibv_context *ctx, uint8_t id);
64 static int
65 rxp_stop_engine(struct ibv_context *ctx, uint8_t id);
66
67 static void __rte_unused
68 rxp_dump_csrs(struct ibv_context *ctx __rte_unused, uint8_t id __rte_unused)
69 {
70         uint32_t reg, i;
71
72         /* Main CSRs*/
73         for (i = 0; i < MLX5_RXP_CSR_NUM_ENTRIES; i++) {
74                 if (mlx5_devx_regex_register_read(ctx, id,
75                                                   (MLX5_RXP_CSR_WIDTH * i) +
76                                                   MLX5_RXP_CSR_BASE_ADDRESS,
77                                                   &reg)) {
78                         DRV_LOG(ERR, "Failed to read Main CSRs Engine %d!", id);
79                         return;
80                 }
81                 DRV_LOG(DEBUG, "RXP Main CSRs (Eng%d) register (%d): %08x",
82                         id, i, reg);
83         }
84         /* RTRU CSRs*/
85         for (i = 0; i < MLX5_RXP_CSR_NUM_ENTRIES; i++) {
86                 if (mlx5_devx_regex_register_read(ctx, id,
87                                                   (MLX5_RXP_CSR_WIDTH * i) +
88                                                  MLX5_RXP_RTRU_CSR_BASE_ADDRESS,
89                                                   &reg)) {
90                         DRV_LOG(ERR, "Failed to read RTRU CSRs Engine %d!", id);
91                         return;
92                 }
93                 DRV_LOG(DEBUG, "RXP RTRU CSRs (Eng%d) register (%d): %08x",
94                         id, i, reg);
95         }
96         /* STAT CSRs */
97         for (i = 0; i < MLX5_RXP_CSR_NUM_ENTRIES; i++) {
98                 if (mlx5_devx_regex_register_read(ctx, id,
99                                                   (MLX5_RXP_CSR_WIDTH * i) +
100                                                 MLX5_RXP_STATS_CSR_BASE_ADDRESS,
101                                                   &reg)) {
102                         DRV_LOG(ERR, "Failed to read STAT CSRs Engine %d!", id);
103                         return;
104                 }
105                 DRV_LOG(DEBUG, "RXP STAT CSRs (Eng%d) register (%d): %08x",
106                         id, i, reg);
107         }
108 }
109
110 int
111 mlx5_regex_info_get(struct rte_regexdev *dev __rte_unused,
112                     struct rte_regexdev_info *info)
113 {
114         info->max_matches = MLX5_REGEX_MAX_MATCHES;
115         info->max_payload_size = MLX5_REGEX_MAX_PAYLOAD_SIZE;
116         info->max_rules_per_group = MLX5_REGEX_MAX_RULES_PER_GROUP;
117         info->max_groups = MLX5_REGEX_MAX_GROUPS;
118         info->max_queue_pairs = 1;
119         info->regexdev_capa = RTE_REGEXDEV_SUPP_PCRE_GREEDY_F |
120                               RTE_REGEXDEV_CAPA_QUEUE_PAIR_OOS_F;
121         info->rule_flags = 0;
122         info->max_queue_pairs = 10;
123         return 0;
124 }
125
126 /**
127  * Actual writing of RXP instructions to RXP via CSRs.
128  */
129 static int
130 rxp_write_rules_via_cp(struct ibv_context *ctx,
131                        struct mlx5_rxp_rof_entry *rules,
132                        int count, uint8_t id)
133 {
134         int i, ret = 0;
135         uint32_t tmp;
136
137         for (i = 0; i < count; i++) {
138                 tmp = (uint32_t)rules[i].value;
139                 ret |= mlx5_devx_regex_register_write(ctx, id,
140                                                       MLX5_RXP_RTRU_CSR_DATA_0,
141                                                       tmp);
142                 tmp = (uint32_t)(rules[i].value >> 32);
143                 ret |= mlx5_devx_regex_register_write(ctx, id,
144                                                       MLX5_RXP_RTRU_CSR_DATA_0 +
145                                                       MLX5_RXP_CSR_WIDTH, tmp);
146                 tmp = rules[i].addr;
147                 ret |= mlx5_devx_regex_register_write(ctx, id,
148                                                       MLX5_RXP_RTRU_CSR_ADDR,
149                                                       tmp);
150                 if (ret) {
151                         DRV_LOG(ERR, "Failed to copy instructions to RXP.");
152                         return -1;
153                 }
154         }
155         DRV_LOG(DEBUG, "Written %d instructions", count);
156         return 0;
157 }
158
159 static int
160 rxp_flush_rules(struct ibv_context *ctx, struct mlx5_rxp_rof_entry *rules,
161                 int count, uint8_t id)
162 {
163         uint32_t val, fifo_depth;
164         int ret;
165
166         ret = rxp_write_rules_via_cp(ctx, rules, count, id);
167         if (ret < 0) {
168                 DRV_LOG(ERR, "Failed to write rules via CSRs.");
169                 return -1;
170         }
171         ret = mlx5_devx_regex_register_read(ctx, id,
172                                             MLX5_RXP_RTRU_CSR_CAPABILITY,
173                                             &fifo_depth);
174         if (ret) {
175                 DRV_LOG(ERR, "CSR read failed!");
176                 return -1;
177         }
178         ret = rxp_poll_csr_for_value(ctx, &val, MLX5_RXP_RTRU_CSR_FIFO_STAT,
179                                      count, ~0,
180                                      MLX5_RXP_POLL_CSR_FOR_VALUE_TIMEOUT, id);
181         if (ret < 0) {
182                 DRV_LOG(ERR, "Rules not rx by RXP: credit: %d, depth: %d", val,
183                         fifo_depth);
184                 return ret;
185         }
186         DRV_LOG(DEBUG, "RTRU FIFO depth: 0x%x", fifo_depth);
187         DRV_LOG(DEBUG, "Rules flush took %d cycles.", ret);
188         ret = mlx5_devx_regex_register_read(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,
189                                             &val);
190         if (ret) {
191                 DRV_LOG(ERR, "CSR read failed!");
192                 return -1;
193         }
194         val |= MLX5_RXP_RTRU_CSR_CTRL_GO;
195         ret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,
196                                              val);
197         if (ret) {
198                 DRV_LOG(ERR, "CSR write failed!");
199                 return -1;
200         }
201         ret = rxp_poll_csr_for_value(ctx, &val, MLX5_RXP_RTRU_CSR_STATUS,
202                                      MLX5_RXP_RTRU_CSR_STATUS_UPDATE_DONE,
203                                      MLX5_RXP_RTRU_CSR_STATUS_UPDATE_DONE,
204                                      MLX5_RXP_POLL_CSR_FOR_VALUE_TIMEOUT, id);
205         if (ret < 0) {
206                 DRV_LOG(ERR, "Rules update timeout: 0x%08X", val);
207                 return ret;
208         }
209         DRV_LOG(DEBUG, "Rules update took %d cycles", ret);
210         if (mlx5_devx_regex_register_read(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,
211                                           &val)) {
212                 DRV_LOG(ERR, "CSR read failed!");
213                 return -1;
214         }
215         val &= ~(MLX5_RXP_RTRU_CSR_CTRL_GO);
216         if (mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,
217                                            val)) {
218                 DRV_LOG(ERR, "CSR write write failed!");
219                 return -1;
220         }
221
222         DRV_LOG(DEBUG, "RXP Flush rules finished.");
223         return 0;
224 }
225
226 static int
227 rxp_poll_csr_for_value(struct ibv_context *ctx, uint32_t *value,
228                        uint32_t address, uint32_t expected_value,
229                        uint32_t expected_mask, uint32_t timeout_ms, uint8_t id)
230 {
231         unsigned int i;
232         int ret;
233
234         ret = -EBUSY;
235         for (i = 0; i < timeout_ms; i++) {
236                 if (mlx5_devx_regex_register_read(ctx, id, address, value))
237                         return -1;
238                 if ((*value & expected_mask) == expected_value) {
239                         ret = 0;
240                         break;
241                 }
242                 rte_delay_us(1000);
243         }
244         return ret;
245 }
246
247 static int
248 rxp_start_engine(struct ibv_context *ctx, uint8_t id)
249 {
250         uint32_t ctrl;
251         int ret;
252
253         ret = mlx5_devx_regex_register_read(ctx, id, MLX5_RXP_CSR_CTRL, &ctrl);
254         if (ret)
255                 return ret;
256         ctrl |= MLX5_RXP_CSR_CTRL_GO;
257         ctrl |= MLX5_RXP_CSR_CTRL_DISABLE_L2C;
258         ret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_CTRL, ctrl);
259         return ret;
260 }
261
262 static int
263 rxp_stop_engine(struct ibv_context *ctx, uint8_t id)
264 {
265         uint32_t ctrl;
266         int ret;
267
268         ret = mlx5_devx_regex_register_read(ctx, id, MLX5_RXP_CSR_CTRL, &ctrl);
269         if (ret)
270                 return ret;
271         ctrl &= ~MLX5_RXP_CSR_CTRL_GO;
272         ret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_CTRL, ctrl);
273         return ret;
274 }
275
276 static int
277 rxp_init_rtru(struct ibv_context *ctx, uint8_t id, uint32_t init_bits)
278 {
279         uint32_t ctrl_value;
280         uint32_t poll_value;
281         uint32_t expected_value;
282         uint32_t expected_mask;
283         int ret;
284
285         /* Read the rtru ctrl CSR. */
286         ret = mlx5_devx_regex_register_read(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,
287                                             &ctrl_value);
288         if (ret)
289                 return -1;
290         /* Clear any previous init modes. */
291         ctrl_value &= ~(MLX5_RXP_RTRU_CSR_CTRL_INIT_MODE_MASK);
292         if (ctrl_value & MLX5_RXP_RTRU_CSR_CTRL_INIT) {
293                 ctrl_value &= ~(MLX5_RXP_RTRU_CSR_CTRL_INIT);
294                 mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,
295                                                ctrl_value);
296         }
297         /* Set the init_mode bits in the rtru ctrl CSR. */
298         ctrl_value |= init_bits;
299         mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,
300                                        ctrl_value);
301         /* Need to sleep for a short period after pulsing the rtru init bit. */
302         rte_delay_us(20000);
303         /* Poll the rtru status CSR until all the init done bits are set. */
304         DRV_LOG(DEBUG, "waiting for RXP rule memory to complete init");
305         /* Set the init bit in the rtru ctrl CSR. */
306         ctrl_value |= MLX5_RXP_RTRU_CSR_CTRL_INIT;
307         mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,
308                                        ctrl_value);
309         /* Clear the init bit in the rtru ctrl CSR */
310         ctrl_value &= ~MLX5_RXP_RTRU_CSR_CTRL_INIT;
311         mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,
312                                        ctrl_value);
313         /* Check that the following bits are set in the RTRU_CSR. */
314         if (init_bits == MLX5_RXP_RTRU_CSR_CTRL_INIT_MODE_L1_L2) {
315                 /* Must be incremental mode */
316                 expected_value = MLX5_RXP_RTRU_CSR_STATUS_L1C_INIT_DONE |
317                         MLX5_RXP_RTRU_CSR_STATUS_L2C_INIT_DONE;
318         } else {
319                 expected_value = MLX5_RXP_RTRU_CSR_STATUS_IM_INIT_DONE |
320                         MLX5_RXP_RTRU_CSR_STATUS_L1C_INIT_DONE |
321                         MLX5_RXP_RTRU_CSR_STATUS_L2C_INIT_DONE;
322         }
323         expected_mask = expected_value;
324         ret = rxp_poll_csr_for_value(ctx, &poll_value,
325                                      MLX5_RXP_RTRU_CSR_STATUS,
326                                      expected_value, expected_mask,
327                                      MLX5_RXP_CSR_STATUS_TRIAL_TIMEOUT, id);
328         if (ret)
329                 return ret;
330         DRV_LOG(DEBUG, "rule memory initialise: 0x%08X", poll_value);
331         /* Clear the init bit in the rtru ctrl CSR */
332         ctrl_value &= ~(MLX5_RXP_RTRU_CSR_CTRL_INIT);
333         mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,
334                                        ctrl_value);
335         return 0;
336 }
337
338 static int
339 rxp_parse_rof(const char *buf, uint32_t len,
340               struct mlx5_rxp_ctl_rules_pgm **rules)
341 {
342         static const char del[] = "\n\r";
343         char *line;
344         char *tmp;
345         char *cur_pos;
346         uint32_t lines = 0;
347         uint32_t entries;
348         struct mlx5_rxp_rof_entry *curentry;
349
350         tmp = rte_malloc("", len, 0);
351         if (!tmp)
352                 return -ENOMEM;
353         memcpy(tmp, buf, len);
354         line = strtok(tmp, del);
355         while (line) {
356                 if (line[0] != '#' && line[0] != '\0')
357                         lines++;
358                 line = strtok(NULL, del);
359         }
360         *rules = rte_malloc("", lines * sizeof(*curentry) + sizeof(**rules), 0);
361         if (!(*rules)) {
362                 rte_free(tmp);
363                 return -ENOMEM;
364         }
365         memset(*rules, 0, lines * sizeof(curentry) + sizeof(**rules));
366         curentry = (*rules)->rules;
367         (*rules)->hdr.cmd = MLX5_RXP_CTL_RULES_PGM;
368         entries = 0;
369         memcpy(tmp, buf, len);
370         line = strtok(tmp, del);
371         while (line) {
372                 if (line[0] == '#' || line[0] == '\0') {
373                         line = strtok(NULL, del);
374                         continue;
375                 }
376                 curentry->type = strtoul(line, &cur_pos, 10);
377                 if (cur_pos == line || cur_pos[0] != ',')
378                         goto parse_error;
379                 cur_pos++;
380                 curentry->addr = strtoul(cur_pos, &cur_pos, 16);
381                 if (cur_pos[0] != ',')
382                         goto parse_error;
383                 cur_pos++;
384                 curentry->value = strtoull(cur_pos, &cur_pos, 16);
385                 if (cur_pos[0] != '\0' && cur_pos[0] != '\n')
386                         goto parse_error;
387                 curentry++;
388                 entries++;
389                 if (entries > lines)
390                         goto parse_error;
391                 line = strtok(NULL, del);
392         }
393         (*rules)->count = entries;
394         (*rules)->hdr.len = entries * sizeof(*curentry) + sizeof(**rules);
395         rte_free(tmp);
396         return 0;
397 parse_error:
398         rte_free(tmp);
399         if (*rules)
400                 rte_free(*rules);
401         return -EINVAL;
402 }
403
404 static int
405 mlnx_set_database(struct mlx5_regex_priv *priv, uint8_t id, uint8_t db_to_use)
406 {
407         int ret;
408         uint32_t umem_id;
409
410         ret = mlx5_devx_regex_database_stop(priv->ctx, id);
411         if (ret < 0) {
412                 DRV_LOG(ERR, "stop engine failed!");
413                 return ret;
414         }
415         umem_id = mlx5_os_get_umem_id(priv->db[db_to_use].umem.umem);
416         ret = mlx5_devx_regex_database_program(priv->ctx, id, umem_id, 0);
417         if (ret < 0) {
418                 DRV_LOG(ERR, "program db failed!");
419                 return ret;
420         }
421         return 0;
422 }
423
424 static int
425 mlnx_resume_database(struct mlx5_regex_priv *priv, uint8_t id)
426 {
427         mlx5_devx_regex_database_resume(priv->ctx, id);
428         return 0;
429 }
430
431 /*
432  * Assign db memory for RXP programming.
433  */
434 static int
435 mlnx_update_database(struct mlx5_regex_priv *priv, uint8_t id)
436 {
437         unsigned int i;
438         uint8_t db_free = MLX5_RXP_DB_NOT_ASSIGNED;
439         uint8_t eng_assigned = MLX5_RXP_DB_NOT_ASSIGNED;
440
441         /* Check which database rxp_eng is currently located if any? */
442         for (i = 0; i < (priv->nb_engines + MLX5_RXP_EM_COUNT);
443              i++) {
444                 if (priv->db[i].db_assigned_to_eng_num == id) {
445                         eng_assigned = i;
446                         break;
447                 }
448         }
449         /*
450          * If private mode then, we can keep the same db ptr as RXP will be
451          * programming EM itself if necessary, however need to see if
452          * programmed yet.
453          */
454         if ((priv->prog_mode == MLX5_RXP_PRIVATE_PROG_MODE) &&
455             (eng_assigned != MLX5_RXP_DB_NOT_ASSIGNED))
456                 return eng_assigned;
457         /* Check for inactive db memory to use. */
458         for (i = 0; i < (priv->nb_engines + MLX5_RXP_EM_COUNT);
459              i++) {
460                 if (priv->db[i].active == true)
461                         continue; /* Already in use, so skip db. */
462                 /* Set this db to active now as free to use. */
463                 priv->db[i].active = true;
464                 /* Now unassign last db index in use by RXP Eng. */
465                 if (eng_assigned != MLX5_RXP_DB_NOT_ASSIGNED) {
466                         priv->db[eng_assigned].active = false;
467                         priv->db[eng_assigned].db_assigned_to_eng_num =
468                                 MLX5_RXP_DB_NOT_ASSIGNED;
469
470                         /* Set all DB memory to 0's before setting up DB. */
471                         memset(priv->db[i].ptr, 0x00, MLX5_MAX_DB_SIZE);
472                 }
473                 /* Now reassign new db index with RXP Engine. */
474                 priv->db[i].db_assigned_to_eng_num = id;
475                 db_free = i;
476                 break;
477         }
478         if (db_free == MLX5_RXP_DB_NOT_ASSIGNED)
479                 return -1;
480         return db_free;
481 }
482
483 /*
484  * Program RXP instruction db to RXP engine/s.
485  */
486 static int
487 program_rxp_rules(struct mlx5_regex_priv *priv,
488                   struct mlx5_rxp_ctl_rules_pgm *rules, uint8_t id)
489 {
490         int ret, db_free;
491         uint32_t rule_cnt;
492
493         rule_cnt = rules->count;
494         db_free = mlnx_update_database(priv, id);
495         if (db_free < 0) {
496                 DRV_LOG(ERR, "Failed to setup db memory!");
497                 return db_free;
498         }
499         if (priv->prog_mode == MLX5_RXP_PRIVATE_PROG_MODE) {
500                 /* Register early to ensure RXP writes to EM use valid addr. */
501                 ret = mlnx_set_database(priv, id, db_free);
502                 if (ret < 0) {
503                         DRV_LOG(ERR, "Failed to register db memory!");
504                         return ret;
505                 }
506         }
507         ret = write_private_rules(priv, rules, id);
508         if (ret < 0) {
509                 DRV_LOG(ERR, "Failed to write rules!");
510                 return ret;
511         }
512         if (priv->prog_mode == MLX5_RXP_SHARED_PROG_MODE) {
513                 /* Write external rules directly to EM. */
514                 rules->count = rule_cnt;
515                /* Now write external instructions to EM. */
516                 ret = write_shared_rules(priv, rules, rules->hdr.len, db_free);
517                 if (ret < 0) {
518                         DRV_LOG(ERR, "Failed to write EM rules!");
519                         return ret;
520                 }
521                 ret = mlnx_set_database(priv, id, db_free);
522                 if (ret < 0) {
523                         DRV_LOG(ERR, "Failed to register db memory!");
524                         return ret;
525                 }
526         }
527         ret = mlnx_resume_database(priv, id);
528         if (ret < 0) {
529                 DRV_LOG(ERR, "Failed to resume engine!");
530                 return ret;
531         }
532         DRV_LOG(DEBUG, "Programmed RXP Engine %d\n", id);
533         rules->count = rule_cnt;
534         return 0;
535 }
536
537 static int
538 rxp_init_eng(struct mlx5_regex_priv *priv, uint8_t id)
539 {
540         uint32_t ctrl;
541         uint32_t reg;
542         struct ibv_context *ctx = priv->ctx;
543         int ret;
544
545         ret = mlx5_devx_regex_register_read(ctx, id, MLX5_RXP_CSR_CTRL, &ctrl);
546         if (ret)
547                 return ret;
548         if (ctrl & MLX5_RXP_CSR_CTRL_INIT) {
549                 ctrl &= ~MLX5_RXP_CSR_CTRL_INIT;
550                 ret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_CTRL,
551                                                      ctrl);
552                 if (ret)
553                         return ret;
554         }
555         ctrl |= MLX5_RXP_CSR_CTRL_INIT;
556         ret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_CTRL, ctrl);
557         if (ret)
558                 return ret;
559         ctrl &= ~MLX5_RXP_CSR_CTRL_INIT;
560         ret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_CTRL, ctrl);
561         if (ret)
562                 return ret;
563         rte_delay_us(20000);
564         ret = rxp_poll_csr_for_value(ctx, &ctrl, MLX5_RXP_CSR_STATUS,
565                                      MLX5_RXP_CSR_STATUS_INIT_DONE,
566                                      MLX5_RXP_CSR_STATUS_INIT_DONE,
567                                      MLX5_RXP_CSR_STATUS_TRIAL_TIMEOUT, id);
568         if (ret)
569                 return ret;
570         ret = mlx5_devx_regex_register_read(ctx, id, MLX5_RXP_CSR_CTRL, &ctrl);
571         if (ret)
572                 return ret;
573         ctrl &= ~MLX5_RXP_CSR_CTRL_INIT;
574         ret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_CTRL,
575                                              ctrl);
576         if (ret)
577                 return ret;
578         ret = rxp_init_rtru(ctx, id, MLX5_RXP_RTRU_CSR_CTRL_INIT_MODE_IM_L1_L2);
579         if (ret)
580                 return ret;
581         ret = mlx5_devx_regex_register_read(ctx, id, MLX5_RXP_CSR_CAPABILITY_5,
582                                             &reg);
583         if (ret)
584                 return ret;
585         DRV_LOG(DEBUG, "max matches: %d, DDOS threshold: %d", reg >> 16,
586                 reg & 0xffff);
587         if ((reg >> 16) >= priv->nb_max_matches)
588                 ret = mlx5_devx_regex_register_write(ctx, id,
589                                                      MLX5_RXP_CSR_MAX_MATCH,
590                                                      priv->nb_max_matches);
591         else
592                 ret = mlx5_devx_regex_register_write(ctx, id,
593                                                      MLX5_RXP_CSR_MAX_MATCH,
594                                                      (reg >> 16));
595         ret |= mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_MAX_PREFIX,
596                                          (reg & 0xFFFF));
597         ret |= mlx5_devx_regex_register_write(ctx, id,
598                                               MLX5_RXP_CSR_MAX_LATENCY, 0);
599         ret |= mlx5_devx_regex_register_write(ctx, id,
600                                               MLX5_RXP_CSR_MAX_PRI_THREAD, 0);
601         return ret;
602 }
603
604 static int
605 write_private_rules(struct mlx5_regex_priv *priv,
606                     struct mlx5_rxp_ctl_rules_pgm *rules,
607                     uint8_t id)
608 {
609         unsigned int pending;
610         uint32_t block, reg, val, rule_cnt, rule_offset, rtru_max_num_entries;
611         int ret = 1;
612
613         if (priv->prog_mode == MLX5_RXP_MODE_NOT_DEFINED)
614                 return -EINVAL;
615         if (rules->hdr.len == 0 || rules->hdr.cmd < MLX5_RXP_CTL_RULES_PGM ||
616                                    rules->hdr.cmd > MLX5_RXP_CTL_RULES_PGM_INCR)
617                 return -EINVAL;
618         /* For a non-incremental rules program, re-init the RXP. */
619         if (rules->hdr.cmd == MLX5_RXP_CTL_RULES_PGM) {
620                 ret = rxp_init_eng(priv, id);
621                 if (ret < 0)
622                         return ret;
623         } else if (rules->hdr.cmd == MLX5_RXP_CTL_RULES_PGM_INCR) {
624                 /* Flush RXP L1 and L2 cache by using MODE_L1_L2. */
625                 ret = rxp_init_rtru(priv->ctx, id,
626                                     MLX5_RXP_RTRU_CSR_CTRL_INIT_MODE_L1_L2);
627                 if (ret < 0)
628                         return ret;
629         }
630         if (rules->count == 0)
631                 return -EINVAL;
632         /* Confirm the RXP is initialised. */
633         if (mlx5_devx_regex_register_read(priv->ctx, id,
634                                             MLX5_RXP_CSR_STATUS, &val)) {
635                 DRV_LOG(ERR, "Failed to read from RXP!");
636                 return -ENODEV;
637         }
638         if (!(val & MLX5_RXP_CSR_STATUS_INIT_DONE)) {
639                 DRV_LOG(ERR, "RXP not initialised...");
640                 return -EBUSY;
641         }
642         /* Get the RTRU maximum number of entries allowed. */
643         if (mlx5_devx_regex_register_read(priv->ctx, id,
644                         MLX5_RXP_RTRU_CSR_CAPABILITY, &rtru_max_num_entries)) {
645                 DRV_LOG(ERR, "Failed to read RTRU capability!");
646                 return -ENODEV;
647         }
648         rtru_max_num_entries = (rtru_max_num_entries & 0x00FF);
649         rule_cnt = 0;
650         pending = 0;
651         while (rules->count > 0) {
652                 if ((rules->rules[rule_cnt].type == MLX5_RXP_ROF_ENTRY_INST) ||
653                     (rules->rules[rule_cnt].type == MLX5_RXP_ROF_ENTRY_IM) ||
654                     (rules->rules[rule_cnt].type == MLX5_RXP_ROF_ENTRY_EM)) {
655                         if ((rules->rules[rule_cnt].type ==
656                              MLX5_RXP_ROF_ENTRY_EM) &&
657                             (priv->prog_mode == MLX5_RXP_SHARED_PROG_MODE)) {
658                                 /* Skip EM rules programming. */
659                                 if (pending > 0) {
660                                         /* Flush any rules that are pending. */
661                                         rule_offset = (rule_cnt - pending);
662                                         ret = rxp_flush_rules(priv->ctx,
663                                                 &rules->rules[rule_offset],
664                                                 pending, id);
665                                         if (ret < 0) {
666                                                 DRV_LOG(ERR, "Flushing rules.");
667                                                 return -ENODEV;
668                                         }
669                                         pending = 0;
670                                 }
671                                 rule_cnt++;
672                         } else {
673                                 pending++;
674                                 rule_cnt++;
675                                 /*
676                                  * If parsing the last rule, or if reached the
677                                  * maximum number of rules for this batch, then
678                                  * flush the rules batch to the RXP.
679                                  */
680                                 if ((rules->count == 1) ||
681                                     (pending == rtru_max_num_entries)) {
682                                         rule_offset = (rule_cnt - pending);
683                                         ret = rxp_flush_rules(priv->ctx,
684                                                 &rules->rules[rule_offset],
685                                                 pending, id);
686                                         if (ret < 0) {
687                                                 DRV_LOG(ERR, "Flushing rules.");
688                                                 return -ENODEV;
689                                         }
690                                         pending = 0;
691                                 }
692                         }
693                 } else if ((rules->rules[rule_cnt].type ==
694                                 MLX5_RXP_ROF_ENTRY_EQ) ||
695                          (rules->rules[rule_cnt].type ==
696                                 MLX5_RXP_ROF_ENTRY_GTE) ||
697                          (rules->rules[rule_cnt].type ==
698                                 MLX5_RXP_ROF_ENTRY_LTE) ||
699                          (rules->rules[rule_cnt].type ==
700                                 MLX5_RXP_ROF_ENTRY_CHECKSUM) ||
701                          (rules->rules[rule_cnt].type ==
702                                 MLX5_RXP_ROF_ENTRY_CHECKSUM_EX_EM)) {
703                         if (pending) {
704                                 /* Flush rules before checking reg values. */
705                                 rule_offset = (rule_cnt - pending);
706                                 ret = rxp_flush_rules(priv->ctx,
707                                         &rules->rules[rule_offset],
708                                         pending, id);
709                                 if (ret < 0) {
710                                         DRV_LOG(ERR, "Failed to flush rules.");
711                                         return -ENODEV;
712                                 }
713                         }
714                         block = (rules->rules[rule_cnt].addr >> 16) & 0xFFFF;
715                         if (block == 0)
716                                 reg = MLX5_RXP_CSR_BASE_ADDRESS;
717                         else if (block == 1)
718                                 reg = MLX5_RXP_RTRU_CSR_BASE_ADDRESS;
719                         else {
720                                 DRV_LOG(ERR, "Invalid ROF register 0x%08X!",
721                                         rules->rules[rule_cnt].addr);
722                                 return -EINVAL;
723                         }
724                         reg += (rules->rules[rule_cnt].addr & 0xFFFF) *
725                                 MLX5_RXP_CSR_WIDTH;
726                         ret = mlx5_devx_regex_register_read(priv->ctx, id,
727                                                             reg, &val);
728                         if (ret) {
729                                 DRV_LOG(ERR, "RXP CSR read failed!");
730                                 return ret;
731                         }
732                         if ((priv->prog_mode == MLX5_RXP_SHARED_PROG_MODE) &&
733                             ((rules->rules[rule_cnt].type ==
734                             MLX5_RXP_ROF_ENTRY_CHECKSUM_EX_EM) &&
735                             (val != rules->rules[rule_cnt].value))) {
736                                 DRV_LOG(ERR, "Unexpected value for register:");
737                                 DRV_LOG(ERR, "reg %x" PRIu32 " got %x" PRIu32,
738                                         rules->rules[rule_cnt].addr, val);
739                                 DRV_LOG(ERR, "expected %" PRIx64 ".",
740                                         rules->rules[rule_cnt].value);
741                                         return -EINVAL;
742                         } else if ((priv->prog_mode ==
743                                  MLX5_RXP_PRIVATE_PROG_MODE) &&
744                                  (rules->rules[rule_cnt].type ==
745                                  MLX5_RXP_ROF_ENTRY_CHECKSUM) &&
746                                  (val != rules->rules[rule_cnt].value)) {
747                                 DRV_LOG(ERR, "Unexpected value for register:");
748                                 DRV_LOG(ERR, "reg %x" PRIu32 " got %x" PRIu32,
749                                         rules->rules[rule_cnt].addr, val);
750                                 DRV_LOG(ERR, "expected %" PRIx64 ".",
751                                         rules->rules[rule_cnt].value);
752                                 return -EINVAL;
753                         } else if ((rules->rules[rule_cnt].type ==
754                                         MLX5_RXP_ROF_ENTRY_EQ) &&
755                                   (val != rules->rules[rule_cnt].value)) {
756                                 DRV_LOG(ERR, "Unexpected value for register:");
757                                 DRV_LOG(ERR, "reg %x" PRIu32 " got %x" PRIu32,
758                                         rules->rules[rule_cnt].addr, val);
759                                 DRV_LOG(ERR, "expected %" PRIx64 ".",
760                                         rules->rules[rule_cnt].value);
761                                         return -EINVAL;
762                         } else if ((rules->rules[rule_cnt].type ==
763                                         MLX5_RXP_ROF_ENTRY_GTE) &&
764                                  (val < rules->rules[rule_cnt].value)) {
765                                 DRV_LOG(ERR, "Unexpected value reg 0x%08X,",
766                                         rules->rules[rule_cnt].addr);
767                                 DRV_LOG(ERR, "got %X, expected >= %" PRIx64 ".",
768                                         val, rules->rules[rule_cnt].value);
769                                 return -EINVAL;
770                         } else if ((rules->rules[rule_cnt].type ==
771                                         MLX5_RXP_ROF_ENTRY_LTE) &&
772                                  (val > rules->rules[rule_cnt].value)) {
773                                 DRV_LOG(ERR, "Unexpected value reg 0x%08X,",
774                                         rules->rules[rule_cnt].addr);
775                                 DRV_LOG(ERR, "got %08X expected <= %" PRIx64,
776                                         val, rules->rules[rule_cnt].value);
777                                 return -EINVAL;
778                         }
779                         rule_cnt++;
780                         pending = 0;
781                 } else {
782                         DRV_LOG(ERR, "Error: Invalid rule type %d!",
783                                 rules->rules[rule_cnt].type);
784                         return -EINVAL;
785                 }
786                 rules->count--;
787         }
788         return ret;
789 }
790
791 /*
792  * Shared memory programming mode, here all external db instructions are written
793  * to EM via the host.
794  */
795 static int
796 write_shared_rules(struct mlx5_regex_priv *priv,
797                    struct mlx5_rxp_ctl_rules_pgm *rules, uint32_t count,
798                    uint8_t db_to_program)
799 {
800         uint32_t rule_cnt, rof_rule_addr;
801         uint64_t tmp_write_swap[4];
802
803         if (priv->prog_mode == MLX5_RXP_MODE_NOT_DEFINED)
804                 return -EINVAL;
805         if ((rules->count == 0) || (count == 0))
806                 return -EINVAL;
807         rule_cnt = 0;
808         /*
809          * Note the following section of code carries out a 32byte swap of
810          * instruction to coincide with HW 32byte swap. This may need removed
811          * in new variants of this programming function!
812          */
813         while (rule_cnt < rules->count) {
814                 if ((rules->rules[rule_cnt].type == MLX5_RXP_ROF_ENTRY_EM) &&
815                     (priv->prog_mode == MLX5_RXP_SHARED_PROG_MODE)) {
816                         /*
817                          * Note there are always blocks of 8 instructions for
818                          * 7's written sequentially. However there is no
819                          * guarantee that all blocks are sequential!
820                          */
821                         if (count >= (rule_cnt + MLX5_RXP_INST_BLOCK_SIZE)) {
822                                 /*
823                                  * Ensure memory write not exceeding boundary
824                                  * Check essential to ensure 0x10000 offset
825                                  * accounted for!
826                                  */
827                                 if ((uint8_t *)((uint8_t *)
828                                     priv->db[db_to_program].ptr +
829                                     ((rules->rules[rule_cnt + 7].addr <<
830                                     MLX5_RXP_INST_OFFSET))) >=
831                                     ((uint8_t *)((uint8_t *)
832                                     priv->db[db_to_program].ptr +
833                                     MLX5_MAX_DB_SIZE))) {
834                                         DRV_LOG(ERR, "DB exceeded memory!");
835                                         return -ENODEV;
836                                 }
837                                 /*
838                                  * Rule address Offset to align with RXP
839                                  * external instruction offset.
840                                  */
841                                 rof_rule_addr = (rules->rules[rule_cnt].addr <<
842                                                  MLX5_RXP_INST_OFFSET);
843                                 /* 32 byte instruction swap (sw work around)! */
844                                 tmp_write_swap[0] = le64toh(
845                                         rules->rules[(rule_cnt + 4)].value);
846                                 tmp_write_swap[1] = le64toh(
847                                         rules->rules[(rule_cnt + 5)].value);
848                                 tmp_write_swap[2] = le64toh(
849                                         rules->rules[(rule_cnt + 6)].value);
850                                 tmp_write_swap[3] = le64toh(
851                                         rules->rules[(rule_cnt + 7)].value);
852                                 /* Write only 4 of the 8 instructions. */
853                                 memcpy((uint8_t *)((uint8_t *)
854                                        priv->db[db_to_program].ptr +
855                                        rof_rule_addr), &tmp_write_swap,
856                                        (sizeof(uint64_t) * 4));
857                                 /* Write 1st 4 rules of block after last 4. */
858                                 rof_rule_addr = (rules->rules[
859                                                  (rule_cnt + 4)].addr <<
860                                                  MLX5_RXP_INST_OFFSET);
861                                 tmp_write_swap[0] = le64toh(
862                                         rules->rules[(rule_cnt + 0)].value);
863                                 tmp_write_swap[1] = le64toh(
864                                         rules->rules[(rule_cnt + 1)].value);
865                                 tmp_write_swap[2] = le64toh(
866                                         rules->rules[(rule_cnt + 2)].value);
867                                 tmp_write_swap[3] = le64toh(
868                                         rules->rules[(rule_cnt + 3)].value);
869                                 memcpy((uint8_t *)((uint8_t *)
870                                        priv->db[db_to_program].ptr +
871                                        rof_rule_addr), &tmp_write_swap,
872                                        (sizeof(uint64_t) * 4));
873                         } else
874                                 return -1;
875                         /* Fast forward as already handled block of 8. */
876                         rule_cnt += MLX5_RXP_INST_BLOCK_SIZE;
877                 } else
878                         rule_cnt++; /* Must be something other than EM rule. */
879         }
880         return 0;
881 }
882
883 static int
884 rxp_db_setup(struct mlx5_regex_priv *priv)
885 {
886         int ret;
887         uint8_t i;
888
889         /* Setup database memories for both RXP engines + reprogram memory. */
890         for (i = 0; i < (priv->nb_engines + MLX5_RXP_EM_COUNT); i++) {
891                 priv->db[i].ptr = rte_malloc("", MLX5_MAX_DB_SIZE, 0);
892                 if (!priv->db[i].ptr) {
893                         DRV_LOG(ERR, "Failed to alloc db memory!");
894                         ret = ENODEV;
895                         goto tidyup_error;
896                 }
897                 /* Register the memory. */
898                 priv->db[i].umem.umem = mlx5_glue->devx_umem_reg(priv->ctx,
899                                                         priv->db[i].ptr,
900                                                         MLX5_MAX_DB_SIZE, 7);
901                 if (!priv->db[i].umem.umem) {
902                         DRV_LOG(ERR, "Failed to register memory!");
903                         ret = ENODEV;
904                         goto tidyup_error;
905                 }
906                 /* Ensure set all DB memory to 0's before setting up DB. */
907                 memset(priv->db[i].ptr, 0x00, MLX5_MAX_DB_SIZE);
908                 /* No data currently in database. */
909                 priv->db[i].len = 0;
910                 priv->db[i].active = false;
911                 priv->db[i].db_assigned_to_eng_num = MLX5_RXP_DB_NOT_ASSIGNED;
912         }
913         return 0;
914 tidyup_error:
915         for (i = 0; i < (priv->nb_engines + MLX5_RXP_EM_COUNT); i++) {
916                 if (priv->db[i].ptr)
917                         rte_free(priv->db[i].ptr);
918                 if (priv->db[i].umem.umem)
919                         mlx5_glue->devx_umem_dereg(priv->db[i].umem.umem);
920         }
921         return -ret;
922 }
923
924 int
925 mlx5_regex_rules_db_import(struct rte_regexdev *dev,
926                      const char *rule_db, uint32_t rule_db_len)
927 {
928         struct mlx5_regex_priv *priv = dev->data->dev_private;
929         struct mlx5_rxp_ctl_rules_pgm *rules = NULL;
930         uint32_t id;
931         int ret;
932
933         if (priv->prog_mode == MLX5_RXP_MODE_NOT_DEFINED) {
934                 DRV_LOG(ERR, "RXP programming mode not set!");
935                 return -1;
936         }
937         if (rule_db == NULL) {
938                 DRV_LOG(ERR, "Database empty!");
939                 return -ENODEV;
940         }
941         if (rule_db_len == 0)
942                 return -EINVAL;
943         ret = rxp_parse_rof(rule_db, rule_db_len, &rules);
944         if (ret) {
945                 DRV_LOG(ERR, "Can't parse ROF file.");
946                 return ret;
947         }
948         /* Need to ensure RXP not busy before stop! */
949         for (id = 0; id < priv->nb_engines; id++) {
950                 ret = rxp_stop_engine(priv->ctx, id);
951                 if (ret) {
952                         DRV_LOG(ERR, "Can't stop engine.");
953                         ret = -ENODEV;
954                         goto tidyup_error;
955                 }
956                 ret = program_rxp_rules(priv, rules, id);
957                 if (ret < 0) {
958                         DRV_LOG(ERR, "Failed to program rxp rules.");
959                         ret = -ENODEV;
960                         goto tidyup_error;
961                 }
962                 ret = rxp_start_engine(priv->ctx, id);
963                 if (ret) {
964                         DRV_LOG(ERR, "Can't start engine.");
965                         ret = -ENODEV;
966                         goto tidyup_error;
967                 }
968         }
969         rte_free(rules);
970         return 0;
971 tidyup_error:
972         rte_free(rules);
973         return ret;
974 }
975
976 int
977 mlx5_regex_configure(struct rte_regexdev *dev,
978                      const struct rte_regexdev_config *cfg)
979 {
980         struct mlx5_regex_priv *priv = dev->data->dev_private;
981         int ret;
982
983         if (priv->prog_mode == MLX5_RXP_MODE_NOT_DEFINED)
984                 return -1;
985         priv->nb_queues = cfg->nb_queue_pairs;
986         dev->data->dev_conf.nb_queue_pairs = priv->nb_queues;
987         priv->qps = rte_zmalloc(NULL, sizeof(struct mlx5_regex_qp) *
988                                 priv->nb_queues, 0);
989         if (!priv->nb_queues) {
990                 DRV_LOG(ERR, "can't allocate qps memory");
991                 rte_errno = ENOMEM;
992                 return -rte_errno;
993         }
994         priv->nb_max_matches = cfg->nb_max_matches;
995         /* Setup rxp db memories. */
996         if (rxp_db_setup(priv)) {
997                 DRV_LOG(ERR, "Failed to setup RXP db memory");
998                 rte_errno = ENOMEM;
999                 return -rte_errno;
1000         }
1001         if (cfg->rule_db != NULL) {
1002                 ret = mlx5_regex_rules_db_import(dev, cfg->rule_db,
1003                                                  cfg->rule_db_len);
1004                 if (ret < 0) {
1005                         DRV_LOG(ERR, "Failed to program rxp rules.");
1006                         rte_errno = ENODEV;
1007                         goto configure_error;
1008                 }
1009         } else
1010                 DRV_LOG(DEBUG, "Regex config without rules programming!");
1011         return 0;
1012 configure_error:
1013         if (priv->qps)
1014                 rte_free(priv->qps);
1015         return -rte_errno;
1016 }