net/ice/base: support FDIR
authorQi Zhang <qi.z.zhang@intel.com>
Mon, 25 Mar 2019 05:44:46 +0000 (13:44 +0800)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 29 Mar 2019 16:25:31 +0000 (17:25 +0100)
Add flow director related support base code.

Signed-off-by: Paul M Stillwell Jr <paul.m.stillwell.jr@intel.com>
Signed-off-by: Qi Zhang <qi.z.zhang@intel.com>
Reviewed-by: Qiming Yang <qiming.yang@intel.com>
Reviewed-by: Wenzhuo Lu <wenzhuo.lu@intel.com>
drivers/net/ice/Makefile
drivers/net/ice/base/ice_adminq_cmd.h
drivers/net/ice/base/ice_common.c
drivers/net/ice/base/ice_common.h
drivers/net/ice/base/ice_fdir.c [new file with mode: 0644]
drivers/net/ice/base/ice_fdir.h [new file with mode: 0644]
drivers/net/ice/base/ice_flex_pipe.c
drivers/net/ice/base/ice_type.h
drivers/net/ice/base/meson.build

index 854e40e..0e5c55e 100644 (file)
@@ -52,6 +52,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_nvm.c
 SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_flex_pipe.c
 SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_flow.c
 SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_dcb.c
+SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_fdir.c
 
 SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_ICE_PMD) += ice_rxtx.c
