regex/mlx5: support configuration
[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
16 #include "mlx5_regex.h"
17 #include "mlx5_regex_utils.h"
18 #include "mlx5_rxp_csrs.h"
19
20 #define MLX5_REGEX_MAX_MATCHES 255
21 #define MLX5_REGEX_MAX_PAYLOAD_SIZE UINT16_MAX
22 #define MLX5_REGEX_MAX_RULES_PER_GROUP UINT16_MAX
23 #define MLX5_REGEX_MAX_GROUPS UINT16_MAX
24
25 int
26 mlx5_regex_info_get(struct rte_regexdev *dev __rte_unused,
27                     struct rte_regexdev_info *info)
28 {
29         info->max_matches = MLX5_REGEX_MAX_MATCHES;
30         info->max_payload_size = MLX5_REGEX_MAX_PAYLOAD_SIZE;
31         info->max_rules_per_group = MLX5_REGEX_MAX_RULES_PER_GROUP;
32         info->max_groups = MLX5_REGEX_MAX_GROUPS;
33         info->regexdev_capa = RTE_REGEXDEV_SUPP_PCRE_GREEDY_F;
34         info->rule_flags = 0;
35         return 0;
36 }
37
38 static int
39 rxp_poll_csr_for_value(struct ibv_context *ctx, uint32_t *value,
40                        uint32_t address, uint32_t expected_value,
41                        uint32_t expected_mask, uint32_t timeout_ms, uint8_t id)
42 {
43         unsigned int i;
44         int ret;
45
46         ret = -EBUSY;
47         for (i = 0; i < timeout_ms; i++) {
48                 if (mlx5_devx_regex_register_read(ctx, id, address, value))
49                         return -1;
50
51                 if ((*value & expected_mask) == expected_value) {
52                         ret = 0;
53                         break;
54                 }
55                 rte_delay_us(1000);
56         }
57         return ret;
58 }
59
60 static int
61 rxp_start_engine(struct ibv_context *ctx, uint8_t id)
62 {
63         uint32_t ctrl;
64         int ret;
65
66         ret = mlx5_devx_regex_register_read(ctx, id, MLX5_RXP_CSR_CTRL, &ctrl);
67         if (ret)
68                 return ret;
69         ctrl |= MLX5_RXP_CSR_CTRL_GO;
70         ret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_CTRL, ctrl);
71         return ret;
72 }
73
74 static int
75 rxp_stop_engine(struct ibv_context *ctx, uint8_t id)
76 {
77         uint32_t ctrl;
78         int ret;
79
80         ret = mlx5_devx_regex_register_read(ctx, id, MLX5_RXP_CSR_CTRL, &ctrl);
81         if (ret)
82                 return ret;
83         ctrl &= ~MLX5_RXP_CSR_CTRL_GO;
84         ret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_CTRL, ctrl);
85         return ret;
86 }
87
88 static int
89 rxp_init_rtru(struct ibv_context *ctx, uint8_t id, uint32_t init_bits)
90 {
91         uint32_t ctrl_value;
92         uint32_t poll_value;
93         uint32_t expected_value;
94         uint32_t expected_mask;
95         int ret = 0;
96
97         /* Read the rtru ctrl CSR. */
98         ret = mlx5_devx_regex_register_read(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,
99                                             &ctrl_value);
100         if (ret)
101                 return -1;
102         /* Clear any previous init modes. */
103         ctrl_value &= ~(MLX5_RXP_RTRU_CSR_CTRL_INIT_MODE_MASK);
104         if (ctrl_value & MLX5_RXP_RTRU_CSR_CTRL_INIT) {
105                 ctrl_value &= ~(MLX5_RXP_RTRU_CSR_CTRL_INIT);
106                 mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,
107                                                ctrl_value);
108         }
109         /* Set the init_mode bits in the rtru ctrl CSR. */
110         ctrl_value |= init_bits;
111         mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,
112                                        ctrl_value);
113         /* Need to sleep for a short period after pulsing the rtru init bit. */
114         rte_delay_us(20000);
115         /* Poll the rtru status CSR until all the init done bits are set. */
116         DRV_LOG(DEBUG, "waiting for RXP rule memory to complete init");
117         /* Set the init bit in the rtru ctrl CSR. */
118         ctrl_value |= MLX5_RXP_RTRU_CSR_CTRL_INIT;
119         mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,
120                                        ctrl_value);
121         /* Clear the init bit in the rtru ctrl CSR */
122         ctrl_value &= ~MLX5_RXP_RTRU_CSR_CTRL_INIT;
123         mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,
124                                        ctrl_value);
125         /* Check that the following bits are set in the RTRU_CSR. */
126         if (init_bits == MLX5_RXP_RTRU_CSR_CTRL_INIT_MODE_L1_L2) {
127                 /* Must be incremental mode */
128                 expected_value = MLX5_RXP_RTRU_CSR_STATUS_L1C_INIT_DONE |
129                         MLX5_RXP_RTRU_CSR_STATUS_L2C_INIT_DONE;
130         } else {
131                 expected_value = MLX5_RXP_RTRU_CSR_STATUS_IM_INIT_DONE |
132                         MLX5_RXP_RTRU_CSR_STATUS_L1C_INIT_DONE |
133                         MLX5_RXP_RTRU_CSR_STATUS_L2C_INIT_DONE;
134         }
135         expected_mask = expected_value;
136         ret = rxp_poll_csr_for_value(ctx, &poll_value,
137                                      MLX5_RXP_RTRU_CSR_STATUS,
138                                      expected_value, expected_mask,
139                                      MLX5_RXP_CSR_STATUS_TRIAL_TIMEOUT, id);
140         if (ret)
141                 return ret;
142         DRV_LOG(DEBUG, "rule memory initialise: 0x%08X", poll_value);
143         /* Clear the init bit in the rtru ctrl CSR */
144         ctrl_value &= ~(MLX5_RXP_RTRU_CSR_CTRL_INIT);
145         mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_RTRU_CSR_CTRL,
146                                        ctrl_value);
147         return 0;
148 }
149
150 static int
151 rxp_init(struct mlx5_regex_priv *priv, uint8_t id)
152 {
153         uint32_t ctrl;
154         uint32_t reg;
155         struct ibv_context *ctx = priv->ctx;
156         int ret;
157
158         ret = mlx5_devx_regex_register_read(ctx, id, MLX5_RXP_CSR_CTRL, &ctrl);
159         if (ret)
160                 return ret;
161         if (ctrl & MLX5_RXP_CSR_CTRL_INIT) {
162                 ctrl &= ~MLX5_RXP_CSR_CTRL_INIT;
163                 ret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_CTRL,
164                                                      ctrl);
165                 if (ret)
166                         return ret;
167         }
168         ctrl |= MLX5_RXP_CSR_CTRL_INIT;
169         ret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_CTRL, ctrl);
170         if (ret)
171                 return ret;
172         ctrl &= ~MLX5_RXP_CSR_CTRL_INIT;
173         ret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_CTRL, ctrl);
174         rte_delay_us(20000);
175
176         ret = rxp_poll_csr_for_value(ctx, &ctrl, MLX5_RXP_CSR_STATUS,
177                                      MLX5_RXP_CSR_STATUS_INIT_DONE,
178                                      MLX5_RXP_CSR_STATUS_INIT_DONE,
179                                      MLX5_RXP_CSR_STATUS_TRIAL_TIMEOUT, id);
180         if (ret)
181                 return ret;
182         ret = mlx5_devx_regex_register_read(ctx, id, MLX5_RXP_CSR_CTRL, &ctrl);
183         if (ret)
184                 return ret;
185         ctrl &= ~MLX5_RXP_CSR_CTRL_INIT;
186         ret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_CTRL,
187                                              ctrl);
188         if (ret)
189                 return ret;
190         rxp_init_rtru(ctx, id, MLX5_RXP_RTRU_CSR_CTRL_INIT_MODE_IM_L1_L2);
191         ret = rxp_init_rtru(ctx, id, MLX5_RXP_RTRU_CSR_CTRL_INIT_MODE_IM_L1_L2);
192         if (ret)
193                 return ret;
194         ret = mlx5_devx_regex_register_read(ctx, id, MLX5_RXP_CSR_CAPABILITY_5,
195                                             &reg);
196         if (ret)
197                 return ret;
198         DRV_LOG(DEBUG, "max matches: %d, DDOS threshold: %d", reg >> 16,
199                 reg & 0xffff);
200         ret = mlx5_devx_regex_register_write(ctx, id, MLX5_RXP_CSR_MAX_MATCH,
201                                              priv->nb_max_matches);
202         ret |= mlx5_devx_regex_register_write(ctx, id,
203                                               MLX5_RXP_CSR_MAX_LATENCY, 0);
204         ret |= mlx5_devx_regex_register_write(ctx, id,
205                                               MLX5_RXP_CSR_MAX_PRI_THREAD, 0);
206         return ret;
207 }
208
209 int
210 mlx5_regex_configure(struct rte_regexdev *dev,
211                      const struct rte_regexdev_config *cfg)
212 {
213         struct mlx5_regex_priv *priv = dev->data->dev_private;
214         int ret;
215         uint8_t id;
216
217         priv->nb_queues = cfg->nb_queue_pairs;
218         priv->qps = rte_zmalloc(NULL, sizeof(struct mlx5_regex_qp) *
219                                 priv->nb_queues, 0);
220         if (!priv->nb_queues) {
221                 DRV_LOG(ERR, "can't allocate qps memory");
222                 rte_errno = ENOMEM;
223                 return -rte_errno;
224         }
225         priv->nb_max_matches = cfg->nb_max_matches;
226         for (id = 0; id < 2; id++) {
227                 ret = rxp_stop_engine(priv->ctx, id);
228                 if (ret) {
229                         DRV_LOG(ERR, "can't stop engine.");
230                         rte_errno = ENODEV;
231                         return -rte_errno;
232                 }
233                 ret = rxp_init(priv, id);
234                 if (ret) {
235                         DRV_LOG(ERR, "can't init engine.");
236                         rte_errno = ENODEV;
237                         return -rte_errno;
238                 }
239                 ret = mlx5_devx_regex_register_write(priv->ctx, id,
240                                                      MLX5_RXP_CSR_MAX_MATCH,
241                                                      priv->nb_max_matches);
242                 if (ret) {
243                         DRV_LOG(ERR, "can't update number of matches.");
244                         rte_errno = ENODEV;
245                         goto configure_error;
246                 }
247                 ret = rxp_start_engine(priv->ctx, id);
248                 if (ret) {
249                         DRV_LOG(ERR, "can't start engine.");
250                         rte_errno = ENODEV;
251                         goto configure_error;
252                 }
253
254         }
255         return 0;
256 configure_error:
257         if (priv->qps)
258                 rte_free(priv->qps);
259         return -rte_errno;
260 }