net/bnxt: use SPDX license tag
[dpdk.git] / drivers / net / bnxt / bnxt_flow.c
index 5564c53..320b53d 100644 (file)
 #include <rte_flow.h>
 #include <rte_flow_driver.h>
 #include <rte_tailq.h>
+#include <rte_alarm.h>
+#include <rte_cycles.h>
 
 #include "bnxt.h"
 #include "bnxt_filter.h"
 #include "bnxt_hwrm.h"
 #include "bnxt_ring.h"
 #include "bnxt_rxq.h"
+#include "bnxt_rxr.h"
 #include "bnxt_vnic.h"
 #include "hsi_struct_def_dpdk.h"
 
@@ -867,7 +870,6 @@ bnxt_create_l2_filter(struct bnxt *bp, struct bnxt_filter_info *nf,
                bnxt_free_filter(bp, filter1);
                return NULL;
        }
-       filter1->l2_ref_cnt++;
        return filter1;
 }
 
@@ -1060,16 +1062,9 @@ start:
                        vnic_id = act_q->index;
                }
 
+               BNXT_VALID_VNIC_OR_RET(bp, vnic_id);
+
                vnic = &bp->vnic_info[vnic_id];
-               if (vnic == NULL) {
-                       rte_flow_error_set(error,
-                                          EINVAL,
-                                          RTE_FLOW_ERROR_TYPE_ACTION,
-                                          act,
-                                          "No matching VNIC found.");
-                       rc = -rte_errno;
-                       goto ret;
-               }
                if (vnic->rx_queue_cnt) {
                        if (vnic->start_grp_id != act_q->index) {
                                PMD_DRV_LOG(ERR,
@@ -1269,28 +1264,9 @@ use_vnic:
                rss = (const struct rte_flow_action_rss *)act->conf;
 
                vnic_id = attr->group;
-               if (!vnic_id) {
-                       PMD_DRV_LOG(ERR, "Group id cannot be 0\n");
-                       rte_flow_error_set(error,
-                                          EINVAL,
-                                          RTE_FLOW_ERROR_TYPE_ATTR,
-                                          NULL,
-                                          "Group id cannot be 0");
-                       rc = -rte_errno;
-                       goto ret;
-               }
 
+               BNXT_VALID_VNIC_OR_RET(bp, vnic_id);
                vnic = &bp->vnic_info[vnic_id];
-               if (vnic == NULL) {
-                       rte_flow_error_set(error,
-                                          EINVAL,
-                                          RTE_FLOW_ERROR_TYPE_ACTION,
-                                          act,
-                                          "No matching VNIC for RSS group.");
-                       rc = -rte_errno;
-                       goto ret;
-               }
-               PMD_DRV_LOG(DEBUG, "VNIC found\n");
 
                /* Check if requested RSS config matches RSS config of VNIC
                 * only if it is not a fresh VNIC configuration.
@@ -1428,18 +1404,6 @@ vnic_found:
                bnxt_update_filter_flags_en(filter, filter1, use_ntuple);
                break;
        case RTE_FLOW_ACTION_TYPE_MARK:
-               if (bp->flags & BNXT_FLAG_RX_VECTOR_PKT_MODE) {
-                       PMD_DRV_LOG(DEBUG,
-                                   "Disable vector processing for mark\n");
-                       rte_flow_error_set(error,
-                                          ENOTSUP,
-                                          RTE_FLOW_ERROR_TYPE_ACTION,
-                                          act,
-                                          "Disable vector processing for mark");
-                       rc = -rte_errno;
-                       goto ret;
-               }
-
                if (bp->mark_table == NULL) {
                        rte_flow_error_set(error,
                                           ENOMEM,
@@ -1450,6 +1414,13 @@ vnic_found:
                        goto ret;
                }
 
+               if (bp->flags & BNXT_FLAG_RX_VECTOR_PKT_MODE) {
+                       PMD_DRV_LOG(DEBUG,
+                                   "Disabling vector processing for mark\n");
+                       bp->eth_dev->rx_pkt_burst = bnxt_recv_pkts;
+                       bp->flags &= ~BNXT_FLAG_RX_VECTOR_PKT_MODE;
+               }
+
                filter->valid_flags |= BNXT_FLOW_MARK_FLAG;
                filter->mark = ((const struct rte_flow_action_mark *)
                                act->conf)->id;
@@ -1654,6 +1625,51 @@ bnxt_match_filter(struct bnxt *bp, struct bnxt_filter_info *nf)
        return 0;
 }
 
+static void
+bnxt_setup_flow_counter(struct bnxt *bp)
+{
+       if (bp->fw_cap & BNXT_FW_CAP_ADV_FLOW_COUNTERS &&
+           !(bp->flags & BNXT_FLAG_FC_THREAD) && BNXT_FLOW_XSTATS_EN(bp)) {
+               rte_eal_alarm_set(US_PER_S * BNXT_FC_TIMER,
+                                 bnxt_flow_cnt_alarm_cb,
+                                 (void *)bp);
+               bp->flags |= BNXT_FLAG_FC_THREAD;
+       }
+}
+
+void bnxt_flow_cnt_alarm_cb(void *arg)
+{
+       int rc = 0;
+       struct bnxt *bp = arg;
+
+       if (!bp->flow_stat->rx_fc_out_tbl.va) {
+               PMD_DRV_LOG(ERR, "bp->flow_stat->rx_fc_out_tbl.va is NULL?\n");
+               bnxt_cancel_fc_thread(bp);
+               return;
+       }
+
+       if (!bp->flow_stat->flow_count) {
+               bnxt_cancel_fc_thread(bp);
+               return;
+       }
+
+       if (!bp->eth_dev->data->dev_started) {
+               bnxt_cancel_fc_thread(bp);
+               return;
+       }
+
+       rc = bnxt_flow_stats_req(bp);
+       if (rc) {
+               PMD_DRV_LOG(ERR, "Flow stat alarm not rescheduled.\n");
+               return;
+       }
+
+       rte_eal_alarm_set(US_PER_S * BNXT_FC_TIMER,
+                         bnxt_flow_cnt_alarm_cb,
+                         (void *)bp);
+}
+
+
 static struct rte_flow *
 bnxt_flow_create(struct rte_eth_dev *dev,
                 const struct rte_flow_attr *attr,
@@ -1667,7 +1683,7 @@ bnxt_flow_create(struct rte_eth_dev *dev,
        bool update_flow = false;
        struct rte_flow *flow;
        int ret = 0;
-       uint32_t tun_type;
+       uint32_t tun_type, flow_id;
 
        if (BNXT_VF(bp) && !BNXT_VF_IS_TRUSTED(bp)) {
                rte_flow_error_set(error, EINVAL,
@@ -1770,12 +1786,24 @@ bnxt_flow_create(struct rte_eth_dev *dev,
                filter->enables |=
                        HWRM_CFA_EM_FLOW_ALLOC_INPUT_ENABLES_L2_FILTER_ID;
                ret = bnxt_hwrm_set_em_filter(bp, filter->dst_id, filter);
+               if (ret != 0) {
+                       rte_flow_error_set(error, -ret,
+                                          RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+                                          "Failed to create EM filter");
+                       goto free_filter;
+               }
        }
 
        if (filter->filter_type == HWRM_CFA_NTUPLE_FILTER) {
                filter->enables |=
                        HWRM_CFA_NTUPLE_FILTER_ALLOC_INPUT_ENABLES_L2_FILTER_ID;
                ret = bnxt_hwrm_set_ntuple_filter(bp, filter->dst_id, filter);
+               if (ret != 0) {
+                       rte_flow_error_set(error, -ret,
+                                          RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+                                          "Failed to create ntuple filter");
+                       goto free_filter;
+               }
        }
 
        vnic = find_matching_vnic(bp, filter);
@@ -1788,9 +1816,6 @@ done:
                        goto free_flow;
                }
 
-               STAILQ_INSERT_TAIL(&vnic->filter, filter, next);
-               PMD_DRV_LOG(DEBUG, "Successfully created flow.\n");
-               STAILQ_INSERT_TAIL(&vnic->flow_list, flow, next);
                if (filter->valid_flags & BNXT_FLOW_MARK_FLAG) {
                        PMD_DRV_LOG(DEBUG,
                                    "Mark action: mark id 0x%x, flow id 0x%x\n",
@@ -1799,10 +1824,27 @@ done:
                        /* TCAM and EM should be 16-bit only.
                         * Other modes not supported.
                         */
-                       bp->mark_table[filter->flow_id & BNXT_FLOW_ID_MASK] =
-                               filter->mark;
+                       flow_id = filter->flow_id & BNXT_FLOW_ID_MASK;
+                       if (bp->mark_table[flow_id].valid) {
+                               rte_flow_error_set(error, EEXIST,
+                                                  RTE_FLOW_ERROR_TYPE_HANDLE,
+                                                  NULL,
+                                                  "Flow with mark id exists");
+                               bnxt_clear_one_vnic_filter(bp, filter);
+                               goto free_filter;
+                       }
+                       bp->mark_table[flow_id].valid = true;
+                       bp->mark_table[flow_id].mark_id = filter->mark;
                }
+
+               STAILQ_INSERT_TAIL(&vnic->filter, filter, next);
+               STAILQ_INSERT_TAIL(&vnic->flow_list, flow, next);
+
+               if (BNXT_FLOW_XSTATS_EN(bp))
+                       bp->flow_stat->flow_count++;
                bnxt_release_flow_lock(bp);
+               bnxt_setup_flow_counter(bp);
+               PMD_DRV_LOG(DEBUG, "Successfully created flow.\n");
                return flow;
        }
 
@@ -1876,6 +1918,7 @@ _bnxt_flow_destroy(struct bnxt *bp,
        struct bnxt_filter_info *filter;
        struct bnxt_vnic_info *vnic;
        int ret = 0;
+       uint32_t flow_id;
 
        filter = flow->filter;
        vnic = flow->vnic;
@@ -1894,15 +1937,13 @@ _bnxt_flow_destroy(struct bnxt *bp,
                PMD_DRV_LOG(ERR, "Could not find matching flow\n");
 
        if (filter->valid_flags & BNXT_FLOW_MARK_FLAG) {
-               bp->mark_table[filter->flow_id & BNXT_FLOW_ID_MASK] = 0;
+               flow_id = filter->flow_id & BNXT_FLOW_ID_MASK;
+               memset(&bp->mark_table[flow_id], 0,
+                      sizeof(bp->mark_table[flow_id]));
                filter->flow_id = 0;
        }
 
-       if (filter->filter_type == HWRM_CFA_EM_FILTER)
-               ret = bnxt_hwrm_clear_em_filter(bp, filter);
-       if (filter->filter_type == HWRM_CFA_NTUPLE_FILTER)
-               ret = bnxt_hwrm_clear_ntuple_filter(bp, filter);
-       ret = bnxt_hwrm_clear_l2_filter(bp, filter);
+       ret = bnxt_clear_one_vnic_filter(bp, filter);
 
 done:
        if (!ret) {
@@ -1919,6 +1960,8 @@ done:
                bnxt_free_filter(bp, filter);
                STAILQ_REMOVE(&vnic->flow_list, flow, rte_flow, next);
                rte_free(flow);
+               if (BNXT_FLOW_XSTATS_EN(bp))
+                       bp->flow_stat->flow_count--;
 
                /* If this was the last flow associated with this vnic,
                 * switch the queue back to RSS pool.
@@ -1971,6 +2014,12 @@ bnxt_flow_destroy(struct rte_eth_dev *dev,
        return ret;
 }
 
+void bnxt_cancel_fc_thread(struct bnxt *bp)
+{
+       bp->flags &= ~BNXT_FLAG_FC_THREAD;
+       rte_eal_alarm_cancel(bnxt_flow_cnt_alarm_cb, (void *)bp);
+}
+
 static int
 bnxt_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
 {
@@ -1997,6 +2046,8 @@ bnxt_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
                                break;
                }
        }
+
+       bnxt_cancel_fc_thread(bp);
        bnxt_release_flow_lock(bp);
 
        return ret;