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_template_db_enum.h"
15 #include "ulp_template_struct.h"
19 ulp_fc_mgr_shadow_mem_alloc(struct hw_fc_mem_info *parms, int size)
25 parms->mem_va = rte_zmalloc("ulp_fc_info",
26 RTE_CACHE_LINE_ROUNDUP(size),
28 if (parms->mem_va == NULL) {
29 BNXT_TF_DBG(ERR, "Allocate failed mem_va\n");
33 rte_mem_lock_page(parms->mem_va);
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");
45 ulp_fc_mgr_shadow_mem_free(struct hw_fc_mem_info *parms)
47 rte_free(parms->mem_va);
51 * Allocate and Initialize all Flow Counter Manager resources for this ulp
54 * ctxt [in] The ulp context for the Flow Counter manager.
58 ulp_fc_mgr_init(struct bnxt_ulp_context *ctxt)
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;
66 BNXT_TF_DBG(DEBUG, "Invalid ULP CTXT\n");
70 if (bnxt_ulp_cntxt_dev_id_get(ctxt, &dev_id)) {
71 BNXT_TF_DBG(DEBUG, "Failed to get device id\n");
75 dparms = bnxt_ulp_device_params_get(dev_id);
77 BNXT_TF_DBG(DEBUG, "Failed to device parms\n");
81 ulp_fc_info = rte_zmalloc("ulp_fc_info", sizeof(*ulp_fc_info), 0);
85 rc = pthread_mutex_init(&ulp_fc_info->fc_lock, NULL);
87 PMD_DRV_LOG(ERR, "Failed to initialize fc mutex\n");
91 /* Add the FC info tbl to the ulp context. */
92 bnxt_ulp_cntxt_ptr2_fc_info_set(ctxt, ulp_fc_info);
94 sw_acc_cntr_tbl_sz = sizeof(struct sw_acc_counter) *
95 dparms->flow_count_db_entries;
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])
104 hw_fc_mem_info_sz = sizeof(uint64_t) * dparms->flow_count_db_entries;
106 for (i = 0; i < TF_DIR_MAX; i++) {
107 rc = ulp_fc_mgr_shadow_mem_alloc(&ulp_fc_info->shadow_hw_tbl[i],
116 ulp_fc_mgr_deinit(ctxt);
118 "Failed to allocate memory for fc mgr\n");
124 * Release all resources in the Flow Counter Manager for this ulp context
126 * ctxt [in] The ulp context for the Flow Counter manager
130 ulp_fc_mgr_deinit(struct bnxt_ulp_context *ctxt)
132 struct bnxt_ulp_fc_info *ulp_fc_info;
135 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
140 ulp_fc_mgr_thread_cancel(ctxt);
142 pthread_mutex_destroy(&ulp_fc_info->fc_lock);
144 for (i = 0; i < TF_DIR_MAX; i++)
145 rte_free(ulp_fc_info->sw_acc_tbl[i]);
147 for (i = 0; i < TF_DIR_MAX; i++)
148 ulp_fc_mgr_shadow_mem_free(&ulp_fc_info->shadow_hw_tbl[i]);
151 rte_free(ulp_fc_info);
153 /* Safe to ignore on deinit */
154 (void)bnxt_ulp_cntxt_ptr2_fc_info_set(ctxt, NULL);
160 * Check if the alarm thread that walks through the flows is started
162 * ctxt [in] The ulp context for the flow counter manager
165 bool ulp_fc_mgr_thread_isstarted(struct bnxt_ulp_context *ctxt)
167 struct bnxt_ulp_fc_info *ulp_fc_info;
169 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
171 return !!(ulp_fc_info->flags & ULP_FLAG_FC_THREAD);
175 * Setup the Flow counter timer thread that will fetch/accumulate raw counter
176 * data from the chip's internal flow counters
178 * ctxt [in] The ulp context for the flow counter manager
182 ulp_fc_mgr_thread_start(struct bnxt_ulp_context *ctxt)
184 struct bnxt_ulp_fc_info *ulp_fc_info;
186 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
188 if (!(ulp_fc_info->flags & ULP_FLAG_FC_THREAD)) {
189 rte_eal_alarm_set(US_PER_S * ULP_FC_TIMER,
192 ulp_fc_info->flags |= ULP_FLAG_FC_THREAD;
199 * Cancel the alarm handler
201 * ctxt [in] The ulp context for the flow counter manager
204 void ulp_fc_mgr_thread_cancel(struct bnxt_ulp_context *ctxt)
206 struct bnxt_ulp_fc_info *ulp_fc_info;
208 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
212 ulp_fc_info->flags &= ~ULP_FLAG_FC_THREAD;
213 rte_eal_alarm_cancel(ulp_fc_mgr_alarm_cb, (void *)ctxt);
217 * DMA-in the raw counter data from the HW and accumulate in the
218 * local accumulator table using the TF-Core API
220 * tfp [in] The TF-Core context
222 * fc_info [in] The ULP Flow counter info ptr
224 * dir [in] The direction of the flow
226 * num_counters [in] The number of counters
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)
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;
242 parms.starting_idx = fc_info->shadow_hw_tbl[dir].start_idx;
243 parms.num_entries = num_counters;
246 * Size of an entry needs to obtained from template
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;
254 "BULK: Memory not initialized id:0x%x dir:%d\n",
255 parms.starting_idx, dir);
259 rc = tf_tbl_bulk_get(tfp, &parms);
262 "BULK: Get failed for id:0x%x rc:%d\n",
263 parms.starting_idx, rc);
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)
272 sw_acc_tbl_entry->pkt_count += FLOW_CNTR_PKTS(stats[i]);
273 sw_acc_tbl_entry->byte_count += FLOW_CNTR_BYTES(stats[i]);
279 * Alarm handler that will issue the TF-Core API to fetch
280 * data from the chip's internal flow counters
282 * ctxt [in] The ulp context for the flow counter manager
286 ulp_fc_mgr_alarm_cb(void *arg)
289 struct bnxt_ulp_context *ctxt = arg;
290 struct bnxt_ulp_fc_info *ulp_fc_info;
291 struct bnxt_ulp_device_params *dparms;
295 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
299 if (bnxt_ulp_cntxt_dev_id_get(ctxt, &dev_id)) {
300 BNXT_TF_DBG(DEBUG, "Failed to get device id\n");
304 dparms = bnxt_ulp_device_params_get(dev_id);
306 BNXT_TF_DBG(DEBUG, "Failed to device parms\n");
310 tfp = bnxt_ulp_cntxt_tfp_get(ctxt);
312 BNXT_TF_DBG(ERR, "Failed to get the truflow pointer\n");
317 * Take the fc_lock to ensure no flow is destroyed
318 * during the bulk get
320 if (pthread_mutex_trylock(&ulp_fc_info->fc_lock))
323 if (!ulp_fc_info->num_entries) {
324 pthread_mutex_unlock(&ulp_fc_info->fc_lock);
325 ulp_fc_mgr_thread_cancel(ctxt);
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);
336 pthread_mutex_unlock(&ulp_fc_info->fc_lock);
339 * If cmd fails once, no need of
340 * invoking again every second
344 ulp_fc_mgr_thread_cancel(ctxt);
348 rte_eal_alarm_set(US_PER_S * ULP_FC_TIMER,
354 * Set the starting index that indicates the first HW flow
357 * ctxt [in] The ulp context for the flow counter manager
359 * dir [in] The direction of the flow
361 * start_idx [in] The HW flow counter ID
364 bool ulp_fc_mgr_start_idx_isset(struct bnxt_ulp_context *ctxt, enum tf_dir dir)
366 struct bnxt_ulp_fc_info *ulp_fc_info;
368 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
370 /* Assuming start_idx of 0 is invalid */
371 return (ulp_fc_info->shadow_hw_tbl[dir].start_idx != 0);
375 * Set the starting index that indicates the first HW flow
378 * ctxt [in] The ulp context for the flow counter manager
380 * dir [in] The direction of the flow
382 * start_idx [in] The HW flow counter ID
385 int32_t ulp_fc_mgr_start_idx_set(struct bnxt_ulp_context *ctxt, enum tf_dir dir,
388 struct bnxt_ulp_fc_info *ulp_fc_info;
390 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
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;
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
408 * ctxt [in] The ulp context for the flow counter manager
410 * dir [in] The direction of the flow
412 * hw_cntr_id [in] The HW flow counter ID
415 int32_t ulp_fc_mgr_cntr_set(struct bnxt_ulp_context *ctxt, enum tf_dir dir,
418 struct bnxt_ulp_fc_info *ulp_fc_info;
419 uint32_t sw_cntr_idx;
421 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
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);
435 * Reset the corresponding SW accumulator table entry based on
436 * the difference between this counter ID and the starting
439 * ctxt [in] The ulp context for the flow counter manager
441 * dir [in] The direction of the flow
443 * hw_cntr_id [in] The HW flow counter ID
446 int32_t ulp_fc_mgr_cntr_reset(struct bnxt_ulp_context *ctxt, enum tf_dir dir,
449 struct bnxt_ulp_fc_info *ulp_fc_info;
450 uint32_t sw_cntr_idx;
452 ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
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);