index 4c5cf54..d2ab9ee 100644 (file)
@@ -105,6 +105,7 @@ struct ice_aqc_list_caps_elem {
 #define ICE_AQC_CAPS_RXQS                              0x0041
 #define ICE_AQC_CAPS_TXQS                              0x0042
 #define ICE_AQC_CAPS_MSIX                              0x0043
+#define ICE_AQC_CAPS_FD                                        0x0045
 #define ICE_AQC_CAPS_MAX_MTU                           0x0047
 
        u8 major_ver;
@@ -1861,6 +1862,16 @@ struct ice_aqc_get_set_rss_lut {
 };
 
 
+/* Clear FD Table Command (direct, 0x0B06) */
+struct ice_aqc_clear_fd_table {
+       u8 clear_type;
+#define CL_FD_VM_VF_TYPE_VSI_IDX       1
+#define CL_FD_VM_VF_TYPE_PF_IDX                2
+       u8 rsvd;
+       __le16 vsi_index;
+       u8 reserved[12];
+};
+
 
 
 
@@ -2210,6 +2221,7 @@ struct ice_aq_desc {
                struct ice_aqc_lldp_stop_start_specific_agent lldp_agent_ctrl;
                struct ice_aqc_get_set_rss_lut get_set_rss_lut;
                struct ice_aqc_get_set_rss_key get_set_rss_key;
+               struct ice_aqc_clear_fd_table clear_fd_table;
                struct ice_aqc_add_txqs add_txqs;
                struct ice_aqc_dis_txqs dis_txqs;
                struct ice_aqc_txqs_cleanup txqs_cleanup;
@@ -2415,6 +2427,7 @@ enum ice_adminq_opc {
        ice_aqc_opc_set_rss_lut                         = 0x0B03,
        ice_aqc_opc_get_rss_key                         = 0x0B04,
        ice_aqc_opc_get_rss_lut                         = 0x0B05,
+       ice_aqc_opc_clear_fd_table                      = 0x0B06,
 
        /* Tx queue handling commands/events */
        ice_aqc_opc_add_txqs                            = 0x0C30,
index 2025927..425f76e 100644 (file)
@@ -805,6 +805,9 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
        if (status)
                goto err_unroll_cqinit;
 
+       /* Set bit to enable Flow Director filters */
+       wr32(hw, PFQF_FD_ENA, PFQF_FD_ENA_FD_ENA_M);
+       INIT_LIST_HEAD(&hw->fdir_list_head);
 
        ice_clear_pxe_mode(hw);
 
@@ -901,6 +904,10 @@ enum ice_status ice_init_hw(struct ice_hw *hw)
        ice_init_flex_flds(hw, ICE_RXDID_FLEX_NIC);
        ice_init_flex_flds(hw, ICE_RXDID_FLEX_NIC_2);
 
+       /* Obtain counter base index which would be used by flow director */
+       status = ice_alloc_fd_res_cntr(hw, &hw->fd_ctr_base);
+       if (status)
+               goto err_unroll_fltr_mgmt_struct;
 
        return ICE_SUCCESS;
 
@@ -926,6 +933,7 @@ err_unroll_cqinit:
  */
 void ice_deinit_hw(struct ice_hw *hw)
 {
+       ice_free_fd_res_cntr(hw, hw->fd_ctr_base);
        ice_cleanup_fltr_mgmt_struct(hw);
 
        ice_sched_cleanup_all(hw);
@@ -1980,6 +1988,34 @@ ice_parse_caps(struct ice_hw *hw, void *buf, u32 cap_count,
                                  "HW caps: MSIX first vector index = %d\n",
                                  caps->msix_vector_first_id);
                        break;
+               case ICE_AQC_CAPS_FD:
+               {
+                       u32 reg_val, val;
+
+                       if (dev_p) {
+                               dev_p->num_flow_director_fltr = number;
+                               ice_debug(hw, ICE_DBG_INIT,
+                                         "HW caps: Dev.fd_fltr =%d\n",
+                                         dev_p->num_flow_director_fltr);
+                       }
+                       if (func_p) {
+                               reg_val = rd32(hw, GLQF_FD_SIZE);
+                               val = (reg_val & GLQF_FD_SIZE_FD_GSIZE_M) >>
+                                     GLQF_FD_SIZE_FD_GSIZE_S;
+                               func_p->fd_fltr_guar =
+                                       ice_get_num_per_func(hw, val);
+                               val = (reg_val & GLQF_FD_SIZE_FD_BSIZE_M) >>
+                                     GLQF_FD_SIZE_FD_BSIZE_S;
+                               func_p->fd_fltr_best_effort = val;
+                               ice_debug(hw, ICE_DBG_INIT,
+                                         "HW:func.fd_fltr guar= %d\n",
+                                         func_p->fd_fltr_guar);
+                               ice_debug(hw, ICE_DBG_INIT,
+                                         "HW:func.fd_fltr best effort=%d\n",
+                                         func_p->fd_fltr_best_effort);
+                       }
+                       break;
+               }
                case ICE_AQC_CAPS_MAX_MTU:
                        caps->max_mtu = number;
                        if (dev_p)
index 9665f32..4dc43dc 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "ice_flex_pipe.h"
 #include "ice_switch.h"
+#include "ice_fdir.h"
 
 enum ice_fw_modes {
        ICE_FW_MODE_NORMAL,
diff --git a/drivers/net/ice/base/ice_fdir.c b/drivers/net/ice/base/ice_fdir.c
new file mode 100644 (file)
index 0000000..4bc8e6d
--- /dev/null
@@ -0,0 +1,742 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2001-2019
+ */
+
+#include "ice_common.h"
+#include "ice_fdir.h"
+
+/* These are dummy packet headers used to program flow director filters. */
+static const u8 ice_fdir_tcpv4_pkt[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00,
+       0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x40, 0x06,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00,
+       0x20, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const u8 ice_fdir_udpv4_pkt[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00,
+       0x00, 0x1C, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+};
+
+static const u8 ice_fdir_sctpv4_pkt[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00,
+       0x00, 0x20, 0x00, 0x00, 0x40, 0x00, 0x40, 0x84,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const u8 ice_fdir_ipv4_pkt[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00,
+       0x00, 0x14, 0x00, 0x00, 0x40, 0x00, 0x40, 0x10,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00
+};
+
+static const u8 ice_fdir_tcpv6_pkt[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x86, 0xDD, 0x60, 0x00,
+       0x00, 0x00, 0x00, 0x14, 0x06, 0x40, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x50, 0x00, 0x20, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+};
+
+static const u8 ice_fdir_udpv6_pkt[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x86, 0xDD, 0x60, 0x00,
+       0x00, 0x00, 0x00, 0x08, 0x11, 0x40, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+};
+
+static const u8 ice_fdir_sctpv6_pkt[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x86, 0xDD, 0x60, 0x00,
+       0x00, 0x00, 0x00, 0x0C, 0x84, 0x40, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00,
+};
+
+static const u8 ice_fdir_ipv6_pkt[] = {
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x86, 0xDD, 0x60, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x3B, 0x40, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* Flow Director dummy packet table */
+static const struct ice_fdir_base_pkt ice_fdir_pkt[] = {
+       {
+               ICE_FLTR_PTYPE_NONF_IPV4_TCP,
+               sizeof(ice_fdir_tcpv4_pkt),
+               ice_fdir_tcpv4_pkt,
+       },
+       {
+               ICE_FLTR_PTYPE_NONF_IPV4_UDP,
+               sizeof(ice_fdir_udpv4_pkt),
+               ice_fdir_udpv4_pkt,
+       },
+       {
+               ICE_FLTR_PTYPE_NONF_IPV4_SCTP,
+               sizeof(ice_fdir_sctpv4_pkt),
+               ice_fdir_sctpv4_pkt,
+       },
+       {
+               ICE_FLTR_PTYPE_NONF_IPV4_OTHER,
+               sizeof(ice_fdir_ipv4_pkt),
+               ice_fdir_ipv4_pkt,
+       },
+       {
+               ICE_FLTR_PTYPE_NONF_IPV6_TCP,
+               sizeof(ice_fdir_tcpv6_pkt),
+               ice_fdir_tcpv6_pkt,
+       },
+       {
+               ICE_FLTR_PTYPE_NONF_IPV6_UDP,
+               sizeof(ice_fdir_udpv6_pkt),
+               ice_fdir_udpv6_pkt,
+       },
+       {
+               ICE_FLTR_PTYPE_NONF_IPV6_SCTP,
+               sizeof(ice_fdir_sctpv6_pkt),
+               ice_fdir_sctpv6_pkt,
+       },
+       {
+               ICE_FLTR_PTYPE_NONF_IPV6_OTHER,
+               sizeof(ice_fdir_ipv6_pkt),
+               ice_fdir_ipv6_pkt,
+       },
+};
+
+#define ICE_FDIR_NUM_PKT ARRAY_SIZE(ice_fdir_pkt)
+
+/* Flow Direcotr (FD) filter program descriptor Context */
+static const struct ice_ctx_ele ice_fd_fltr_desc_ctx_info[] = {
+                                          /* Field             Width   LSB */
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, qindex,             11,     0),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, comp_q,             1,      11),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, comp_report,        2,      12),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, fd_space,           2,      14),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, cnt_index,          13,     16),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, cnt_ena,            2,      29),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, evict_ena,          1,      31),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, toq,                3,      32),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, toq_prio,           3,      35),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, dpu_recipe,         2,      38),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, drop,               1,      40),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, flex_prio,          3,      41),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, flex_mdid,          4,      44),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, flex_val,           16,     48),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, dtype,              4,      64),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, pcmd,               1,      68),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, desc_prof_prio,     3,      69),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, desc_prof,          6,      72),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, fd_vsi,             10,     78),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, swap,               1,      88),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, fdid_prio,          3,      89),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, fdid_mdid,          4,      92),
+       ICE_CTX_STORE(ice_fd_fltr_desc_ctx, fdid,               32,     96),
+       { 0 }
+};
+
+/**
+ * ice_set_dflt_val_fd_desc
+ * @fd_fltr_ctx: pointer to fd filter descriptor
+ */
+void
+ice_set_dflt_val_fd_desc(struct ice_fd_fltr_desc_ctx *fd_fltr_ctx)
+{
+       fd_fltr_ctx->comp_q = ICE_FXD_FLTR_QW0_COMP_Q_ZERO;
+       fd_fltr_ctx->comp_report = ICE_FXD_FLTR_QW0_COMP_REPORT_SW_FAIL;
+       fd_fltr_ctx->fd_space = ICE_FXD_FLTR_QW0_FD_SPACE_GUAR_BEST;
+       fd_fltr_ctx->cnt_ena = ICE_FXD_FLTR_QW0_STAT_ENA_PKTS;
+       fd_fltr_ctx->evict_ena = ICE_FXD_FLTR_QW0_EVICT_ENA_TRUE;
+       fd_fltr_ctx->toq = ICE_FXD_FLTR_QW0_TO_Q_EQUALS_QINDEX;
+       fd_fltr_ctx->toq_prio = ICE_FXD_FLTR_QW0_TO_Q_PRIO1;
+       fd_fltr_ctx->dpu_recipe = ICE_FXD_FLTR_QW0_DPU_RECIPE_DFLT;
+       fd_fltr_ctx->drop = ICE_FXD_FLTR_QW0_DROP_NO;
+       fd_fltr_ctx->flex_prio = ICE_FXD_FLTR_QW0_FLEX_PRI_NONE;
+       fd_fltr_ctx->flex_mdid = ICE_FXD_FLTR_QW0_FLEX_MDID0;
+       fd_fltr_ctx->flex_val = ICE_FXD_FLTR_QW0_FLEX_VAL0;
+       fd_fltr_ctx->dtype = ICE_TX_DESC_DTYPE_FLTR_PROG;
+       fd_fltr_ctx->desc_prof_prio = ICE_FXD_FLTR_QW1_PROF_PRIO_ZERO;
+       fd_fltr_ctx->desc_prof = ICE_FXD_FLTR_QW1_PROF_ZERO;
+       fd_fltr_ctx->swap = ICE_FXD_FLTR_QW1_SWAP_SET;
+       fd_fltr_ctx->fdid_prio = ICE_FXD_FLTR_QW1_FDID_PRI_ZERO;
+       fd_fltr_ctx->fdid_mdid = ICE_FXD_FLTR_QW1_FDID_MDID_FD;
+       fd_fltr_ctx->fdid = ICE_FXD_FLTR_QW1_FDID_ZERO;
+}
+
+/**
+ * ice_fdir_get_prgm_desc - set a fdir descriptor from a fdir filter struct
+ * @hw: pointer to the hardware structure
+ * @input: filter
+ * @fdesc: filter descriptor
+ * @add: if add is true, this is an add operation, false implies delete
+ */
+void
+ice_fdir_get_prgm_desc(struct ice_hw *hw, struct ice_fdir_fltr *input,
+                      struct ice_fltr_desc *fdesc, bool add)
+{
+       struct ice_fd_fltr_desc_ctx fdir_fltr_ctx = { 0 };
+
+       /* set default context info */
+       ice_set_dflt_val_fd_desc(&fdir_fltr_ctx);
+
+       /* change sideband filtering values */
+       fdir_fltr_ctx.fdid = input->fltr_id;
+       if (input->dest_ctl == ICE_FLTR_PRGM_DESC_DEST_DROP_PKT) {
+               fdir_fltr_ctx.drop = ICE_FXD_FLTR_QW0_DROP_YES;
+               fdir_fltr_ctx.qindex = 0;
+       } else {
+               fdir_fltr_ctx.drop = ICE_FXD_FLTR_QW0_DROP_NO;
+               fdir_fltr_ctx.qindex = input->q_index;
+       }
+       fdir_fltr_ctx.cnt_ena = ICE_FXD_FLTR_QW0_STAT_ENA_PKTS;
+       fdir_fltr_ctx.cnt_index = input->cnt_index;
+       fdir_fltr_ctx.fd_vsi = ice_get_hw_vsi_num(hw, input->dest_vsi);
+       fdir_fltr_ctx.evict_ena = ICE_FXD_FLTR_QW0_EVICT_ENA_FALSE;
+       fdir_fltr_ctx.toq_prio = 3;
+       fdir_fltr_ctx.pcmd = (add) ? ICE_FXD_FLTR_QW1_PCMD_ADD :
+               ICE_FXD_FLTR_QW1_PCMD_REMOVE;
+       fdir_fltr_ctx.swap = ICE_FXD_FLTR_QW1_SWAP_NOT_SET;
+       fdir_fltr_ctx.comp_q = ICE_FXD_FLTR_QW0_COMP_Q_ZERO;
+       fdir_fltr_ctx.comp_report = ICE_FXD_FLTR_QW0_COMP_REPORT_SW;
+       fdir_fltr_ctx.fdid_prio = 3;
+       fdir_fltr_ctx.desc_prof = 1;
+       fdir_fltr_ctx.desc_prof_prio = 3;
+       ice_set_fd_desc_val(&fdir_fltr_ctx, fdesc);
+}
+
+/**
+ * ice_set_fd_desc_val
+ * @fd_fltr_ctx: pointer to fd filter descriptor context
+ * @fdir_desc: populated with fd filter descriptor values
+ */
+void
+ice_set_fd_desc_val(struct ice_fd_fltr_desc_ctx *fd_fltr_ctx,
+                   struct ice_fltr_desc *fdir_desc)
+{
+       u64 ctx_buf[2] = { 0 };
+
+       ice_set_ctx((u8 *)fd_fltr_ctx, (u8 *)ctx_buf,
+                   ice_fd_fltr_desc_ctx_info);
+       fdir_desc->qidx_compq_space_stat = CPU_TO_LE64(ctx_buf[0]);
+       fdir_desc->dtype_cmd_vsi_fdid = CPU_TO_LE64(ctx_buf[1]);
+}
+
+/**
+ * ice_alloc_fd_res_cntr - obtain counter resource for FD type
+ * @hw: pointer to the hardware structure
+ * @cntr_id: returns counter index
+ */
+enum ice_status ice_alloc_fd_res_cntr(struct ice_hw *hw, u16 *cntr_id)
+{
+       return ice_alloc_res_cntr(hw, ICE_AQC_RES_TYPE_FDIR_COUNTER_BLOCK,
+                                 ICE_AQC_RES_TYPE_FLAG_DEDICATED, 1, cntr_id);
+}
+
+/**
+ * ice_free_fd_res_cntr - Free counter resource for FD type
+ * @hw: pointer to the hardware structure
+ * @cntr_id: counter index to be freed
+ */
+enum ice_status ice_free_fd_res_cntr(struct ice_hw *hw, u16 cntr_id)
+{
+       return ice_free_res_cntr(hw, ICE_AQC_RES_TYPE_FDIR_COUNTER_BLOCK,
+                                ICE_AQC_RES_TYPE_FLAG_DEDICATED, 1, cntr_id);
+}
+
+/**
+ * ice_alloc_fd_guar_item - allocate resource for FD guaranteed entries
+ * @hw: pointer to the hardware structure
+ * @cntr_id: returns counter index
+ * @num_fltr: number of filter entries to be allocated
+ */
+enum ice_status
+ice_alloc_fd_guar_item(struct ice_hw *hw, u16 *cntr_id, u16 num_fltr)
+{
+       return ice_alloc_res_cntr(hw, ICE_AQC_RES_TYPE_FDIR_GUARANTEED_ENTRIES,
+                                 ICE_AQC_RES_TYPE_FLAG_DEDICATED, num_fltr,
+                                 cntr_id);
+}
+
+/**
+ * ice_free_fd_guar_item - Free flow director guaranteed entries
+ * @hw: pointer to the hardware structure
+ * @cntr_id: counter index that needs to be freed
+ * @num_fltr: number of filters to be freed
+ */
+enum ice_status
+ice_free_fd_guar_item(struct ice_hw *hw, u16 cntr_id, u16 num_fltr)
+{
+       return ice_free_res_cntr(hw, ICE_AQC_RES_TYPE_FDIR_GUARANTEED_ENTRIES,
+                                ICE_AQC_RES_TYPE_FLAG_DEDICATED, num_fltr,
+                                cntr_id);
+}
+
+/**
+ * ice_alloc_fd_shrd_item - allocate resource for flow director shared entries
+ * @hw: pointer to the hardware structure
+ * @cntr_id: returns counter index
+ * @num_fltr: number of filter entries to be allocated
+ */
+enum ice_status
+ice_alloc_fd_shrd_item(struct ice_hw *hw, u16 *cntr_id, u16 num_fltr)
+{
+       return ice_alloc_res_cntr(hw, ICE_AQC_RES_TYPE_FDIR_SHARED_ENTRIES,
+                                 ICE_AQC_RES_TYPE_FLAG_DEDICATED, num_fltr,
+                                 cntr_id);
+}
+
+/**
+ * ice_free_fd_shrd_item - Free flow director shared entries
+ * @hw: pointer to the hardware structure
+ * @cntr_id: counter index that needs to be freed
+ * @num_fltr: number of filters to be freed
+ */
+enum ice_status
+ice_free_fd_shrd_item(struct ice_hw *hw, u16 cntr_id, u16 num_fltr)
+{
+       return ice_free_res_cntr(hw, ICE_AQC_RES_TYPE_FDIR_SHARED_ENTRIES,
+                                ICE_AQC_RES_TYPE_FLAG_DEDICATED, num_fltr,
+                                cntr_id);
+}
+
+/**
+ * ice_get_fdir_cnt_all - get the number of Flow Director filters
+ * @hw: hardware data structure
+ *
+ * Returns the number of filters available on device
+ */
+int ice_get_fdir_cnt_all(struct ice_hw *hw)
+{
+       return hw->func_caps.fd_fltr_guar +
+              hw->func_caps.fd_fltr_best_effort;
+}
+
+/**
+ * ice_pkt_insert_ipv6_addr - insert a be32 IPv6 address into a memory buffer.
+ * @pkt: packet buffer
+ * @offset: offset into buffer
+ * @addr: IPv6 address to convert and insert into pkt at offset
+ */
+static void ice_pkt_insert_ipv6_addr(u8 *pkt, int offset, __be32 *addr)
+{
+       int idx;
+
+       for (idx = 0; idx < ICE_IPV6_ADDR_LEN_AS_U32; idx++)
+               ice_memcpy(pkt + offset + idx * sizeof(*addr), &addr[idx],
+                          sizeof(*addr), ICE_NONDMA_TO_NONDMA);
+}
+
+/**
+ * ice_pkt_insert_u16 - insert a be16 value into a memory buffer.
+ * @pkt: packet buffer
+ * @offset: offset into buffer
+ * @data: 16 bit value to convert and insert into pkt at offset
+ */
+static void ice_pkt_insert_u16(u8 *pkt, int offset, __be16 data)
+{
+       ice_memcpy(pkt + offset, &data, sizeof(data), ICE_NONDMA_TO_NONDMA);
+}
+
+/**
+ * ice_pkt_insert_u32 - insert a be32 value into a memory buffer.
+ * @pkt: packet buffer
+ * @offset: offset into buffer
+ * @data: 32 bit value to convert and insert into pkt at offset
+ */
+static void ice_pkt_insert_u32(u8 *pkt, int offset, __be32 data)
+{
+       ice_memcpy(pkt + offset, &data, sizeof(data), ICE_NONDMA_TO_NONDMA);
+}
+
+/**
+ * ice_fdir_get_prgm_pkt - generate a dummy packet
+ * @input: flow director filter data structure
+ * @pkt: pointer to return filter packet
+ * @frag: generate a fragment packet
+ */
+enum ice_status
+ice_fdir_get_prgm_pkt(struct ice_fdir_fltr *input, u8 *pkt, bool frag)
+{
+       enum ice_fltr_ptype flow;
+       u16 idx;
+
+       if (input->flow_type == ICE_FLTR_PTYPE_NONF_IPV4_OTHER) {
+               switch (input->ip.v4.proto) {
+               case ICE_IP_PROTO_TCP:
+                       flow = ICE_FLTR_PTYPE_NONF_IPV4_TCP;
+                       break;
+               case ICE_IP_PROTO_UDP:
+                       flow = ICE_FLTR_PTYPE_NONF_IPV4_UDP;
+                       break;
+               case ICE_IP_PROTO_SCTP:
+                       flow = ICE_FLTR_PTYPE_NONF_IPV4_SCTP;
+                       break;
+               case ICE_IP_PROTO_IP:
+                       flow = ICE_FLTR_PTYPE_NONF_IPV4_OTHER;
+                       break;
+               default:
+                       return ICE_ERR_PARAM;
+               }
+       } else if (input->flow_type == ICE_FLTR_PTYPE_NONF_IPV6_OTHER) {
+               switch (input->ip.v6.proto) {
+               case ICE_IP_PROTO_TCP:
+                       flow = ICE_FLTR_PTYPE_NONF_IPV6_TCP;
+                       break;
+               case ICE_IP_PROTO_UDP:
+                       flow = ICE_FLTR_PTYPE_NONF_IPV6_UDP;
+                       break;
+               case ICE_IP_PROTO_SCTP:
+                       flow = ICE_FLTR_PTYPE_NONF_IPV6_SCTP;
+                       break;
+               case ICE_IP_PROTO_IP:
+                       flow = ICE_FLTR_PTYPE_NONF_IPV6_OTHER;
+                       break;
+               default:
+                       return ICE_ERR_PARAM;
+               }
+       } else {
+               flow = input->flow_type;
+       }
+
+       for (idx = 0; idx < ICE_FDIR_NUM_PKT; idx++)
+               if (ice_fdir_pkt[idx].flow == flow)
+                       break;
+       if (idx == ICE_FDIR_NUM_PKT)
+               return ICE_ERR_PARAM;
+       ice_memcpy(pkt, ice_fdir_pkt[idx].pkt, ice_fdir_pkt[idx].pkt_len,
+                  ICE_NONDMA_TO_NONDMA);
+
+       switch (flow) {
+       case ICE_FLTR_PTYPE_NONF_IPV4_TCP:
+               ice_pkt_insert_u32(pkt, ICE_IPV4_DST_ADDR_OFFSET,
+                                  input->ip.v4.dst_ip);
+               ice_pkt_insert_u16(pkt, ICE_IPV4_TCP_DST_PORT_OFFSET,
+                                  input->ip.v4.dst_port);
+               ice_pkt_insert_u32(pkt, ICE_IPV4_SRC_ADDR_OFFSET,
+                                  input->ip.v4.src_ip);
+               ice_pkt_insert_u16(pkt, ICE_IPV4_TCP_SRC_PORT_OFFSET,
+                                  input->ip.v4.src_port);
+               if (frag)
+                       pkt[20] = ICE_FDIR_IPV4_PKT_FLAG_DF;
+               break;
+       case ICE_FLTR_PTYPE_NONF_IPV4_UDP:
+               ice_pkt_insert_u32(pkt, ICE_IPV4_DST_ADDR_OFFSET,
+                                  input->ip.v4.dst_ip);
+               ice_pkt_insert_u16(pkt, ICE_IPV4_UDP_DST_PORT_OFFSET,
+                                  input->ip.v4.dst_port);
+               ice_pkt_insert_u32(pkt, ICE_IPV4_SRC_ADDR_OFFSET,
+                                  input->ip.v4.src_ip);
+               ice_pkt_insert_u16(pkt, ICE_IPV4_UDP_SRC_PORT_OFFSET,
+                                  input->ip.v4.src_port);
+               break;
+       case ICE_FLTR_PTYPE_NONF_IPV4_SCTP:
+               ice_pkt_insert_u32(pkt, ICE_IPV4_DST_ADDR_OFFSET,
+                                  input->ip.v4.dst_ip);
+               ice_pkt_insert_u16(pkt, ICE_IPV4_SCTP_DST_PORT_OFFSET,
+                                  input->ip.v4.dst_port);
+               ice_pkt_insert_u32(pkt, ICE_IPV4_SRC_ADDR_OFFSET,
+                                  input->ip.v4.src_ip);
+               ice_pkt_insert_u16(pkt, ICE_IPV4_SCTP_SRC_PORT_OFFSET,
+                                  input->ip.v4.src_port);
+               break;
+       case ICE_FLTR_PTYPE_NONF_IPV4_OTHER:
+               ice_pkt_insert_u32(pkt, ICE_IPV4_DST_ADDR_OFFSET,
+                                  input->ip.v4.dst_ip);
+               ice_pkt_insert_u32(pkt, ICE_IPV4_SRC_ADDR_OFFSET,
+                                  input->ip.v4.src_ip);
+               ice_pkt_insert_u16(pkt, ICE_IPV4_PROTO_OFFSET, 0);
+               break;
+       case ICE_FLTR_PTYPE_NONF_IPV6_TCP:
+               ice_pkt_insert_ipv6_addr(pkt, ICE_IPV6_DST_ADDR_OFFSET,
+                                        input->ip.v6.dst_ip);
+               ice_pkt_insert_ipv6_addr(pkt, ICE_IPV6_SRC_ADDR_OFFSET,
+                                        input->ip.v6.src_ip);
+               ice_pkt_insert_u16(pkt, ICE_IPV6_TCP_DST_PORT_OFFSET,
+                                  input->ip.v6.dst_port);
+               ice_pkt_insert_u16(pkt, ICE_IPV6_TCP_SRC_PORT_OFFSET,
+                                  input->ip.v6.src_port);
+               break;
+       case ICE_FLTR_PTYPE_NONF_IPV6_UDP:
+               ice_pkt_insert_ipv6_addr(pkt, ICE_IPV6_DST_ADDR_OFFSET,
+                                        input->ip.v6.dst_ip);
+               ice_pkt_insert_ipv6_addr(pkt, ICE_IPV6_SRC_ADDR_OFFSET,
+                                        input->ip.v6.src_ip);
+               ice_pkt_insert_u16(pkt, ICE_IPV6_UDP_DST_PORT_OFFSET,
+                                  input->ip.v6.dst_port);
+               ice_pkt_insert_u16(pkt, ICE_IPV6_UDP_SRC_PORT_OFFSET,
+                                  input->ip.v6.src_port);
+               break;
+       case ICE_FLTR_PTYPE_NONF_IPV6_SCTP:
+               ice_pkt_insert_ipv6_addr(pkt, ICE_IPV6_DST_ADDR_OFFSET,
+                                        input->ip.v6.dst_ip);
+               ice_pkt_insert_ipv6_addr(pkt, ICE_IPV6_SRC_ADDR_OFFSET,
+                                        input->ip.v6.src_ip);
+               ice_pkt_insert_u16(pkt, ICE_IPV6_SCTP_DST_PORT_OFFSET,
+                                  input->ip.v6.dst_port);
+               ice_pkt_insert_u16(pkt, ICE_IPV6_SCTP_SRC_PORT_OFFSET,
+                                  input->ip.v6.src_port);
+               break;
+       case ICE_FLTR_PTYPE_NONF_IPV6_OTHER:
+               ice_pkt_insert_ipv6_addr(pkt, ICE_IPV6_DST_ADDR_OFFSET,
+                                        input->ip.v6.dst_ip);
+               ice_pkt_insert_ipv6_addr(pkt, ICE_IPV6_SRC_ADDR_OFFSET,
+                                        input->ip.v6.src_ip);
+               break;
+       default:
+               return ICE_ERR_PARAM;
+       }
+
+       if (input->flex_fltr)
+               ice_pkt_insert_u16(pkt, input->flex_offset, input->flex_word);
+
+       return ICE_SUCCESS;
+}
+
+/**
+ * ice_fdir_has_frag - does flow type have 2 ptypes
+ * @flow: flow ptype
+ *
+ * returns true is there is a fragment packet for this ptype
+ */
+bool ice_fdir_has_frag(enum ice_fltr_ptype flow)
+{
+       if (flow == ICE_FLTR_PTYPE_NONF_IPV4_OTHER)
+               return true;
+       else
+               return false;
+}
+
+/**
+ * ice_fdir_find_by_idx - find filter with idx
+ * @hw: pointer to hardware structure
+ * @fltr_idx: index to find.
+ *
+ * Returns pointer to filter if found or null
+ */
+struct ice_fdir_fltr *
+ice_fdir_find_fltr_by_idx(struct ice_hw *hw, u32 fltr_idx)
+{
+       struct ice_fdir_fltr *rule = NULL;
+
+       LIST_FOR_EACH_ENTRY(rule, &hw->fdir_list_head, ice_fdir_fltr,
+                           fltr_node) {
+               /* rule ID found in the list */
+               if (fltr_idx == rule->fltr_id)
+                       return rule;
+               if (fltr_idx < rule->fltr_id)
+                       break;
+       }
+       return NULL;
+}
+
+/**
+ * ice_fdir_list_add_fltr - add a new node to the flow director filter list
+ * @hw: hardware structure
+ * @fltr: filter node to add to structure
+ */
+void ice_fdir_list_add_fltr(struct ice_hw *hw, struct ice_fdir_fltr *fltr)
+{
+       struct ice_fdir_fltr *rule, *parent = NULL;
+
+       LIST_FOR_EACH_ENTRY(rule, &hw->fdir_list_head, ice_fdir_fltr,
+                           fltr_node) {
+               /* rule ID found or pass its spot in the list */
+               if (rule->fltr_id >= fltr->fltr_id)
+                       break;
+               parent = rule;
+       }
+
+       if (parent)
+               LIST_ADD_AFTER(&fltr->fltr_node, &parent->fltr_node);
+       else
+               LIST_ADD(&fltr->fltr_node, &hw->fdir_list_head);
+}
+
+/**
+ * ice_fdir_update_cntrs - increment / decrement filter counter
+ * @hw: pointer to hardware structure
+ * @flow: filter flow type
+ * @add: true implies filters added
+ */
+void
+ice_fdir_update_cntrs(struct ice_hw *hw, enum ice_fltr_ptype flow, bool add)
+{
+       int incr;
+
+       incr = (add) ? 1 : -1;
+       hw->fdir_active_fltr += incr;
+       if (flow == ICE_FLTR_PTYPE_NONF_NONE || flow >= ICE_FLTR_PTYPE_MAX)
+               ice_debug(hw, ICE_DBG_SW, "Unknown filter type %d\n", flow);
+       else
+               hw->fdir_fltr_cnt[flow] += incr;
+}
+
+/**
+ * ice_cmp_ipv6_addr - compare 2 IP v6 addresses
+ * @a: IP v6 address
+ * @b: IP v6 address
+ *
+ * Returns 0 on equal, returns non-0 if different
+ */
+static int ice_cmp_ipv6_addr(__be32 *a, __be32 *b)
+{
+       return memcmp(a, b, 4 * sizeof(__be32));
+}
+
+/**
+ * ice_fdir_comp_ipv6_rules - compare 2 filters
+ * @a: a Flow Director filter data structure
+ * @b: a Flow Director filter data structure
+ * @v6: bool true if v6 filter
+ *
+ * Returns true if the filters match
+ */
+static bool
+ice_fdir_comp_rules(struct ice_fdir_fltr *a,  struct ice_fdir_fltr *b, bool v6)
+{
+       enum ice_fltr_ptype flow_type = a->flow_type;
+
+       /* The calling function already checks that the two filters have the
+        * same flow_type.
+        */
+       if (!v6) {
+               if (flow_type == ICE_FLTR_PTYPE_NONF_IPV4_TCP ||
+                   flow_type == ICE_FLTR_PTYPE_NONF_IPV4_UDP ||
+                   flow_type == ICE_FLTR_PTYPE_NONF_IPV4_SCTP) {
+                       if (a->ip.v4.dst_ip == b->ip.v4.dst_ip &&
+                           a->ip.v4.src_ip == b->ip.v4.src_ip &&
+                           a->ip.v4.dst_port == b->ip.v4.dst_port &&
+                           a->ip.v4.src_port == b->ip.v4.src_port)
+                               return true;
+               } else if (flow_type == ICE_FLTR_PTYPE_NONF_IPV4_OTHER) {
+                       if (a->ip.v4.dst_ip == b->ip.v4.dst_ip &&
+                           a->ip.v4.src_ip == b->ip.v4.src_ip &&
+                           a->ip.v4.l4_header == b->ip.v4.l4_header &&
+                           a->ip.v4.proto == b->ip.v4.proto &&
+                           a->ip.v4.ip_ver == b->ip.v4.ip_ver &&
+                           a->ip.v4.tos == b->ip.v4.tos)
+                               return true;
+               }
+       } else {
+               if (flow_type == ICE_FLTR_PTYPE_NONF_IPV6_UDP ||
+                   flow_type == ICE_FLTR_PTYPE_NONF_IPV6_TCP ||
+                   flow_type == ICE_FLTR_PTYPE_NONF_IPV6_SCTP) {
+                       if (a->ip.v6.dst_port == b->ip.v6.dst_port &&
+                           a->ip.v6.src_port == b->ip.v6.src_port &&
+                           !ice_cmp_ipv6_addr(a->ip.v6.dst_ip,
+                                              b->ip.v6.dst_ip) &&
+                           !ice_cmp_ipv6_addr(a->ip.v6.src_ip,
+                                              b->ip.v6.src_ip))
+                               return true;
+               } else if (flow_type == ICE_FLTR_PTYPE_NONF_IPV6_OTHER) {
+                       if (a->ip.v6.dst_port == b->ip.v6.dst_port &&
+                           a->ip.v6.src_port == b->ip.v6.src_port)
+                               return true;
+               }
+       }
+
+       return false;
+}
+
+/**
+ * ice_fdir_is_dup_fltr - test if filter is already in list for PF
+ * @hw: hardware data structure
+ * @input: Flow Director filter data structure
+ *
+ * Returns true if the filter is found in the list
+ */
+bool ice_fdir_is_dup_fltr(struct ice_hw *hw, struct ice_fdir_fltr *input)
+{
+       enum ice_fltr_ptype flow_type;
+       struct ice_fdir_fltr *rule;
+       bool ret = false;
+
+       rule = NULL;
+
+       LIST_FOR_EACH_ENTRY(rule, &hw->fdir_list_head, ice_fdir_fltr,
+                           fltr_node) {
+               if (rule->flow_type == input->flow_type) {
+                       flow_type = input->flow_type;
+                       if (flow_type == ICE_FLTR_PTYPE_NONF_IPV4_TCP ||
+                           flow_type == ICE_FLTR_PTYPE_NONF_IPV4_UDP ||
+                           flow_type == ICE_FLTR_PTYPE_NONF_IPV4_SCTP ||
+                           flow_type == ICE_FLTR_PTYPE_NONF_IPV4_OTHER)
+                               ret = ice_fdir_comp_rules(rule, input, false);
+                       else
+                               ret = ice_fdir_comp_rules(rule, input, true);
+                       if (ret)
+                               break;
+               }
+       }
+
+       return ret;
+}
+
+/**
+ * ice_clear_vsi_fd_table - admin command to clear FD table for a VSI
+ * @hw: hardware data structure
+ * @vsi_num: vsi_num (HW VSI num)
+ *
+ * Clears FD table entries by issuing admin command (direct, 0x0B06)
+ * Must to pass valid vsi_num as returned by "AddVSI".
+ */
+enum ice_status ice_clear_vsi_fd_table(struct ice_hw *hw, u16 vsi_num)
+{
+       struct ice_aqc_clear_fd_table *cmd;
+       struct ice_aq_desc desc;
+
+       cmd = &desc.params.clear_fd_table;
+       ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_clear_fd_table);
+       cmd->clear_type = CL_FD_VM_VF_TYPE_VSI_IDX;
+
+       cmd->vsi_index = CPU_TO_LE16(vsi_num);
+       return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
+}
+
+/**
+ * ice_clear_pf_fd_table - admin command to clear FD table for PF
+ * @hw: hardware data structure
+ *
+ * Clears FD table entries for a PF by issuing admin command (direct, 0x0B06)
+ */
+enum ice_status ice_clear_pf_fd_table(struct ice_hw *hw)
+{
+       struct ice_aqc_clear_fd_table *cmd;
+       struct ice_aq_desc desc;
+
+       cmd = &desc.params.clear_fd_table;
+       ice_fill_dflt_direct_cmd_desc(&desc, ice_aqc_opc_clear_fd_table);
+       cmd->clear_type = CL_FD_VM_VF_TYPE_PF_IDX;
+       /* vsi_index must be 0 to clear FD table for a PF */
+       cmd->vsi_index = CPU_TO_LE16(0);
+
+       return ice_aq_send_cmd(hw, &desc, NULL, 0, NULL);
+}
diff --git a/drivers/net/ice/base/ice_fdir.h b/drivers/net/ice/base/ice_fdir.h
new file mode 100644 (file)
index 0000000..2ecb147
--- /dev/null
@@ -0,0 +1,202 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2001-2019
+ */
+
+#ifndef _ICE_FDIR_H_
+#define _ICE_FDIR_H_
+
+#include "ice_common.h"
+
+/* Flow Director (FD) Filter Programming descriptor */
+struct ice_fd_fltr_desc_ctx {
+       u32 fdid;
+       u16 qindex;
+       u16 cnt_index;
+       u16 fd_vsi;
+       u16 flex_val;
+       u8 comp_q;
+       u8 comp_report;
+       u8 fd_space;
+       u8 cnt_ena;
+       u8 evict_ena;
+       u8 toq;
+       u8 toq_prio;
+       u8 dpu_recipe;
+       u8 drop;
+       u8 flex_prio;
+       u8 flex_mdid;
+       u8 dtype;
+       u8 pcmd;
+       u8 desc_prof_prio;
+       u8 desc_prof;
+       u8 swap;
+       u8 fdid_prio;
+       u8 fdid_mdid;
+};
+
+enum ice_status ice_alloc_fd_res_cntr(struct ice_hw *hw, u16 *cntr_id);
+enum ice_status ice_free_fd_res_cntr(struct ice_hw *hw, u16 cntr_id);
+void
+ice_set_fd_desc_val(struct ice_fd_fltr_desc_ctx *fd_fltr_ctx,
+                   struct ice_fltr_desc *fdir_desc);
+void ice_set_dflt_val_fd_desc(struct ice_fd_fltr_desc_ctx *fd_fltr_ctx);
+enum ice_status
+ice_alloc_fd_guar_item(struct ice_hw *hw, u16 *cntr_id, u16 num_fltr);
+enum ice_status
+ice_free_fd_guar_item(struct ice_hw *hw, u16 cntr_id, u16 num_fltr);
+enum ice_status
+ice_alloc_fd_shrd_item(struct ice_hw *hw, u16 *cntr_id, u16 num_fltr);
+enum ice_status
+ice_free_fd_shrd_item(struct ice_hw *hw, u16 cntr_id, u16 num_fltr);
+enum ice_status ice_clear_vsi_fd_table(struct ice_hw *hw, u16 vsi_num);
+enum ice_status ice_clear_pf_fd_table(struct ice_hw *hw);
+
+#define ICE_FDIR_IP_PROTOCOLS
+#define ICE_IP_PROTO_TCP               6
+#define ICE_IP_PROTO_UDP               17
+#define ICE_IP_PROTO_SCTP              132
+#define ICE_IP_PROTO_IP                        0
+#define ICE_IP_PROTO_ESP               50
+
+#define ICE_FDIR_MAX_RAW_PKT_SIZE      512
+#define ICE_FDIR_BUF_FULL_MARGIN       10
+#define ICE_FDIR_BUF_HEAD_ROOM         32
+
+/* macros for offsets into packets for flow director programming */
+#define ICE_IPV4_SRC_ADDR_OFFSET       26
+#define ICE_IPV4_DST_ADDR_OFFSET       30
+#define ICE_IPV4_TCP_SRC_PORT_OFFSET   34
+#define ICE_IPV4_TCP_DST_PORT_OFFSET   36
+#define ICE_IPV4_UDP_SRC_PORT_OFFSET   34
+#define ICE_IPV4_UDP_DST_PORT_OFFSET   36
+#define ICE_IPV4_SCTP_SRC_PORT_OFFSET  34
+#define ICE_IPV4_SCTP_DST_PORT_OFFSET  36
+#define ICE_IPV4_PROTO_OFFSET          23
+#define ICE_IPV6_SRC_ADDR_OFFSET       22
+#define ICE_IPV6_DST_ADDR_OFFSET       38
+#define ICE_IPV6_TCP_SRC_PORT_OFFSET   54
+#define ICE_IPV6_TCP_DST_PORT_OFFSET   56
+#define ICE_IPV6_UDP_SRC_PORT_OFFSET   54
+#define ICE_IPV6_UDP_DST_PORT_OFFSET   56
+#define ICE_IPV6_SCTP_SRC_PORT_OFFSET  54
+#define ICE_IPV6_SCTP_DST_PORT_OFFSET  56
+
+#define ICE_FDIR_MAX_FLTRS             16384
+
+/* IP v4 has 2 flag bits that enable fragment processing: DF and MF. DF
+ * requests that the packet not be fragmented. MF indicates that a packet has
+ * been fragmented.
+ */
+#define ICE_FDIR_IPV4_PKT_FLAG_DF              0x20
+#define ICE_FDIR_IPV4_PKT_FLAG_MF              0x40
+
+enum ice_fltr_prgm_desc_dest {
+       ICE_FLTR_PRGM_DESC_DEST_DROP_PKT,
+       ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QINDEX,
+       ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QGROUP,
+       ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_OTHER,
+};
+
+enum ice_fltr_prgm_desc_fd_status {
+       ICE_FLTR_PRGM_DESC_FD_STATUS_NONE,
+       ICE_FLTR_PRGM_DESC_FD_STATUS_FD_ID,
+       ICE_FLTR_PRGM_DESC_FD_STATUS_FD_ID_4FLEX_BYTES,
+       ICE_FLTR_PRGM_DESC_FD_STATUS_8FLEX_BYTES,
+};
+
+#define ICE_FLTR_PRGM_FLEX_WORD_SIZE   sizeof(__be16)
+
+struct ice_rx_flow_userdef {
+       u16 flex_word;
+       u16 flex_offset;
+       u16 flex_fltr;
+};
+
+struct ice_fdir_v4 {
+       __be32 dst_ip;
+       __be32 src_ip;
+       __be16 dst_port;
+       __be16 src_port;
+       __be32 l4_header;
+       __be32 sec_parm_idx;    /* security parameter index */
+       u8 tos;
+       u8 ip_ver;
+       u8 proto;
+};
+
+#define ICE_IPV6_ADDR_LEN_AS_U32               4
+
+struct ice_fdir_v6 {
+       __be32 dst_ip[ICE_IPV6_ADDR_LEN_AS_U32];
+       __be32 src_ip[ICE_IPV6_ADDR_LEN_AS_U32];
+       __be16 dst_port;
+       __be16 src_port;
+       __be32 l4_header; /* next header */
+       __be32 sec_parm_idx; /* security parameter index */
+       u8 tc;
+       u8 proto;
+};
+
+struct ice_fdir_extra {
+       u8 dst_mac[ETH_ALEN];   /* dest MAC address */
+       u32 usr_def[2];         /* user data */
+       __be16 vlan_type;       /* VLAN ethertype */
+       __be16 vlan_tag;        /* VLAN tag info */
+};
+
+struct ice_fdir_fltr {
+       struct LIST_ENTRY_TYPE fltr_node;
+       enum ice_fltr_ptype flow_type;
+
+       union {
+               struct ice_fdir_v4 v4;
+               struct ice_fdir_v6 v6;
+       } ip, mask;
+
+       struct ice_fdir_extra ext_data;
+       struct ice_fdir_extra ext_mask;
+
+       /* flex byte filter data */
+       __be16 flex_word;
+       u16 flex_offset;
+       u16 flex_fltr;
+
+       /* filter control */
+       u16 q_index;
+#ifdef ADQ_SUPPORT
+       u16 orig_q_index;
+#endif /* ADQ_SUPPORT */
+       u16 dest_vsi;
+       u8 dest_ctl;
+       u8 fltr_status;
+       u16 cnt_index;
+       u32 fltr_id;
+};
+
+
+/* Dummy packet filter definition structure. */
+struct ice_fdir_base_pkt {
+       enum ice_fltr_ptype flow;
+       u16 pkt_len;
+       const u8 *pkt;
+};
+
+void
+ice_fdir_get_prgm_desc(struct ice_hw *hw, struct ice_fdir_fltr *input,
+                      struct ice_fltr_desc *fdesc, bool add);
+enum ice_status
+ice_fdir_get_prgm_pkt(struct ice_fdir_fltr *input, u8 *pkt, bool frag);
+enum ice_status
+ice_add_del_fdir(struct ice_hw *hw, struct ice_fdir_fltr *input, bool add);
+int ice_get_fdir_cnt_all(struct ice_hw *hw);
+bool ice_fdir_is_dup_fltr(struct ice_hw *hw, struct ice_fdir_fltr *input);
+enum ice_status
+ice_update_fdir_list_entry(struct ice_hw *hw, struct ice_fdir_fltr *input,
+                          u16 sw_idx);
+bool ice_fdir_has_frag(enum ice_fltr_ptype flow);
+struct ice_fdir_fltr *
+ice_fdir_find_fltr_by_idx(struct ice_hw *hw, u32 fltr_idx);
+void
+ice_fdir_update_cntrs(struct ice_hw *hw, enum ice_fltr_ptype flow, bool add);
+void ice_fdir_list_add_fltr(struct ice_hw *hw, struct ice_fdir_fltr *input);
+#endif /* _ICE_FDIR_H_ */
index 99108d8..37bb4cb 100644 (file)
@@ -1274,6 +1274,25 @@ void ice_free_seg(struct ice_hw *hw)
        hw->seg = NULL;
 }
 
