+
+/*
+ * Fill the rte_flow_query_count 'data' argument passed
+ * in the rte_flow_query() with the values obtained and
+ * accumulated locally.
+ *
+ * ctxt [in] The ulp context for the flow counter manager
+ *
+ * flow_id [in] The HW flow ID
+ *
+ * count [out] The rte_flow_query_count 'data' that is set
+ *
+ */
+int ulp_fc_mgr_query_count_get(struct bnxt_ulp_context *ctxt,
+ uint32_t flow_id,
+ struct rte_flow_query_count *count)
+{
+ int rc = 0;
+ uint32_t nxt_resource_index = 0;
+ struct bnxt_ulp_fc_info *ulp_fc_info;
+ struct ulp_flow_db_res_params params;
+ enum tf_dir dir;
+ uint32_t hw_cntr_id = 0, sw_cntr_idx = 0;
+ struct sw_acc_counter *sw_acc_tbl_entry;
+ bool found_cntr_resource = false;
+ bool found_parent_flow = false;
+ uint32_t pc_idx = 0;
+
+ ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
+ if (!ulp_fc_info)
+ return -ENODEV;
+
+ if (bnxt_ulp_cntxt_acquire_fdb_lock(ctxt))
+ return -EIO;
+
+ do {
+ rc = ulp_flow_db_resource_get(ctxt,
+ BNXT_ULP_FDB_TYPE_REGULAR,
+ flow_id,
+ &nxt_resource_index,
+ ¶ms);
+ if (params.resource_func ==
+ BNXT_ULP_RESOURCE_FUNC_INDEX_TABLE &&
+ (params.resource_sub_type ==
+ BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TABLE_INT_COUNT ||
+ params.resource_sub_type ==
+ BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TABLE_EXT_COUNT)) {
+ found_cntr_resource = true;
+ break;
+ }
+ if (params.resource_func ==
+ BNXT_ULP_RESOURCE_FUNC_PARENT_FLOW) {
+ found_parent_flow = true;
+ pc_idx = params.resource_hndl;
+ }
+
+ } while (!rc && nxt_resource_index);
+
+ bnxt_ulp_cntxt_release_fdb_lock(ctxt);
+
+ if (rc || !found_cntr_resource)
+ return rc;
+
+ dir = params.direction;
+ hw_cntr_id = params.resource_hndl;
+ if (!found_parent_flow &&
+ params.resource_sub_type ==
+ BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TABLE_INT_COUNT) {
+ if (!ulp_fc_info->num_counters)
+ return ulp_fc_tf_flow_stat_get(ctxt, ¶ms, count);
+
+ /* TODO:
+ * Think about optimizing with try_lock later
+ */
+ pthread_mutex_lock(&ulp_fc_info->fc_lock);
+ sw_cntr_idx = hw_cntr_id -
+ ulp_fc_info->shadow_hw_tbl[dir].start_idx;
+ sw_acc_tbl_entry = &ulp_fc_info->sw_acc_tbl[dir][sw_cntr_idx];
+ if (sw_acc_tbl_entry->pkt_count) {
+ count->hits_set = 1;
+ count->bytes_set = 1;
+ count->hits = sw_acc_tbl_entry->pkt_count;
+ count->bytes = sw_acc_tbl_entry->byte_count;
+ }
+ if (count->reset) {
+ sw_acc_tbl_entry->pkt_count = 0;
+ sw_acc_tbl_entry->byte_count = 0;
+ }
+ pthread_mutex_unlock(&ulp_fc_info->fc_lock);
+ } else if (found_parent_flow &&
+ params.resource_sub_type ==
+ BNXT_ULP_RESOURCE_SUB_TYPE_INDEX_TABLE_INT_COUNT) {
+ /* Get stats from the parent child table */
+ ulp_flow_db_parent_flow_count_get(ctxt, pc_idx,
+ &count->hits, &count->bytes,
+ count->reset);
+ if (count->hits)
+ count->hits_set = 1;
+ if (count->bytes)
+ count->bytes_set = 1;
+ } else {
+ /* TBD: Handle External counters */
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+/*
+ * Set the parent flow if it is SW accumulation counter entry.
+ *
+ * ctxt [in] The ulp context for the flow counter manager
+ *
+ * dir [in] The direction of the flow
+ *
+ * hw_cntr_id [in] The HW flow counter ID
+ *
+ * pc_idx [in] parent child db index
+ *
+ */
+int32_t ulp_fc_mgr_cntr_parent_flow_set(struct bnxt_ulp_context *ctxt,
+ enum tf_dir dir,
+ uint32_t hw_cntr_id,
+ uint32_t pc_idx)
+{
+ struct bnxt_ulp_fc_info *ulp_fc_info;
+ uint32_t sw_cntr_idx;
+ int32_t rc = 0;
+
+ ulp_fc_info = bnxt_ulp_cntxt_ptr2_fc_info_get(ctxt);
+ if (!ulp_fc_info)
+ return -EIO;
+
+ pthread_mutex_lock(&ulp_fc_info->fc_lock);
+ sw_cntr_idx = hw_cntr_id - ulp_fc_info->shadow_hw_tbl[dir].start_idx;
+ if (ulp_fc_info->sw_acc_tbl[dir][sw_cntr_idx].valid) {
+ pc_idx |= FLOW_CNTR_PC_FLOW_VALID;
+ ulp_fc_info->sw_acc_tbl[dir][sw_cntr_idx].pc_flow_idx = pc_idx;
+ } else {
+ BNXT_TF_DBG(ERR, "Failed to set parent flow id %x:%x\n",
+ hw_cntr_id, pc_idx);
+ rc = -ENOENT;
+ }
+ pthread_mutex_unlock(&ulp_fc_info->fc_lock);
+
+ return rc;
+}