1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2014-2020 Broadcom
6 #include <rte_common.h>
7 #include <rte_malloc.h>
12 #include "bnxt_tf_common.h"
13 #include "ulp_fc_mgr.h"
14 #include "ulp_flow_db.h"
15 #include "ulp_template_db_enum.h"
16 #include "ulp_template_struct.h"
20 ulp_fc_mgr_shadow_mem_alloc(struct hw_fc_mem_info *parms, int size)
26 parms->mem_va = rte_zmalloc("ulp_fc_info",
27 RTE_CACHE_LINE_ROUNDUP(size),
29 if (parms->mem_va == NULL) {
30 BNXT_TF_DBG(ERR, "Allocate failed mem_va\n");
34 rte_mem_lock_page(parms->mem_va);
36 parms->mem_pa = (void *)(uintptr_t)rte_mem_virt2phy(parms->mem_va);
37 if (parms->mem_pa == (void *)(uintptr_t)RTE_BAD_IOVA) {
38 BNXT_TF_DBG(ERR, "Allocate failed mem_pa\n");
46 ulp_fc_mgr_shadow_mem_free(struct hw_fc_mem_info *parms)
48 rte_free(parms->mem_va);
52 * Allocate and Initialize all Flow Counter Manager resources for this ulp
55 * ctxt [in] The ulp context for the Flow Counter manager.
59 ulp_fc_mgr_init(struct bnxt_ulp_context *ctxt)
61 struct bnxt_ulp_device_params *dparms;
62 uint32_t dev_id, sw_acc_cntr_tbl_sz, hw_fc_mem_info_sz;
63 struct bnxt_ulp_fc_info *ulp_fc_info;
67 BNXT_TF_DBG(DEBUG, "Invalid ULP CTXT\n");
71 if (bnxt_ulp_cntxt_dev_id_get(ctxt, &dev_id)) {
72 BNXT_TF_DBG(DEBUG, "Failed to get device id\n");
76 dparms = bnxt_ulp_device_params_get(dev_id);
78 BNXT_TF_DBG(DEBUG, "Failed to device parms\n");
82 ulp_fc_info = rte_zmalloc("ulp_fc_info", sizeof(*ulp_fc_info), 0);
86 rc = pthread_mutex_init(&ulp_fc_info->fc_lock, NULL);
88 PMD_DRV_LOG(ERR, "Failed to initialize fc mutex\n");
92 /* Add the FC info tbl to the ulp context. */
93 bnxt_ulp_cntxt_ptr2_fc_info_set(ctxt, ulp_fc_info);
95 sw_acc_cntr_tbl_sz = sizeof(struct sw_acc_counter) *
96 dparms->flow_count_db_entries;
98 for (i = 0; i < TF_DIR_MAX; i++) {
99 ulp_fc_info->sw_acc_tbl[i] = rte_zmalloc("ulp_sw_acc_cntr_tbl",
100 sw_acc_cntr_tbl_sz, 0);
101 if (!ulp_fc_info->sw_acc_tbl[i])
105 hw_fc_mem_info_sz = sizeof(uint64_t) * dparms->flow_count_db_entries;
107 for (i = 0; i < TF_DIR_MAX; i++) {
108 rc = ulp_fc_mgr_shadow_mem_alloc(&ulp_fc_info->shadow_hw_tbl[i],
117 ulp_fc_mgr_deinit(ctxt);
119 "Failed to allocate memory for fc mgr\n");
125 * Release all resources in the Flow Counter Manager for this ulp context
127 * ctxt [in] The ulp context for the Flow Counter manager
131 ulp_fc_mgr_deinit(struct bnxt_ulp_context *ctxt)
133 struct bnxt_ulp_fc_info *ulp_fc_info;
136 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
141 ulp_fc_mgr_thread_cancel(ctxt);
143 pthread_mutex_destroy(&ulp_fc_info->fc_lock);
145 for (i = 0; i < TF_DIR_MAX; i++)
146 rte_free(ulp_fc_info->sw_acc_tbl[i]);
148 for (i = 0; i < TF_DIR_MAX; i++)
149 ulp_fc_mgr_shadow_mem_free(&ulp_fc_info->shadow_hw_tbl[i]);
152 rte_free(ulp_fc_info);
154 /* Safe to ignore on deinit */
155 (void)bnxt_ulp_cntxt_ptr2_fc_info_set(ctxt, NULL);
161 * Check if the alarm thread that walks through the flows is started
163 * ctxt [in] The ulp context for the flow counter manager
166 bool ulp_fc_mgr_thread_isstarted(struct bnxt_ulp_context *ctxt)
168 struct bnxt_ulp_fc_info *ulp_fc_info;
170 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
172 return !!(ulp_fc_info->flags & ULP_FLAG_FC_THREAD);
176 * Setup the Flow counter timer thread that will fetch/accumulate raw counter
177 * data from the chip's internal flow counters
179 * ctxt [in] The ulp context for the flow counter manager
183 ulp_fc_mgr_thread_start(struct bnxt_ulp_context *ctxt)
185 struct bnxt_ulp_fc_info *ulp_fc_info;
187 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
189 if (!(ulp_fc_info->flags & ULP_FLAG_FC_THREAD)) {
190 rte_eal_alarm_set(US_PER_S * ULP_FC_TIMER,
193 ulp_fc_info->flags |= ULP_FLAG_FC_THREAD;
200 * Cancel the alarm handler
202 * ctxt [in] The ulp context for the flow counter manager
205 void ulp_fc_mgr_thread_cancel(struct bnxt_ulp_context *ctxt)
207 struct bnxt_ulp_fc_info *ulp_fc_info;
209 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
213 ulp_fc_info->flags &= ~ULP_FLAG_FC_THREAD;
214 rte_eal_alarm_cancel(ulp_fc_mgr_alarm_cb, (void *)ctxt);
218 * DMA-in the raw counter data from the HW and accumulate in the
219 * local accumulator table using the TF-Core API
221 * tfp [in] The TF-Core context
223 * fc_info [in] The ULP Flow counter info ptr
225 * dir [in] The direction of the flow
227 * num_counters [in] The number of counters
230 __rte_unused static int32_t ulp_bulk_get_flow_stats(struct tf *tfp,
231 struct bnxt_ulp_fc_info *fc_info,
232 enum tf_dir dir, uint32_t num_counters)
233 /* MARK AS UNUSED FOR NOW TO AVOID COMPILATION ERRORS TILL API is RESOLVED */
236 struct tf_tbl_get_bulk_parms parms = { 0 };
237 enum tf_tbl_type stype = TF_TBL_TYPE_ACT_STATS_64; /* TBD: Template? */
238 struct sw_acc_counter *sw_acc_tbl_entry = NULL;
239 uint64_t *stats = NULL;
244 parms.starting_idx = fc_info->shadow_hw_tbl[dir].start_idx;
245 parms.num_entries = num_counters;
248 * Size of an entry needs to obtained from template
250 parms.entry_sz_in_bytes = sizeof(uint64_t);
251 stats = (uint64_t *)fc_info->shadow_hw_tbl[dir].mem_va;
252 parms.physical_mem_addr = (uintptr_t)fc_info->shadow_hw_tbl[dir].mem_pa;
256 "BULK: Memory not initialized id:0x%x dir:%d\n",
257 parms.starting_idx, dir);
261 rc = tf_tbl_bulk_get(tfp, &parms);
264 "BULK: Get failed for id:0x%x rc:%d\n",
265 parms.starting_idx, rc);
269 for (i = 0; i < num_counters; i++) {
270 /* TBD - Get PKT/BYTE COUNT SHIFT/MASK from Template */
271 sw_acc_tbl_entry = &fc_info->sw_acc_tbl[dir][i];
272 if (!sw_acc_tbl_entry->valid)
274 sw_acc_tbl_entry->pkt_count += FLOW_CNTR_PKTS(stats[i]);
275 sw_acc_tbl_entry->byte_count += FLOW_CNTR_BYTES(stats[i]);
281 static int ulp_get_single_flow_stat(struct tf *tfp,
282 struct bnxt_ulp_fc_info *fc_info,
287 struct tf_get_tbl_entry_parms parms = { 0 };
288 enum tf_tbl_type stype = TF_TBL_TYPE_ACT_STATS_64; /* TBD:Template? */
289 struct sw_acc_counter *sw_acc_tbl_entry = NULL;
291 uint32_t sw_cntr_indx = 0;
295 parms.idx = hw_cntr_id;
298 * Size of an entry needs to obtained from template
300 parms.data_sz_in_bytes = sizeof(uint64_t);
301 parms.data = (uint8_t *)&stats;
302 rc = tf_get_tbl_entry(tfp, &parms);
305 "Get failed for id:0x%x rc:%d\n",
310 /* TBD - Get PKT/BYTE COUNT SHIFT/MASK from Template */
311 sw_cntr_indx = hw_cntr_id - fc_info->shadow_hw_tbl[dir].start_idx;
312 sw_acc_tbl_entry = &fc_info->sw_acc_tbl[dir][sw_cntr_indx];
313 sw_acc_tbl_entry->pkt_count += FLOW_CNTR_PKTS(stats);
314 sw_acc_tbl_entry->byte_count += FLOW_CNTR_BYTES(stats);
320 * Alarm handler that will issue the TF-Core API to fetch
321 * data from the chip's internal flow counters
323 * ctxt [in] The ulp context for the flow counter manager
328 ulp_fc_mgr_alarm_cb(void *arg)
333 struct bnxt_ulp_context *ctxt = arg;
334 struct bnxt_ulp_fc_info *ulp_fc_info;
335 struct bnxt_ulp_device_params *dparms;
337 uint32_t dev_id, hw_cntr_id = 0;
339 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
343 if (bnxt_ulp_cntxt_dev_id_get(ctxt, &dev_id)) {
344 BNXT_TF_DBG(DEBUG, "Failed to get device id\n");
348 dparms = bnxt_ulp_device_params_get(dev_id);
350 BNXT_TF_DBG(DEBUG, "Failed to device parms\n");
354 tfp = bnxt_ulp_cntxt_tfp_get(ctxt);
356 BNXT_TF_DBG(ERR, "Failed to get the truflow pointer\n");
361 * Take the fc_lock to ensure no flow is destroyed
362 * during the bulk get
364 if (pthread_mutex_trylock(&ulp_fc_info->fc_lock))
367 if (!ulp_fc_info->num_entries) {
368 pthread_mutex_unlock(&ulp_fc_info->fc_lock);
369 ulp_fc_mgr_thread_cancel(ctxt);
373 * Commented for now till GET_BULK is resolved, just get the first flow
375 for (i = 0; i < TF_DIR_MAX; i++) {
376 rc = ulp_bulk_get_flow_stats(tfp, ulp_fc_info, i,
377 dparms->flow_count_db_entries);
382 for (i = 0; i < TF_DIR_MAX; i++) {
383 for (j = 0; j < ulp_fc_info->num_entries; j++) {
384 if (!ulp_fc_info->sw_acc_tbl[i][j].valid)
386 hw_cntr_id = ulp_fc_info->sw_acc_tbl[i][j].hw_cntr_id;
387 rc = ulp_get_single_flow_stat(tfp, ulp_fc_info, i,
394 pthread_mutex_unlock(&ulp_fc_info->fc_lock);
397 * If cmd fails once, no need of
398 * invoking again every second
402 ulp_fc_mgr_thread_cancel(ctxt);
406 rte_eal_alarm_set(US_PER_S * ULP_FC_TIMER,
412 * Set the starting index that indicates the first HW flow
415 * ctxt [in] The ulp context for the flow counter manager
417 * dir [in] The direction of the flow
419 * start_idx [in] The HW flow counter ID
422 bool ulp_fc_mgr_start_idx_isset(struct bnxt_ulp_context *ctxt, enum tf_dir dir)
424 struct bnxt_ulp_fc_info *ulp_fc_info;
426 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
428 /* Assuming start_idx of 0 is invalid */
429 return (ulp_fc_info->shadow_hw_tbl[dir].start_idx != 0);
433 * Set the starting index that indicates the first HW flow
436 * ctxt [in] The ulp context for the flow counter manager
438 * dir [in] The direction of the flow
440 * start_idx [in] The HW flow counter ID
443 int32_t ulp_fc_mgr_start_idx_set(struct bnxt_ulp_context *ctxt, enum tf_dir dir,
446 struct bnxt_ulp_fc_info *ulp_fc_info;
448 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
453 /* Assuming that 0 is an invalid counter ID ? */
454 if (ulp_fc_info->shadow_hw_tbl[dir].start_idx == 0)
455 ulp_fc_info->shadow_hw_tbl[dir].start_idx = start_idx;
461 * Set the corresponding SW accumulator table entry based on
462 * the difference between this counter ID and the starting
463 * counter ID. Also, keep track of num of active counter enabled
466 * ctxt [in] The ulp context for the flow counter manager
468 * dir [in] The direction of the flow
470 * hw_cntr_id [in] The HW flow counter ID
473 int32_t ulp_fc_mgr_cntr_set(struct bnxt_ulp_context *ctxt, enum tf_dir dir,
476 struct bnxt_ulp_fc_info *ulp_fc_info;
477 uint32_t sw_cntr_idx;
479 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
483 pthread_mutex_lock(&ulp_fc_info->fc_lock);
484 sw_cntr_idx = hw_cntr_id - ulp_fc_info->shadow_hw_tbl[dir].start_idx;
485 ulp_fc_info->sw_acc_tbl[dir][sw_cntr_idx].valid = true;
486 ulp_fc_info->sw_acc_tbl[dir][sw_cntr_idx].hw_cntr_id = hw_cntr_id;
487 ulp_fc_info->num_entries++;
488 pthread_mutex_unlock(&ulp_fc_info->fc_lock);
494 * Reset the corresponding SW accumulator table entry based on
495 * the difference between this counter ID and the starting
498 * ctxt [in] The ulp context for the flow counter manager
500 * dir [in] The direction of the flow
502 * hw_cntr_id [in] The HW flow counter ID
505 int32_t ulp_fc_mgr_cntr_reset(struct bnxt_ulp_context *ctxt, enum tf_dir dir,
508 struct bnxt_ulp_fc_info *ulp_fc_info;
509 uint32_t sw_cntr_idx;
511 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
515 pthread_mutex_lock(&ulp_fc_info->fc_lock);
516 sw_cntr_idx = hw_cntr_id - ulp_fc_info->shadow_hw_tbl[dir].start_idx;
517 ulp_fc_info->sw_acc_tbl[dir][sw_cntr_idx].valid = false;
518 ulp_fc_info->sw_acc_tbl[dir][sw_cntr_idx].hw_cntr_id = 0;
519 ulp_fc_info->sw_acc_tbl[dir][sw_cntr_idx].pkt_count = 0;
520 ulp_fc_info->sw_acc_tbl[dir][sw_cntr_idx].byte_count = 0;
521 ulp_fc_info->num_entries--;
522 pthread_mutex_unlock(&ulp_fc_info->fc_lock);
528 * Fill the rte_flow_query_count 'data' argument passed
529 * in the rte_flow_query() with the values obtained and
530 * accumulated locally.
532 * ctxt [in] The ulp context for the flow counter manager
534 * flow_id [in] The HW flow ID
536 * count [out] The rte_flow_query_count 'data' that is set
539 int ulp_fc_mgr_query_count_get(struct bnxt_ulp_context *ctxt,
541 struct rte_flow_query_count *count)
544 uint32_t nxt_resource_index = 0;
545 struct bnxt_ulp_fc_info *ulp_fc_info;
546 struct ulp_flow_db_res_params params;
548 uint32_t hw_cntr_id = 0, sw_cntr_idx = 0;
549 struct sw_acc_counter sw_acc_tbl_entry;
550 bool found_cntr_resource = false;
552 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
557 rc = ulp_flow_db_resource_get(ctxt,
558 BNXT_ULP_REGULAR_FLOW_TABLE,
562 if (params.resource_func ==
563 BNXT_ULP_RESOURCE_FUNC_INDEX_TABLE &&
564 (params.resource_sub_type ==
565 BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT ||
566 params.resource_sub_type ==
567 BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_EXT_COUNT)) {
568 found_cntr_resource = true;
577 if (found_cntr_resource) {
578 dir = params.direction;
579 hw_cntr_id = params.resource_hndl;
580 sw_cntr_idx = hw_cntr_id -
581 ulp_fc_info->shadow_hw_tbl[dir].start_idx;
582 sw_acc_tbl_entry = ulp_fc_info->sw_acc_tbl[dir][sw_cntr_idx];
583 if (params.resource_sub_type ==
584 BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TYPE_INT_COUNT) {
586 count->bytes_set = 1;
587 count->hits = sw_acc_tbl_entry.pkt_count;
588 count->bytes = sw_acc_tbl_entry.byte_count;
590 /* TBD: Handle External counters */