+/**
+ * ice_init_fd_mask_regs - initialize Flow Director mask registers
+ * @hw: pointer to the HW struct
+ *
+ * This function sets up the Flow Director mask registers to allow for complete
+ * masking off of any of the 24 Field Vector words. After this call, mask 0 will
+ * mask off all of FV index 0, mask 1 will mask off all of FV index 1, etc.
+ */
+static void ice_init_fd_mask_regs(struct ice_hw *hw)
+{
+       u16 i;
+
+       for (i = 0; i < hw->blk[ICE_BLK_FD].es.fvw; i++) {
+               wr32(hw, GLQF_FDMASK(i), i);
+               ice_debug(hw, ICE_DBG_INIT, "init fd mask(%d): %x = %x\n", i,
+                         GLQF_FDMASK(i), i);
+       }
+}
+
 /**
  * ice_init_pkg_regs - initialize additional package registers
  * @hw: pointer to the hardware structure
@@ -1287,6 +1306,8 @@ static void ice_init_pkg_regs(struct ice_hw *hw)
        /* setup Switch block input mask, which is 48-bits in two parts */
        wr32(hw, GL_PREEXT_L2_PMASK0(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_L);
        wr32(hw, GL_PREEXT_L2_PMASK1(ICE_SW_BLK_IDX), ICE_SW_BLK_INP_MASK_H);
+       /* setup default flow director masks */
+       ice_init_fd_mask_regs(hw);
 }
 
 /**
@@ -3782,6 +3803,205 @@ error_tmp:
        return status;
 }
 
+/**
+ * ice_update_fd_mask - set Flow Director Field Vector mask for a profile
+ * @hw: pointer to the HW struct
+ * @prof_id: profile ID
+ * @mask_sel: mask select
+ *
+ * This function enable any of the masks selected by the mask select parameter
+ * for the profile specified.
+ */
+static void ice_update_fd_mask(struct ice_hw *hw, u16 prof_id, u32 mask_sel)
+{
+       wr32(hw, GLQF_FDMASK_SEL(prof_id), mask_sel);
+
+       ice_debug(hw, ICE_DBG_INIT, "fd mask(%d): %x = %x\n", prof_id,
+                 GLQF_FDMASK_SEL(prof_id), mask_sel);
+}
+
+#define ICE_SRC_DST_MAX_COUNT  8
+
+struct ice_fd_src_dst_pair {
+       u8 prot_id;
+       u8 count;
+       u16 off;
+};
+
+static const struct ice_fd_src_dst_pair ice_fd_pairs[] = {
+       /* These are defined in pairs */
+       { ICE_PROT_IPV4_OF_OR_S, 2, 12 },
+       { ICE_PROT_IPV4_OF_OR_S, 2, 16 },
+
+       { ICE_PROT_IPV4_IL, 2, 12 },
+       { ICE_PROT_IPV4_IL, 2, 16 },
+
+       { ICE_PROT_IPV6_OF_OR_S, 8, 8 },
+       { ICE_PROT_IPV6_OF_OR_S, 8, 24 },
+
+       { ICE_PROT_IPV6_IL, 8, 8 },
+       { ICE_PROT_IPV6_IL, 8, 24 },
+
+       { ICE_PROT_TCP_IL, 1, 0 },
+       { ICE_PROT_TCP_IL, 1, 2 },
+
+       { ICE_PROT_UDP_OF, 1, 0 },
+       { ICE_PROT_UDP_OF, 1, 2 },
+
+       { ICE_PROT_UDP_IL_OR_S, 1, 0 },
+       { ICE_PROT_UDP_IL_OR_S, 1, 2 },
+
+       { ICE_PROT_SCTP_IL, 1, 0 },
+       { ICE_PROT_SCTP_IL, 1, 2 }
+};
+
+#define ICE_FD_SRC_DST_PAIR_COUNT      ARRAY_SIZE(ice_fd_pairs)
+
+/**
+ * ice_update_fd_swap - set register appropriately for a FD FV extraction
+ * @hw: pointer to the HW struct
+ * @prof_id: profile ID
+ * @es: extraction sequence (length of array is determined by the block)
+ */
+static enum ice_status
+ice_update_fd_swap(struct ice_hw *hw, u16 prof_id, struct ice_fv_word *es)
+{
+       ice_declare_bitmap(pair_list, ICE_FD_SRC_DST_PAIR_COUNT);
+       u8 pair_start[ICE_FD_SRC_DST_PAIR_COUNT] = { 0 };
+#define ICE_FD_FV_NOT_FOUND (-2)
+       s8 first_free = ICE_FD_FV_NOT_FOUND;
+       u8 used[ICE_MAX_FV_WORDS] = { 0 };
+       s8 orig_free, si;
+       u32 mask_sel = 0;
+       u8 i, j, k;
+
+       ice_memset(pair_list, 0, sizeof(pair_list), ICE_NONDMA_MEM);
+
+       ice_init_fd_mask_regs(hw);
+
+       /* This code assumes that the Flow Director field vectors are assigned
+        * from the end of the FV indexes working towards the zero index, that
+        * only complete fields will be included and will be consecutive, and
+        * that there are no gaps between valid indexes.
+        */
+
+       /* Determine swap fields present */
+       for (i = 0; i < hw->blk[ICE_BLK_FD].es.fvw; i++) {
+               /* Find the first free entry, assuming right to left population.
+                * This is where we can start adding additional pairs if needed.
+                */
+               if (first_free == ICE_FD_FV_NOT_FOUND && es[i].prot_id !=
+                   ICE_PROT_INVALID)
+                       first_free = i - 1;
+
+               for (j = 0; j < ICE_FD_SRC_DST_PAIR_COUNT; j++) {
+                       if (es[i].prot_id == ice_fd_pairs[j].prot_id &&
+                           es[i].off == ice_fd_pairs[j].off) {
+                               ice_set_bit(j, pair_list);
+                               pair_start[j] = i;
+                       }
+               }
+       }
+
+       orig_free = first_free;
+
+       /* determine missing swap fields that need to be added */
+       for (i = 0; i < ICE_FD_SRC_DST_PAIR_COUNT; i += 2) {
+               u8 bit1 = ice_is_bit_set(pair_list, i + 1);
+               u8 bit0 = ice_is_bit_set(pair_list, i);
+
+               if (bit0 ^ bit1) {
+                       u8 index;
+
+                       /* add the appropriate 'paired' entry */
+                       if (!bit0)
+                               index = i;
+                       else
+                               index = i + 1;
+
+                       /* check for room */
+                       if (first_free + 1 < ice_fd_pairs[index].count)
+                               return ICE_ERR_MAX_LIMIT;
+
+                       /* place in extraction sequence */
+                       for (k = 0; k < ice_fd_pairs[index].count; k++) {
+                               es[first_free - k].prot_id =
+                                       ice_fd_pairs[index].prot_id;
+                               es[first_free - k].off =
+                                       ice_fd_pairs[index].off + (k * 2);
+
+                               /* keep track of non-relevant fields */
+                               mask_sel |= 1 << (first_free - k);
+                       }
+
+                       pair_start[index] = first_free;
+                       first_free -= ice_fd_pairs[index].count;
+               }
+       }
+
+       /* fill in the swap array */
+       si = hw->blk[ICE_BLK_FD].es.fvw - 1;
+       do {
+               u8 indexes_used = 1;
+
+               /* assume flat at this index */
+#define ICE_SWAP_VALID 0x80
+               used[si] = si | ICE_SWAP_VALID;
+
+               if (orig_free == ICE_FD_FV_NOT_FOUND || si <= orig_free) {
+                       si -= indexes_used;
+                       continue;
+               }
+
+               /* check for a swap location */
+               for (j = 0; j < ICE_FD_SRC_DST_PAIR_COUNT; j++) {
+                       if (es[si].prot_id == ice_fd_pairs[j].prot_id &&
+                           es[si].off == ice_fd_pairs[j].off) {
+                               u8 idx;
+
+                               /* determine the appropriate matching field */
+                               idx = j + ((j % 2) ? -1 : 1);
+
+                               indexes_used = ice_fd_pairs[idx].count;
+                               for (k = 0; k < indexes_used; k++) {
+                                       used[si - k] = (pair_start[idx] - k) |
+                                               ICE_SWAP_VALID;
+                               }
+
+                               break;
+                       }
+               }
+
+               si -= indexes_used;
+       } while (si >= 0);
+
+       /* for each set of 4 swap indexes, write the appropriate register */
+       for (j = 0; j < hw->blk[ICE_BLK_FD].es.fvw / 4; j++) {
+               u32 raw_entry = 0;
+
+               for (k = 0; k < 4; k++) {
+                       u8 idx;
+
+                       idx = (j * 4) + k;
+                       if (used[idx])
+                               raw_entry |= used[idx] << (k * 8);
+               }
+
+               /* write the appropriate register set, based on HW block */
+               wr32(hw, GLQF_FDSWAP(prof_id, j), raw_entry);
+
+               ice_debug(hw, ICE_DBG_INIT, "swap wr(%d, %d): %x = %x\n",
+                         prof_id, j, GLQF_FDSWAP(prof_id, j), raw_entry);
+       }
+
+       /* update the masks for this profile to be sure we ignore fields that
+        * are not relevant to our match criteria
+        */
+       ice_update_fd_mask(hw, prof_id, mask_sel);
+
+       return ICE_SUCCESS;
+}
+
 /**
  * ice_add_prof - add profile
  * @hw: pointer to the HW struct
@@ -3812,6 +4032,18 @@ ice_add_prof(struct ice_hw *hw, enum ice_block blk, u64 id, u8 ptypes[],
                status = ice_alloc_prof_id(hw, blk, &prof_id);
                if (status)
                        goto err_ice_add_prof;
+               if (blk == ICE_BLK_FD) {
+                       /* For Flow Director block, the extraction sequence may
+                        * need to be altered in the case where there are paired
+                        * fields that have no match. This is necessary because
+                        * for Flow Director, src and dest fields need to paired
+                        * for filter programming and these values are swapped
+                        * during Tx.
+                        */
+                       status = ice_update_fd_swap(hw, prof_id, es);
+                       if (status)
+                               goto err_ice_add_prof;
+               }
 
                /* and write new es */
                ice_write_es(hw, blk, prof_id, es);
