/* SPDX-License-Identifier: BSD-3-Clause * Copyright(c) 2014-2021 Broadcom * All rights reserved. */ #include #include #include #include #include #include "bnxt.h" #include "bnxt_ulp.h" #include "bnxt_ulp_utils.h" #include "bnxt_ulp_tf.h" #include "bnxt_tf_common.h" #include "ulp_fc_mgr.h" #include "ulp_flow_db.h" #include "ulp_template_db_enum.h" #include "ulp_template_struct.h" #include "tf_tbl.h" /* * DMA-in the raw counter data from the HW and accumulate in the * local accumulator table using the TF-Core API * * tfp [in] The TF-Core context * * fc_info [in] The ULP Flow counter info ptr * * dir [in] The direction of the flow * * num_counters [in] The number of counters * */ static int32_t __rte_unused ulp_bulk_get_flow_stats(struct tf *tfp, struct bnxt_ulp_fc_info *fc_info, enum tf_dir dir, struct bnxt_ulp_device_params *dparms) /* MARK AS UNUSED FOR NOW TO AVOID COMPILATION ERRORS TILL API is RESOLVED */ { int rc = 0; struct tf_tbl_get_bulk_parms parms = { 0 }; enum tf_tbl_type stype = TF_TBL_TYPE_ACT_STATS_64; /* TBD: Template? */ struct sw_acc_counter *sw_acc_tbl_entry = NULL; uint64_t *stats = NULL; uint16_t i = 0; parms.dir = dir; parms.type = stype; parms.starting_idx = fc_info->shadow_hw_tbl[dir].start_idx; parms.num_entries = dparms->flow_count_db_entries / 2; /* direction */ /* * TODO: * Size of an entry needs to obtained from template */ parms.entry_sz_in_bytes = sizeof(uint64_t); stats = (uint64_t *)fc_info->shadow_hw_tbl[dir].mem_va; parms.physical_mem_addr = (uint64_t) ((uintptr_t)(fc_info->shadow_hw_tbl[dir].mem_pa)); if (!stats) { BNXT_DRV_DBG(ERR, "BULK: Memory not initialized id:0x%x dir:%d\n", parms.starting_idx, dir); return -EINVAL; } rc = tf_tbl_bulk_get(tfp, &parms); if (rc) { BNXT_DRV_DBG(ERR, "BULK: Get failed for id:0x%x rc:%d\n", parms.starting_idx, rc); return rc; } for (i = 0; i < parms.num_entries; i++) { /* TBD - Get PKT/BYTE COUNT SHIFT/MASK from Template */ sw_acc_tbl_entry = &fc_info->sw_acc_tbl[dir][i]; if (!sw_acc_tbl_entry->valid) continue; sw_acc_tbl_entry->pkt_count += FLOW_CNTR_PKTS(stats[i], dparms); sw_acc_tbl_entry->byte_count += FLOW_CNTR_BYTES(stats[i], dparms); } return rc; } static int ulp_fc_tf_flow_stat_update(struct bnxt_ulp_context *ctxt, struct tf *tfp, struct bnxt_ulp_fc_info *fc_info, enum tf_dir dir, uint32_t hw_cntr_id, struct bnxt_ulp_device_params *dparms) { int rc = 0; struct tf_get_tbl_entry_parms parms = { 0 }; enum tf_tbl_type stype = TF_TBL_TYPE_ACT_STATS_64; /* TBD:Template? */ struct sw_acc_counter *sw_acc_tbl_entry = NULL, *t_sw; uint64_t stats = 0; uint32_t sw_cntr_indx = 0; parms.dir = dir; parms.type = stype; parms.idx = hw_cntr_id; /* * TODO: * Size of an entry needs to obtained from template */ parms.data_sz_in_bytes = sizeof(uint64_t); parms.data = (uint8_t *)&stats; rc = tf_get_tbl_entry(tfp, &parms); if (rc) { BNXT_DRV_DBG(ERR, "Get failed for id:0x%x rc:%d\n", parms.idx, rc); return rc; } /* PKT/BYTE COUNT SHIFT/MASK are device specific */ sw_cntr_indx = hw_cntr_id - fc_info->shadow_hw_tbl[dir].start_idx; sw_acc_tbl_entry = &fc_info->sw_acc_tbl[dir][sw_cntr_indx]; /* Some dpdk applications may accumulate the flow counters while some * may not. In cases where the application is accumulating the counters * the PMD need not do the accumulation itself and viceversa to report * the correct flow counters. */ sw_acc_tbl_entry->pkt_count += FLOW_CNTR_PKTS(stats, dparms); sw_acc_tbl_entry->byte_count += FLOW_CNTR_BYTES(stats, dparms); /* Update the parent counters if it is child flow */ if (sw_acc_tbl_entry->pc_flow_idx & FLOW_CNTR_PC_FLOW_VALID) { uint32_t pc_idx; /* Update the parent counters */ t_sw = sw_acc_tbl_entry; pc_idx = t_sw->pc_flow_idx & ~FLOW_CNTR_PC_FLOW_VALID; if (ulp_flow_db_parent_flow_count_update(ctxt, pc_idx, t_sw->pkt_count, t_sw->byte_count)) { BNXT_DRV_DBG(ERR, "Error updating parent counters\n"); } } return rc; } static int32_t ulp_fc_tf_update_accum_stats(struct bnxt_ulp_context *ctxt, struct bnxt_ulp_fc_info *fc_info, struct bnxt_ulp_device_params *dparms) { uint32_t hw_cntr_id = 0, num_entries = 0, j; int32_t rc = 0; enum tf_dir dir; struct tf *tfp; num_entries = dparms->flow_count_db_entries / 2; for (dir = 0; dir < TF_DIR_MAX; dir++) { for (j = 0; j < num_entries; j++) { if (!fc_info->sw_acc_tbl[dir][j].valid) continue; tfp = bnxt_ulp_cntxt_tfp_get(ctxt, fc_info->sw_acc_tbl[dir][j].session_type); if (!tfp) { BNXT_DRV_DBG(ERR, "Failed to get the tfp\n"); return 0; } hw_cntr_id = fc_info->sw_acc_tbl[dir][j].hw_cntr_id; rc = ulp_fc_tf_flow_stat_update(ctxt, tfp, fc_info, dir, hw_cntr_id, dparms); if (rc) break; } } return rc; } static int32_t ulp_fc_tf_flow_stat_get(struct bnxt_ulp_context *ctxt, uint8_t direction, uint32_t session_type, uint64_t handle, struct rte_flow_query_count *qcount) { struct tf *tfp; struct bnxt_ulp_device_params *dparms; struct tf_get_tbl_entry_parms parms = { 0 }; struct tf_set_tbl_entry_parms sparms = { 0 }; enum tf_tbl_type stype = TF_TBL_TYPE_ACT_STATS_64; uint64_t stats = 0; uint32_t dev_id = 0; int32_t rc = 0; tfp = bnxt_ulp_cntxt_tfp_get(ctxt, session_type); if (!tfp) { BNXT_DRV_DBG(ERR, "Failed to get the truflow pointer\n"); return -EINVAL; } if (bnxt_ulp_cntxt_dev_id_get(ctxt, &dev_id)) { BNXT_DRV_DBG(DEBUG, "Failed to get device id\n"); bnxt_ulp_cntxt_entry_release(); return -EINVAL; } dparms = bnxt_ulp_device_params_get(dev_id); if (!dparms) { BNXT_DRV_DBG(DEBUG, "Failed to device parms\n"); bnxt_ulp_cntxt_entry_release(); return -EINVAL; } parms.dir = (enum tf_dir)direction; parms.type = stype; parms.idx = (uint32_t)handle; parms.data_sz_in_bytes = sizeof(uint64_t); parms.data = (uint8_t *)&stats; rc = tf_get_tbl_entry(tfp, &parms); if (rc) { BNXT_DRV_DBG(ERR, "Get failed for id:0x%x rc:%d\n", parms.idx, rc); return rc; } qcount->hits = FLOW_CNTR_PKTS(stats, dparms); if (qcount->hits) qcount->hits_set = 1; qcount->bytes = FLOW_CNTR_BYTES(stats, dparms); if (qcount->bytes) qcount->bytes_set = 1; if (qcount->reset) { stats = 0; sparms.dir = (enum tf_dir)direction; sparms.type = stype; sparms.idx = (uint32_t)handle; sparms.data = (uint8_t *)&stats; sparms.data_sz_in_bytes = sizeof(uint64_t); rc = tf_set_tbl_entry(tfp, &sparms); if (rc) { BNXT_DRV_DBG(ERR, "Set failed for id:0x%x rc:%d\n", sparms.idx, rc); return rc; } } return rc; } const struct bnxt_ulp_fc_core_ops ulp_fc_tf_core_ops = { .ulp_flow_stat_get = ulp_fc_tf_flow_stat_get, .ulp_flow_stats_accum_update = ulp_fc_tf_update_accum_stats };