dc8a41cdc18743998516cb5edecc889fdea9241f
[dpdk.git] / drivers / net / bnxt / tf_ulp / ulp_fc_mgr.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2014-2020 Broadcom
3  * All rights reserved.
4  */
5
6 #include <rte_common.h>
7 #include <rte_malloc.h>
8 #include <rte_log.h>
9 #include <rte_alarm.h>
10 #include "bnxt.h"
11 #include "bnxt_ulp.h"
12 #include "bnxt_tf_common.h"
13 #include "ulp_fc_mgr.h"
14 #include "ulp_template_db_enum.h"
15 #include "ulp_template_struct.h"
16 #include "tf_tbl.h"
17
18 static int
19 ulp_fc_mgr_shadow_mem_alloc(struct hw_fc_mem_info *parms, int size)
20 {
21         /* Allocate memory*/
22         if (parms == NULL)
23                 return -EINVAL;
24
25         parms->mem_va = rte_zmalloc("ulp_fc_info",
26                                     RTE_CACHE_LINE_ROUNDUP(size),
27                                     4096);
28         if (parms->mem_va == NULL) {
29                 BNXT_TF_DBG(ERR, "Allocate failed mem_va\n");
30                 return -ENOMEM;
31         }
32
33         rte_mem_lock_page(parms->mem_va);
34
35         parms->mem_pa = (void *)(uintptr_t)rte_mem_virt2phy(parms->mem_va);
36         if (parms->mem_pa == (void *)(uintptr_t)RTE_BAD_IOVA) {
37                 BNXT_TF_DBG(ERR, "Allocate failed mem_pa\n");
38                 return -ENOMEM;
39         }
40
41         return 0;
42 }
43
44 static void
45 ulp_fc_mgr_shadow_mem_free(struct hw_fc_mem_info *parms)
46 {
47         rte_free(parms->mem_va);
48 }
49
50 /*
51  * Allocate and Initialize all Flow Counter Manager resources for this ulp
52  * context.
53  *
54  * ctxt [in] The ulp context for the Flow Counter manager.
55  *
56  */
57 int32_t
58 ulp_fc_mgr_init(struct bnxt_ulp_context *ctxt)
59 {
60         struct bnxt_ulp_device_params *dparms;
61         uint32_t dev_id, sw_acc_cntr_tbl_sz, hw_fc_mem_info_sz;
62         struct bnxt_ulp_fc_info *ulp_fc_info;
63         int i, rc;
64
65         if (!ctxt) {
66                 BNXT_TF_DBG(DEBUG, "Invalid ULP CTXT\n");
67                 return -EINVAL;
68         }
69
70         if (bnxt_ulp_cntxt_dev_id_get(ctxt, &dev_id)) {
71                 BNXT_TF_DBG(DEBUG, "Failed to get device id\n");
72                 return -EINVAL;
73         }
74
75         dparms = bnxt_ulp_device_params_get(dev_id);
76         if (!dparms) {
77                 BNXT_TF_DBG(DEBUG, "Failed to device parms\n");
78                 return -EINVAL;
79         }
80
81         ulp_fc_info = rte_zmalloc("ulp_fc_info", sizeof(*ulp_fc_info), 0);
82         if (!ulp_fc_info)
83                 goto error;
84
85         rc = pthread_mutex_init(&ulp_fc_info->fc_lock, NULL);
86         if (rc) {
87                 PMD_DRV_LOG(ERR, "Failed to initialize fc mutex\n");
88                 goto error;
89         }
90
91         /* Add the FC info tbl to the ulp context. */
92         bnxt_ulp_cntxt_ptr2_fc_info_set(ctxt, ulp_fc_info);
93
94         sw_acc_cntr_tbl_sz = sizeof(struct sw_acc_counter) *
95                                 dparms->flow_count_db_entries;
96
97         for (i = 0; i < TF_DIR_MAX; i++) {
98                 ulp_fc_info->sw_acc_tbl[i] = rte_zmalloc("ulp_sw_acc_cntr_tbl",
99                                                          sw_acc_cntr_tbl_sz, 0);
100                 if (!ulp_fc_info->sw_acc_tbl[i])
101                         goto error;
102         }
103
104         hw_fc_mem_info_sz = sizeof(uint64_t) * dparms->flow_count_db_entries;
105
106         for (i = 0; i < TF_DIR_MAX; i++) {
107                 rc = ulp_fc_mgr_shadow_mem_alloc(&ulp_fc_info->shadow_hw_tbl[i],
108                                                  hw_fc_mem_info_sz);
109                 if (rc)
110                         goto error;
111         }
112
113         return 0;
114
115 error:
116         ulp_fc_mgr_deinit(ctxt);
117         BNXT_TF_DBG(DEBUG,
118                     "Failed to allocate memory for fc mgr\n");
119
120         return -ENOMEM;
121 }
122
123 /*
124  * Release all resources in the Flow Counter Manager for this ulp context
125  *
126  * ctxt [in] The ulp context for the Flow Counter manager
127  *
128  */
129 int32_t
130 ulp_fc_mgr_deinit(struct bnxt_ulp_context *ctxt)
131 {
132         struct bnxt_ulp_fc_info *ulp_fc_info;
133         int i;
134
135         ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
136
137         if (!ulp_fc_info)
138                 return -EINVAL;
139
140         ulp_fc_mgr_thread_cancel(ctxt);
141
142         pthread_mutex_destroy(&ulp_fc_info->fc_lock);
143
144         for (i = 0; i < TF_DIR_MAX; i++)
145                 rte_free(ulp_fc_info->sw_acc_tbl[i]);
146
147         for (i = 0; i < TF_DIR_MAX; i++)
148                 ulp_fc_mgr_shadow_mem_free(&ulp_fc_info->shadow_hw_tbl[i]);
149
150
151         rte_free(ulp_fc_info);
152
153         /* Safe to ignore on deinit */
154         (void)bnxt_ulp_cntxt_ptr2_fc_info_set(ctxt, NULL);
155
156         return 0;
157 }
158
159 /*
160  * Check if the alarm thread that walks through the flows is started
161  *
162  * ctxt [in] The ulp context for the flow counter manager
163  *
164  */
165 bool ulp_fc_mgr_thread_isstarted(struct bnxt_ulp_context *ctxt)
166 {
167         struct bnxt_ulp_fc_info *ulp_fc_info;
168
169         ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
170
171         return !!(ulp_fc_info->flags & ULP_FLAG_FC_THREAD);
172 }
173
174 /*
175  * Setup the Flow counter timer thread that will fetch/accumulate raw counter
176  * data from the chip's internal flow counters
177  *
178  * ctxt [in] The ulp context for the flow counter manager
179  *
180  */
181 int32_t
182 ulp_fc_mgr_thread_start(struct bnxt_ulp_context *ctxt)
183 {
184         struct bnxt_ulp_fc_info *ulp_fc_info;
185
186         ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
187
188         if (!(ulp_fc_info->flags & ULP_FLAG_FC_THREAD)) {
189                 rte_eal_alarm_set(US_PER_S * ULP_FC_TIMER,
190                                   ulp_fc_mgr_alarm_cb,
191                                   (void *)ctxt);
192                 ulp_fc_info->flags |= ULP_FLAG_FC_THREAD;
193         }
194
195         return 0;
196 }
197
198 /*
199  * Cancel the alarm handler
200  *
201  * ctxt [in] The ulp context for the flow counter manager
202  *
203  */
204 void ulp_fc_mgr_thread_cancel(struct bnxt_ulp_context *ctxt)
205 {
206         struct bnxt_ulp_fc_info *ulp_fc_info;
207
208         ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
209         if (!ulp_fc_info)
210                 return;
211
212         ulp_fc_info->flags &= ~ULP_FLAG_FC_THREAD;
213         rte_eal_alarm_cancel(ulp_fc_mgr_alarm_cb, (void *)ctxt);
214 }
215
216 /*
217  * DMA-in the raw counter data from the HW and accumulate in the
218  * local accumulator table using the TF-Core API
219  *
220  * tfp [in] The TF-Core context
221  *
222  * fc_info [in] The ULP Flow counter info ptr
223  *
224  * dir [in] The direction of the flow
225  *
226  * num_counters [in] The number of counters
227  *
228  */
229 static int32_t ulp_bulk_get_flow_stats(struct tf *tfp,
230                                        struct bnxt_ulp_fc_info *fc_info,
231                                        enum tf_dir dir, uint32_t num_counters)
232 {
233         int rc = 0;
234         struct tf_tbl_get_bulk_parms parms = { 0 };
235         enum tf_tbl_type stype = TF_TBL_TYPE_ACT_STATS_64;  /* TBD: Template? */
236         struct sw_acc_counter *sw_acc_tbl_entry = NULL;
237         uint64_t *stats = NULL;
238         uint16_t i = 0;
239
240         parms.dir = dir;
241         parms.type = stype;
242         parms.starting_idx = fc_info->shadow_hw_tbl[dir].start_idx;
243         parms.num_entries = num_counters;
244         /*
245          * TODO:
246          * Size of an entry needs to obtained from template
247          */
248         parms.entry_sz_in_bytes = sizeof(uint64_t);
249         stats = (uint64_t *)fc_info->shadow_hw_tbl[dir].mem_va;
250         parms.physical_mem_addr = (uintptr_t)fc_info->shadow_hw_tbl[dir].mem_pa;
251
252         if (stats == NULL) {
253                 PMD_DRV_LOG(ERR,
254                             "BULK: Memory not initialized id:0x%x dir:%d\n",
255                             parms.starting_idx, dir);
256                 return -EINVAL;
257         }
258
259         rc = tf_tbl_bulk_get(tfp, &parms);
260         if (rc) {
261                 PMD_DRV_LOG(ERR,
262                             "BULK: Get failed for id:0x%x rc:%d\n",
263                             parms.starting_idx, rc);
264                 return rc;
265         }
266
267         for (i = 0; i < num_counters; i++) {
268                 /* TBD - Get PKT/BYTE COUNT SHIFT/MASK from Template */
269                 sw_acc_tbl_entry = &fc_info->sw_acc_tbl[dir][i];
270                 if (!sw_acc_tbl_entry->valid)
271                         continue;
272                 sw_acc_tbl_entry->pkt_count += FLOW_CNTR_PKTS(stats[i]);
273                 sw_acc_tbl_entry->byte_count += FLOW_CNTR_BYTES(stats[i]);
274         }
275
276         return rc;
277 }
278 /*
279  * Alarm handler that will issue the TF-Core API to fetch
280  * data from the chip's internal flow counters
281  *
282  * ctxt [in] The ulp context for the flow counter manager
283  *
284  */
285 void
286 ulp_fc_mgr_alarm_cb(void *arg)
287 {
288         int rc = 0, i;
289         struct bnxt_ulp_context *ctxt = arg;
290         struct bnxt_ulp_fc_info *ulp_fc_info;
291         struct bnxt_ulp_device_params *dparms;
292         struct tf *tfp;
293         uint32_t dev_id;
294
295         ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
296         if (!ulp_fc_info)
297                 return;
298
299         if (bnxt_ulp_cntxt_dev_id_get(ctxt, &dev_id)) {
300                 BNXT_TF_DBG(DEBUG, "Failed to get device id\n");
301                 return;
302         }
303
304         dparms = bnxt_ulp_device_params_get(dev_id);
305         if (!dparms) {
306                 BNXT_TF_DBG(DEBUG, "Failed to device parms\n");
307                 return;
308         }
309
310         tfp = bnxt_ulp_cntxt_tfp_get(ctxt);
311         if (!tfp) {
312                 BNXT_TF_DBG(ERR, "Failed to get the truflow pointer\n");
313                 return;
314         }
315
316         /*
317          * Take the fc_lock to ensure no flow is destroyed
318          * during the bulk get
319          */
320         if (pthread_mutex_trylock(&ulp_fc_info->fc_lock))
321                 goto out;
322
323         if (!ulp_fc_info->num_entries) {
324                 pthread_mutex_unlock(&ulp_fc_info->fc_lock);
325                 ulp_fc_mgr_thread_cancel(ctxt);
326                 return;
327         }
328
329         for (i = 0; i < TF_DIR_MAX; i++) {
330                 rc = ulp_bulk_get_flow_stats(tfp, ulp_fc_info, i,
331                                              dparms->flow_count_db_entries);
332                 if (rc)
333                         break;
334         }
335
336         pthread_mutex_unlock(&ulp_fc_info->fc_lock);
337
338         /*
339          * If cmd fails once, no need of
340          * invoking again every second
341          */
342
343         if (rc) {
344                 ulp_fc_mgr_thread_cancel(ctxt);
345                 return;
346         }
347 out:
348         rte_eal_alarm_set(US_PER_S * ULP_FC_TIMER,
349                           ulp_fc_mgr_alarm_cb,
350                           (void *)ctxt);
351 }
352
353 /*
354  * Set the starting index that indicates the first HW flow
355  * counter ID
356  *
357  * ctxt [in] The ulp context for the flow counter manager
358  *
359  * dir [in] The direction of the flow
360  *
361  * start_idx [in] The HW flow counter ID
362  *
363  */
364 bool ulp_fc_mgr_start_idx_isset(struct bnxt_ulp_context *ctxt, enum tf_dir dir)
365 {
366         struct bnxt_ulp_fc_info *ulp_fc_info;
367
368         ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
369
370         /* Assuming start_idx of 0 is invalid */
371         return (ulp_fc_info->shadow_hw_tbl[dir].start_idx != 0);
372 }
373
374 /*
375  * Set the starting index that indicates the first HW flow
376  * counter ID
377  *
378  * ctxt [in] The ulp context for the flow counter manager
379  *
380  * dir [in] The direction of the flow
381  *
382  * start_idx [in] The HW flow counter ID
383  *
384  */
385 int32_t ulp_fc_mgr_start_idx_set(struct bnxt_ulp_context *ctxt, enum tf_dir dir,
386                                  uint32_t start_idx)
387 {
388         struct bnxt_ulp_fc_info *ulp_fc_info;
389
390         ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
391
392         if (!ulp_fc_info)
393                 return -EIO;
394
395         /* Assuming that 0 is an invalid counter ID ? */
396         if (ulp_fc_info->shadow_hw_tbl[dir].start_idx == 0)
397                 ulp_fc_info->shadow_hw_tbl[dir].start_idx = start_idx;
398
399         return 0;
400 }
401
402 /*
403  * Set the corresponding SW accumulator table entry based on
404  * the difference between this counter ID and the starting
405  * counter ID. Also, keep track of num of active counter enabled
406  * flows.
407  *
408  * ctxt [in] The ulp context for the flow counter manager
409  *
410  * dir [in] The direction of the flow
411  *
412  * hw_cntr_id [in] The HW flow counter ID
413  *
414  */
415 int32_t ulp_fc_mgr_cntr_set(struct bnxt_ulp_context *ctxt, enum tf_dir dir,
416                             uint32_t hw_cntr_id)
417 {
418         struct bnxt_ulp_fc_info *ulp_fc_info;
419         uint32_t sw_cntr_idx;
420
421         ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
422         if (!ulp_fc_info)
423                 return -EIO;
424
425         pthread_mutex_lock(&ulp_fc_info->fc_lock);
426         sw_cntr_idx = hw_cntr_id - ulp_fc_info->shadow_hw_tbl[dir].start_idx;
427         ulp_fc_info->sw_acc_tbl[dir][sw_cntr_idx].valid = true;
428         ulp_fc_info->num_entries++;
429         pthread_mutex_unlock(&ulp_fc_info->fc_lock);
430
431         return 0;
432 }
433
434 /*
435  * Reset the corresponding SW accumulator table entry based on
436  * the difference between this counter ID and the starting
437  * counter ID.
438  *
439  * ctxt [in] The ulp context for the flow counter manager
440  *
441  * dir [in] The direction of the flow
442  *
443  * hw_cntr_id [in] The HW flow counter ID
444  *
445  */
446 int32_t ulp_fc_mgr_cntr_reset(struct bnxt_ulp_context *ctxt, enum tf_dir dir,
447                               uint32_t hw_cntr_id)
448 {
449         struct bnxt_ulp_fc_info *ulp_fc_info;
450         uint32_t sw_cntr_idx;
451
452         ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
453         if (!ulp_fc_info)
454                 return -EIO;
455
456         pthread_mutex_lock(&ulp_fc_info->fc_lock);
457         sw_cntr_idx = hw_cntr_id - ulp_fc_info->shadow_hw_tbl[dir].start_idx;
458         ulp_fc_info->sw_acc_tbl[dir][sw_cntr_idx].valid = false;
459         ulp_fc_info->sw_acc_tbl[dir][sw_cntr_idx].pkt_count = 0;
460         ulp_fc_info->sw_acc_tbl[dir][sw_cntr_idx].byte_count = 0;
461         ulp_fc_info->num_entries--;
462         pthread_mutex_unlock(&ulp_fc_info->fc_lock);
463
464         return 0;
465 }