From: Qi Zhang Date: Mon, 25 Mar 2019 05:44:46 +0000 (+0800) Subject: net/ice/base: support FDIR X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=bd984f155f49;p=dpdk.git net/ice/base: support FDIR Add flow director related support base code. Signed-off-by: Paul M Stillwell Jr Signed-off-by: Qi Zhang Reviewed-by: Qiming Yang Reviewed-by: Wenzhuo Lu --- diff --git a/drivers/net/ice/Makefile b/drivers/net/ice/Makefile index 854e40e79b..0e5c55ef87 100644 --- a/drivers/net/ice/Makefile +++ b/drivers/net/ice/Makefile @@ -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 diff --git a/drivers/net/ice/base/ice_adminq_cmd.h b/drivers/net/ice/base/ice_adminq_cmd.h index 4c5cf54196..d2ab9eeff5 100644 --- a/drivers/net/ice/base/ice_adminq_cmd.h +++ b/drivers/net/ice/base/ice_adminq_cmd.h @@ -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, diff --git a/drivers/net/ice/base/ice_common.c b/drivers/net/ice/base/ice_common.c index 2025927106..425f76e8da 100644 --- a/drivers/net/ice/base/ice_common.c +++ b/drivers/net/ice/base/ice_common.c @@ -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) diff --git a/drivers/net/ice/base/ice_common.h b/drivers/net/ice/base/ice_common.h index 9665f3204c..4dc43dcfe2 100644 --- a/drivers/net/ice/base/ice_common.h +++ b/drivers/net/ice/base/ice_common.h @@ -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 index 0000000000..4bc8e6dcb2 --- /dev/null +++ b/drivers/net/ice/base/ice_fdir.c @@ -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 index 0000000000..2ecb147f12 --- /dev/null +++ b/drivers/net/ice/base/ice_fdir.h @@ -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_ */ diff --git a/drivers/net/ice/base/ice_flex_pipe.c b/drivers/net/ice/base/ice_flex_pipe.c index 99108d81c6..37bb4cbb56 100644 --- a/drivers/net/ice/base/ice_flex_pipe.c +++ b/drivers/net/ice/base/ice_flex_pipe.c @@ -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); diff --git a/drivers/net/ice/base/ice_type.h b/drivers/net/ice/base/ice_type.h index 6a08b3d288..ef0b5bb52a 100644 --- a/drivers/net/ice/base/ice_type.h +++ b/drivers/net/ice/base/ice_type.h @@ -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 { diff --git a/drivers/net/ice/base/meson.build b/drivers/net/ice/base/meson.build index 755d2497b0..624202567c 100644 --- a/drivers/net/ice/base/meson.build +++ b/drivers/net/ice/base/meson.build @@ -10,6 +10,7 @@ sources = [ 'ice_flex_pipe.c', 'ice_flow.c', 'ice_dcb.c', + 'ice_fdir.c', ] error_cflags = ['-Wno-unused-value',