Support to add large action to set 32 bits markid via switch filter. Signed-off-by: Zhirun Yan <zhirun....@intel.com> --- drivers/net/ice/base/ice_switch.c | 216 +++++++++++++++++++++++++++++- drivers/net/ice/base/ice_switch.h | 44 ++++++ drivers/net/ice/base/ice_type.h | 1 + 3 files changed, 258 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ice/base/ice_switch.c b/drivers/net/ice/base/ice_switch.c index a2581f404d..e4eed66406 100644 --- a/drivers/net/ice/base/ice_switch.c +++ b/drivers/net/ice/base/ice_switch.c @@ -2501,6 +2501,42 @@ enum ice_status ice_alloc_rss_global_lut(struct ice_hw *hw, bool shared_res, u16 return status; } +/** + * ice_free_sw_marker_lg - free a switch marker large action + * @hw: pointer to the HW struct + * @marker_lg_id: ID of the marker large action to free + * @sw_marker: sw marker to tag the Rx descriptor with + */ +static enum ice_status +ice_free_sw_marker_lg(struct ice_hw *hw, u16 marker_lg_id, u32 sw_marker) +{ + struct ice_aqc_alloc_free_res_elem *sw_buf; + u16 buf_len, num_elems = 1; + enum ice_status status; + + buf_len = ice_struct_size(sw_buf, elem, num_elems); + sw_buf = (struct ice_aqc_alloc_free_res_elem *)ice_malloc(hw, buf_len); + if (!sw_buf) + return ICE_ERR_NO_MEMORY; + + sw_buf->num_elems = CPU_TO_LE16(num_elems); + if (sw_marker == (sw_marker & 0xFFFF)) + sw_buf->res_type = CPU_TO_LE16(ICE_AQC_RES_TYPE_WIDE_TABLE_1); + else + sw_buf->res_type = CPU_TO_LE16(ICE_AQC_RES_TYPE_WIDE_TABLE_2); + + sw_buf->elem[0].e.sw_resp = CPU_TO_LE16(marker_lg_id); + + status = ice_aq_alloc_free_res(hw, num_elems, sw_buf, buf_len, + ice_aqc_opc_free_res, NULL); + if (status) + ice_debug(hw, ICE_DBG_RES, "Failed to free sw marker lg %d, status %d\n", + marker_lg_id, status); + + ice_free(hw, sw_buf); + return status; +} + /** * ice_free_rss_global_lut - free a RSS global LUT * @hw: pointer to the HW struct @@ -8807,6 +8843,139 @@ ice_adv_add_update_vsi_list(struct ice_hw *hw, return status; } +/** + * ice_set_lg_action_entry + * @act_type: large action type is defined in struct ice_sw_rule_lg_act + * @lg_act_entry: large action entry content + * + * Helper function to set large action entry. Each entry represents a single + * action and up to 4 actions can be chained. + */ +static u32 +ice_set_lg_action_entry(u8 act_type, union lg_act_entry *lg_entry) +{ + u32 act = act_type; + + switch (act_type) { + case ICE_LG_ACT_VSI_FORWARDING: + act |= ICE_LG_ACT_VALID_BIT; + act |= (lg_entry->vsi_fwd.vsi_list << + ICE_LG_ACT_VSI_LIST_ID_S) & + ICE_LG_ACT_VSI_LIST_ID_M; + break; + case ICE_LG_ACT_TO_Q: + act |= ICE_LG_ACT_Q_PRIORITY_SET; + act |= (lg_entry->to_q.q_idx << ICE_LG_ACT_Q_INDEX_S) & + ICE_LG_ACT_Q_INDEX_M; + act |= (lg_entry->to_q.q_region_sz << ICE_LG_ACT_Q_REGION_S) & + ICE_LG_ACT_Q_REGION_M; + act |= (lg_entry->to_q.q_pri << ICE_LG_ACT_Q_REGION_S) & + ICE_LG_ACT_Q_REGION_M; + break; + case ICE_LG_ACT_PRUNE: + act |= (lg_entry->prune.vsi_list << ICE_LG_ACT_VSI_LIST_ID_S) & + ICE_LG_ACT_VSI_LIST_ID_M; + + if (lg_entry->prune.egr) + act |= ICE_LG_ACT_EGRESS; + if (lg_entry->prune.ing) + act |= ICE_LG_ACT_INGRESS; + if (lg_entry->prune.prune_t) + act |= ICE_LG_ACT_PRUNET; + break; + case ICE_LG_OTHER_ACT_MIRROR: + act |= (lg_entry->mirror.mirror_vsi << + ICE_LG_ACT_MIRROR_VSI_ID_S) & + ICE_LG_ACT_MIRROR_VSI_ID_M; + break; + case ICE_LG_ACT_GENERIC: + act |= (lg_entry->generic_act.generic_value << + ICE_LG_ACT_GENERIC_VALUE_S) & + ICE_LG_ACT_GENERIC_VALUE_M; + act |= (lg_entry->generic_act.offset << + ICE_LG_ACT_GENERIC_OFFSET_S) & + ICE_LG_ACT_GENERIC_OFFSET_M; + act |= (lg_entry->generic_act.priority << + ICE_LG_ACT_GENERIC_PRIORITY_S) & + ICE_LG_ACT_GENERIC_PRIORITY_M; + break; + case ICE_LG_ACT_STAT_COUNT: + act |= (lg_entry->statistics.counter_idx << + ICE_LG_ACT_STAT_COUNT_S) & + ICE_LG_ACT_STAT_COUNT_M; + break; + } + + return act; +} + +/** + * ice_fill_sw_marker_lg_act + * @hw: pointer to the hardware structure + * @sw_marker: sw marker to tag the Rx descriptor with + * @l_id: large action resource ID + * @lkup_rule_sz: lookup rule size + * @lg_act_size: large action rule size + * @num_lg_acts: number of actions to hold with a large action entry + * @s_rule: switch lookup rule structure + * + * Fill a large action to hold software marker and link the lookup rule + * with an action pointing to this larger action + */ +static struct ice_aqc_sw_rules_elem * +ice_fill_sw_marker_lg_act(struct ice_hw *hw, u32 sw_marker, u16 l_id, + u16 lkup_rule_sz, u16 lg_act_size, u16 num_lg_acts, + struct ice_aqc_sw_rules_elem *s_rule) +{ + struct ice_aqc_sw_rules_elem *rx_tx, *lg_act; + const u16 offset_generic_md_word_0 = 0; + const u16 offset_generic_md_word_1 = 1; + enum ice_status status = ICE_SUCCESS; + union lg_act_entry lg_e_lo; + union lg_act_entry lg_e_hi; + const u8 priority = 0x3; + u16 rules_size; + u32 act; + + /* For software marker we need 2 large actions for 32 bit mark id */ + rules_size = lg_act_size + lkup_rule_sz; + lg_act = (struct ice_aqc_sw_rules_elem *)ice_malloc(hw, rules_size); + if (!lg_act) + return NULL; + + rx_tx = (struct ice_aqc_sw_rules_elem *)((u8 *)lg_act + lg_act_size); + + ice_memcpy(rx_tx, s_rule, lkup_rule_sz, ICE_NONDMA_TO_NONDMA); + ice_free(hw, s_rule); + s_rule = NULL; + + lg_act->type = CPU_TO_LE16(ICE_AQC_SW_RULES_T_LG_ACT); + lg_act->pdata.lg_act.index = CPU_TO_LE16(l_id); + lg_act->pdata.lg_act.size = CPU_TO_LE16(num_lg_acts); + + /* GENERIC VALUE action to hold the software marker ID low 16 bits */ + /* and set in meta data index 4 by default. */ + lg_e_lo.generic_act.generic_value = (u16)(sw_marker & 0xFFFF); + lg_e_lo.generic_act.offset = offset_generic_md_word_0; + lg_e_lo.generic_act.priority = priority; + act = ice_set_lg_action_entry(ICE_LG_ACT_GENERIC, &lg_e_lo); + lg_act->pdata.lg_act.act[0] = CPU_TO_LE32(act); + + if (num_lg_acts == 1) + return lg_act; + + /* This is a 32 bits marker id, chain a new entry to set higher 16 bits + * and set in meta data index 5 by default. + */ + lg_e_hi.generic_act.generic_value = (u16)((sw_marker >> 16) & 0xFFFF); + lg_e_hi.generic_act.offset = offset_generic_md_word_1; + lg_e_hi.generic_act.priority = priority; + act = ice_set_lg_action_entry(ICE_LG_ACT_GENERIC, &lg_e_hi); + lg_act->pdata.lg_act.act[1] = CPU_TO_LE32(act); + + return lg_act; +} + /** * ice_add_adv_rule - helper function to create an advanced switch rule * @hw: pointer to the hardware structure @@ -8831,13 +9000,17 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, struct ice_rule_query_data *added_entry) { struct ice_adv_fltr_mgmt_list_entry *m_entry, *adv_fltr = NULL; + u16 lg_act_size, lg_act_id = ICE_INVAL_LG_ACT_INDEX; u16 rid = 0, i, pkt_len, rule_buf_sz, vsi_handle; const struct ice_dummy_pkt_offsets *pkt_offsets; struct ice_aqc_sw_rules_elem *s_rule = NULL; + struct ice_aqc_sw_rules_elem *rx_tx; struct LIST_HEAD_TYPE *rule_head; struct ice_switch_info *sw; + u16 nb_lg_acts_mark = 1; enum ice_status status; const u8 *pkt = NULL; + u16 num_rules = 1; bool prof_rule; u16 word_cnt; u32 act = 0; @@ -8883,6 +9056,7 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, if (!(rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI || rinfo->sw_act.fltr_act == ICE_FWD_TO_Q || rinfo->sw_act.fltr_act == ICE_FWD_TO_QGRP || + rinfo->sw_act.fltr_act == ICE_SET_MARK || rinfo->sw_act.fltr_act == ICE_DROP_PACKET)) return ICE_ERR_CFG; @@ -8949,6 +9123,19 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, act |= (q_rgn << ICE_SINGLE_ACT_Q_REGION_S) & ICE_SINGLE_ACT_Q_REGION_M; break; + case ICE_SET_MARK: + if (rinfo->sw_act.markid != (rinfo->sw_act.markid & 0xFFFF)) + nb_lg_acts_mark += 1; + /* Allocate a hardware table entry to hold large act. */ + status = ice_alloc_res_lg_act(hw, &lg_act_id, nb_lg_acts_mark); + if (status || lg_act_id == ICE_INVAL_LG_ACT_INDEX) + return ICE_ERR_NO_MEMORY; + + act = ICE_SINGLE_ACT_PTR; + act |= (lg_act_id << ICE_SINGLE_ACT_PTR_VAL_S) & + ICE_SINGLE_ACT_PTR_VAL_M; + act |= ICE_SINGLE_ACT_PTR_BIT; + break; case ICE_DROP_PACKET: act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP | ICE_SINGLE_ACT_VALID_BIT; @@ -8991,9 +9178,25 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, goto err_ice_add_adv_rule; } + rx_tx = s_rule; + if (rinfo->sw_act.fltr_act == ICE_SET_MARK) { + lg_act_size = (u16)ICE_SW_RULE_LG_ACT_SIZE(nb_lg_acts_mark); + s_rule = ice_fill_sw_marker_lg_act(hw, rinfo->sw_act.markid, + lg_act_id, rule_buf_sz, + lg_act_size, nb_lg_acts_mark, + s_rule); + if (!s_rule) + goto err_ice_add_adv_rule; + + rule_buf_sz += lg_act_size; + num_rules += 1; + rx_tx = (struct ice_aqc_sw_rules_elem *) + ((u8 *)s_rule + lg_act_size); + } + status = ice_aq_sw_rules(hw, (struct ice_aqc_sw_rules *)s_rule, - rule_buf_sz, 1, ice_aqc_opc_add_sw_rules, - NULL); + rule_buf_sz, num_rules, + ice_aqc_opc_add_sw_rules, NULL); if (status) goto err_ice_add_adv_rule; adv_fltr = (struct ice_adv_fltr_mgmt_list_entry *) @@ -9018,7 +9221,8 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, adv_fltr->lkups_cnt = lkups_cnt; adv_fltr->rule_info = *rinfo; adv_fltr->rule_info.fltr_rule_id = - LE16_TO_CPU(s_rule->pdata.lkup_tx_rx.index); + LE16_TO_CPU(rx_tx->pdata.lkup_tx_rx.index); + adv_fltr->rule_info.lg_id = LE16_TO_CPU(lg_act_id); sw = hw->switch_info; sw->recp_list[rid].adv_rule = true; rule_head = &sw->recp_list[rid].filt_rules; @@ -9034,6 +9238,9 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, added_entry->vsi_handle = rinfo->sw_act.vsi_handle; } err_ice_add_adv_rule: + if (status && rinfo->sw_act.fltr_act == ICE_SET_MARK) + ice_free_sw_marker_lg(hw, lg_act_id, rinfo->sw_act.markid); + if (status && adv_fltr) { ice_free(hw, adv_fltr->lkups); ice_free(hw, adv_fltr); @@ -9212,6 +9419,9 @@ ice_rem_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups, struct ice_aqc_sw_rules_elem *s_rule; u16 rule_buf_sz; + if (rinfo->sw_act.fltr_act == ICE_SET_MARK) + ice_free_sw_marker_lg(hw, list_elem->rule_info.lg_id, + rinfo->sw_act.markid); rule_buf_sz = ICE_SW_RULE_RX_TX_NO_HDR_SIZE; s_rule = (struct ice_aqc_sw_rules_elem *) ice_malloc(hw, rule_buf_sz); diff --git a/drivers/net/ice/base/ice_switch.h b/drivers/net/ice/base/ice_switch.h index 01b49595d2..949c94c0c3 100644 --- a/drivers/net/ice/base/ice_switch.h +++ b/drivers/net/ice/base/ice_switch.h @@ -219,6 +219,48 @@ struct ice_adv_lkup_elem { union ice_prot_hdr m_u; /* Mask of header values to match */ }; +struct lg_entry_vsi_fwd { + u16 vsi_list; + u8 list; + u8 valid; +}; + +struct lg_entry_to_q { + u16 q_idx; + u8 q_region_sz; + u8 q_pri; +}; + +struct lg_entry_prune { + u16 vsi_list; + u8 list; + u8 egr; + u8 ing; + u8 prune_t; +}; + +struct lg_entry_mirror { + u16 mirror_vsi; +}; + +struct lg_entry_generic_act { + u16 generic_value; + u8 offset; + u8 priority; +}; + +struct lg_entry_statistics { + u8 counter_idx; +}; + +union lg_act_entry { + struct lg_entry_vsi_fwd vsi_fwd; + struct lg_entry_to_q to_q; + struct lg_entry_prune prune; + struct lg_entry_mirror mirror; + struct lg_entry_generic_act generic_act; + struct lg_entry_statistics statistics; +}; struct ice_prof_type_entry { u16 prof_id; enum ice_sw_tunnel_type type; @@ -242,6 +284,7 @@ struct ice_sw_act_ctrl { /* software VSI handle */ u16 vsi_handle; u8 qgrp_size; + u32 markid; }; struct ice_rule_query_data { @@ -269,6 +312,7 @@ struct ice_adv_rule_info { u32 priority; u8 rx; /* true means LOOKUP_RX otherwise LOOKUP_TX */ u16 fltr_rule_id; + u16 lg_id; struct ice_adv_rule_flags_info flags_info; }; diff --git a/drivers/net/ice/base/ice_type.h b/drivers/net/ice/base/ice_type.h index 54a753545e..bfec317b57 100644 --- a/drivers/net/ice/base/ice_type.h +++ b/drivers/net/ice/base/ice_type.h @@ -1364,6 +1364,7 @@ enum ice_sw_fwd_act_type { ICE_FWD_TO_VSI_LIST, /* Do not use this when adding filter */ ICE_FWD_TO_Q, ICE_FWD_TO_QGRP, + ICE_SET_MARK, ICE_DROP_PACKET, ICE_INVAL_ACT }; -- 2.25.1