index 6a08b3d..ef0b5bb 100644 (file)
@@ -164,6 +164,7 @@ enum ice_media_type {
 /* Software VSI types. */
 enum ice_vsi_type {
        ICE_VSI_PF = 0,
+       ICE_VSI_CTRL = 3,       /* equates to ICE_VSI_PF with 1 queue pair */
 #ifdef ADQ_SUPPORT
        ICE_VSI_CHNL = 4,
 #endif /* ADQ_SUPPORT */
@@ -218,6 +219,32 @@ struct ice_phy_info {
 
 #define ICE_MAX_NUM_MIRROR_RULES       64
 
+/* protocol enumeration for filters */
+enum ice_fltr_ptype {
+       /* NONE - used for undef/error */
+       ICE_FLTR_PTYPE_NONF_NONE = 0,
+       ICE_FLTR_PTYPE_NONF_IPV4_UDP,
+       ICE_FLTR_PTYPE_NONF_IPV4_TCP,
+       ICE_FLTR_PTYPE_NONF_IPV4_SCTP,
+       ICE_FLTR_PTYPE_NONF_IPV4_OTHER,
+       ICE_FLTR_PTYPE_FRAG_IPV4,
+       ICE_FLTR_PTYPE_NONF_IPV6_UDP,
+       ICE_FLTR_PTYPE_NONF_IPV6_TCP,
+       ICE_FLTR_PTYPE_NONF_IPV6_SCTP,
+       ICE_FLTR_PTYPE_NONF_IPV6_OTHER,
+       ICE_FLTR_PTYPE_MAX,
+};
+
+/* 6 VSI = 1 ICE_VSI_PF + 1 ICE_VSI_CTRL + 4 ICE_VSI_CHNL */
+#define ICE_MAX_FDIR_VSI_PER_FILTER    6
+
+struct ice_fd_hw_prof {
+       struct ice_flow_seg_info *fdir_seg;
+       int cnt;
+       u64 entry_h[ICE_MAX_FDIR_VSI_PER_FILTER];
+       u16 vsi_h[ICE_MAX_FDIR_VSI_PER_FILTER];
+};
+
 /* Common HW capabilities for SW use */
 struct ice_hw_common_caps {
        /* Write CSR protection */
@@ -297,12 +324,15 @@ struct ice_hw_common_caps {
 struct ice_hw_func_caps {
        struct ice_hw_common_caps common_cap;
        u32 guar_num_vsi;
+       u32 fd_fltr_guar;               /* Number of filters guaranteed */
+       u32 fd_fltr_best_effort;        /* Number of best effort filters */
 };
 
 /* Device wide capabilities */
 struct ice_hw_dev_caps {
        struct ice_hw_common_caps common_cap;
        u32 num_vsi_allocd_to_host;     /* Excluding EMP VSI */
+       u32 num_flow_director_fltr;     /* Number of FD filters available */
 };
 
 
@@ -651,6 +681,7 @@ struct ice_hw {
        u64 debug_mask;         /* BITMAP for debug mask */
        enum ice_mac_type mac_type;
 
+       u16 fd_ctr_base;        /* FD counter base index */
        /* pci info */
        u16 device_id;
        u16 vendor_id;
@@ -748,6 +779,19 @@ struct ice_hw {
        struct ice_blk_info blk[ICE_BLK_COUNT];
        struct ice_lock fl_profs_locks[ICE_BLK_COUNT];  /* lock fltr profiles */
        struct LIST_HEAD_TYPE fl_profs[ICE_BLK_COUNT];
+       /* Flow Director filter info */
+       int fdir_active_fltr;
+
+       struct ice_lock fdir_fltr_lock; /* protect Flow Director */
+       struct LIST_HEAD_TYPE fdir_list_head;
+
+       /* Book-keeping of side-band filter count per flow-type.
+        * This is used to detect and handle input set changes for
+        * respective flow-type.
+        */
+       u16 fdir_fltr_cnt[ICE_FLTR_PTYPE_MAX];
+
+       struct ice_fd_hw_prof **fdir_prof;
 };
 
 /* Statistics collected by each port, VSI, VEB, and S-channel */
@@ -792,6 +836,11 @@ struct ice_hw_port_stats {
        u64 link_xoff_rx;               /* lxoffrxc */
        u64 link_xon_tx;                /* lxontxc */
        u64 link_xoff_tx;               /* lxofftxc */
+       u64 priority_xon_rx[8];         /* pxonrxc[8] */
+       u64 priority_xoff_rx[8];        /* pxoffrxc[8] */
+       u64 priority_xon_tx[8];         /* pxontxc[8] */
+       u64 priority_xoff_tx[8];        /* pxofftxc[8] */
+       u64 priority_xon_2_xoff[8];     /* pxon2offc[8] */
        u64 rx_size_64;                 /* prc64 */
        u64 rx_size_127;                /* prc127 */
        u64 rx_size_255;                /* prc255 */
@@ -811,6 +860,12 @@ struct ice_hw_port_stats {
        u64 tx_size_1522;               /* ptc1522 */
        u64 tx_size_big;                /* ptc9522 */
        u64 mac_short_pkt_dropped;      /* mspdc */
+       /* flow director stats */
+       u32 fd_sb_status;
+       u64 fd_sb_match;
+#ifdef ADQ_SUPPORT
+       u64 ch_atr_match;
+#endif /* ADQ_SUPPORT */
 };
 
 enum ice_sw_fwd_act_type {
index 755d249..6242025 100644 (file)
@@ -10,6 +10,7 @@ sources = [
        'ice_flex_pipe.c',
        'ice_flow.c',
        'ice_dcb.c',
+       'ice_fdir.c',
 ]
 
 error_cflags = ['-Wno-unused-value',