X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fice%2Fbase%2Fice_vlan_mode.c;h=ce150009c2323eb18753657002bd010ffd0b798b;hb=937fa68010317dde8bc2f63117e82315c2176b5c;hp=503c6c1b2833d9a58f9287400db827796f8130b5;hpb=d84e220a8d17149a030cacc5f54599379a64ad5a;p=dpdk.git diff --git a/drivers/net/ice/base/ice_vlan_mode.c b/drivers/net/ice/base/ice_vlan_mode.c index 503c6c1b28..ce150009c2 100644 --- a/drivers/net/ice/base/ice_vlan_mode.c +++ b/drivers/net/ice/base/ice_vlan_mode.c @@ -2,11 +2,10 @@ * Copyright(c) 2001-2021 Intel Corporation */ -#include "ice_vlan_mode.h" #include "ice_common.h" /** - * ice_pkg_supports_dvm - determine if DDP supports Double VLAN mode (DVM) + * ice_pkg_get_supported_vlan_mode - chk if DDP supports Double VLAN mode (DVM) * @hw: pointer to the HW struct * @dvm: output variable to determine if DDP supports DVM(true) or SVM(false) */ @@ -55,21 +54,100 @@ ice_pkg_get_supported_vlan_mode(struct ice_hw *hw, bool *dvm) } /** - * ice_is_dvm_supported - check if double VLAN mode is supported based on DDP + * ice_aq_get_vlan_mode - get the VLAN mode of the device + * @hw: pointer to the HW structure + * @get_params: structure FW fills in based on the current VLAN mode config + * + * Get VLAN Mode Parameters (0x020D) + */ +static enum ice_status +ice_aq_get_vlan_mode(struct ice_hw *hw, + struct ice_aqc_get_vlan_mode *get_params) +{ + struct ice_aq_desc desc; + + if (!get_params) + return ICE_ERR_PARAM; + + ice_fill_dflt_direct_cmd_desc(&desc, + ice_aqc_opc_get_vlan_mode_parameters); + + return ice_aq_send_cmd(hw, &desc, get_params, sizeof(*get_params), + NULL); +} + +/** + * ice_aq_is_dvm_ena - query FW to check if double VLAN mode is enabled + * @hw: pointer to the HW structure + * + * Returns true if the hardware/firmware is configured in double VLAN mode, + * else return false signaling that the hardware/firmware is configured in + * single VLAN mode. + * + * Also, return false if this call fails for any reason (i.e. firmware doesn't + * support this AQ call). + */ +static bool ice_aq_is_dvm_ena(struct ice_hw *hw) +{ + struct ice_aqc_get_vlan_mode get_params = { 0 }; + enum ice_status status; + + status = ice_aq_get_vlan_mode(hw, &get_params); + if (status) { + ice_debug(hw, ICE_DBG_AQ, "Failed to get VLAN mode, status %d\n", + status); + return false; + } + + return (get_params.vlan_mode & ICE_AQ_VLAN_MODE_DVM_ENA); +} + +/** + * ice_is_dvm_ena - check if double VLAN mode is enabled + * @hw: pointer to the HW structure + * + * The device is configured in single or double VLAN mode on initialization and + * this cannot be dynamically changed during runtime. Based on this there is no + * need to make an AQ call every time the driver needs to know the VLAN mode. + * Instead, use the cached VLAN mode. + */ +bool ice_is_dvm_ena(struct ice_hw *hw) +{ + return hw->dvm_ena; +} + +/** + * ice_cache_vlan_mode - cache VLAN mode after DDP is downloaded + * @hw: pointer to the HW structure + * + * This is only called after downloading the DDP and after the global + * configuration lock has been released because all ports on a device need to + * cache the VLAN mode. + */ +void ice_cache_vlan_mode(struct ice_hw *hw) +{ + hw->dvm_ena = ice_aq_is_dvm_ena(hw) ? true : false; +} + +/** + * ice_is_dvm_supported - check if Double VLAN Mode is supported * @hw: pointer to the hardware structure * - * Returns true if DVM is supported and false if only SVM is supported. This - * function should only be called while the global config lock is held and after - * the package has been successfully downloaded. + * Returns true if Double VLAN Mode (DVM) is supported and false if only Single + * VLAN Mode (SVM) is supported. In order for DVM to be supported the DDP and + * firmware must support it, otherwise only SVM is supported. This function + * should only be called while the global config lock is held and after the + * package has been successfully downloaded. */ static bool ice_is_dvm_supported(struct ice_hw *hw) { + struct ice_aqc_get_vlan_mode get_vlan_mode = { 0 }; enum ice_status status; bool pkg_supports_dvm; status = ice_pkg_get_supported_vlan_mode(hw, &pkg_supports_dvm); if (status) { - ice_debug(hw, ICE_DBG_PKG, "Failed to get supported VLAN mode, err %d\n", + ice_debug(hw, ICE_DBG_PKG, "Failed to get supported VLAN mode, status %d\n", status); return false; } @@ -77,28 +155,203 @@ static bool ice_is_dvm_supported(struct ice_hw *hw) if (!pkg_supports_dvm) return false; + /* If firmware returns success, then it supports DVM, else it only + * supports SVM + */ + status = ice_aq_get_vlan_mode(hw, &get_vlan_mode); + if (status) { + ice_debug(hw, ICE_DBG_NVM, "Failed to get VLAN mode, status %d\n", + status); + return false; + } + return true; } +#define ICE_EXTERNAL_VLAN_ID_FV_IDX 11 +#define ICE_SW_LKUP_VLAN_LOC_LKUP_IDX 1 +#define ICE_SW_LKUP_VLAN_PKT_FLAGS_LKUP_IDX 2 +#define ICE_SW_LKUP_PROMISC_VLAN_LOC_LKUP_IDX 2 +#define ICE_PKT_FLAGS_0_TO_15_FV_IDX 1 +#define ICE_PKT_FLAGS_0_TO_15_VLAN_FLAGS_MASK 0xD000 +static struct ice_update_recipe_lkup_idx_params ice_dvm_dflt_recipes[] = { + { + /* Update recipe ICE_SW_LKUP_VLAN to filter based on the + * outer/single VLAN in DVM + */ + .rid = ICE_SW_LKUP_VLAN, + .fv_idx = ICE_EXTERNAL_VLAN_ID_FV_IDX, + .ignore_valid = true, + .mask = 0, + .mask_valid = false, /* use pre-existing mask */ + .lkup_idx = ICE_SW_LKUP_VLAN_LOC_LKUP_IDX, + }, + { + /* Update recipe ICE_SW_LKUP_VLAN to filter based on the VLAN + * packet flags to support VLAN filtering on multiple VLAN + * ethertypes (i.e. 0x8100 and 0x88a8) in DVM + */ + .rid = ICE_SW_LKUP_VLAN, + .fv_idx = ICE_PKT_FLAGS_0_TO_15_FV_IDX, + .ignore_valid = false, + .mask = ICE_PKT_FLAGS_0_TO_15_VLAN_FLAGS_MASK, + .mask_valid = true, + .lkup_idx = ICE_SW_LKUP_VLAN_PKT_FLAGS_LKUP_IDX, + }, + { + /* Update recipe ICE_SW_LKUP_PROMISC_VLAN to filter based on the + * outer/single VLAN in DVM + */ + .rid = ICE_SW_LKUP_PROMISC_VLAN, + .fv_idx = ICE_EXTERNAL_VLAN_ID_FV_IDX, + .ignore_valid = true, + .mask = 0, + .mask_valid = false, /* use pre-existing mask */ + .lkup_idx = ICE_SW_LKUP_PROMISC_VLAN_LOC_LKUP_IDX, + }, +}; + /** - * ice_set_svm - set single VLAN mode + * ice_dvm_update_dflt_recipes - update default switch recipes in DVM + * @hw: hardware structure used to update the recipes + */ +static enum ice_status ice_dvm_update_dflt_recipes(struct ice_hw *hw) +{ + unsigned long i; + + for (i = 0; i < ARRAY_SIZE(ice_dvm_dflt_recipes); i++) { + struct ice_update_recipe_lkup_idx_params *params; + enum ice_status status; + + params = &ice_dvm_dflt_recipes[i]; + + status = ice_update_recipe_lkup_idx(hw, params); + if (status) { + ice_debug(hw, ICE_DBG_INIT, "Failed to update RID %d lkup_idx %d fv_idx %d mask_valid %s mask 0x%04x\n", + params->rid, params->lkup_idx, params->fv_idx, + params->mask_valid ? "true" : "false", + params->mask); + return status; + } + } + + return ICE_SUCCESS; +} + +/** + * ice_aq_set_vlan_mode - set the VLAN mode of the device * @hw: pointer to the HW structure + * @set_params: requested VLAN mode configuration + * + * Set VLAN Mode Parameters (0x020C) */ -static enum ice_status ice_set_svm_dflt(struct ice_hw *hw) +static enum ice_status +ice_aq_set_vlan_mode(struct ice_hw *hw, + struct ice_aqc_set_vlan_mode *set_params) { - ice_debug(hw, ICE_DBG_TRACE, "%s\n", __func__); + u8 rdma_packet, mng_vlan_prot_id; + struct ice_aq_desc desc; + + if (!set_params) + return ICE_ERR_PARAM; + + if (set_params->l2tag_prio_tagging > ICE_AQ_VLAN_PRIO_TAG_MAX) + return ICE_ERR_PARAM; + + rdma_packet = set_params->rdma_packet; + if (rdma_packet != ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING && + rdma_packet != ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING) + return ICE_ERR_PARAM; + + mng_vlan_prot_id = set_params->mng_vlan_prot_id; + if (mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER && + mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER) + return ICE_ERR_PARAM; + + ice_fill_dflt_direct_cmd_desc(&desc, + ice_aqc_opc_set_vlan_mode_parameters); + desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD); + + return ice_aq_send_cmd(hw, &desc, set_params, sizeof(*set_params), + NULL); +} + +/** + * ice_set_dvm - sets up software and hardware for double VLAN mode + * @hw: pointer to the hardware structure + */ +static enum ice_status ice_set_dvm(struct ice_hw *hw) +{ + struct ice_aqc_set_vlan_mode params = { 0 }; + enum ice_status status; + + params.l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_OUTER_CTAG; + params.rdma_packet = ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING; + params.mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER; + + status = ice_aq_set_vlan_mode(hw, ¶ms); + if (status) { + ice_debug(hw, ICE_DBG_INIT, "Failed to set double VLAN mode parameters, status %d\n", + status); + return status; + } + + status = ice_dvm_update_dflt_recipes(hw); + if (status) { + ice_debug(hw, ICE_DBG_INIT, "Failed to update default recipes for double VLAN mode, status %d\n", + status); + return status; + } + + status = ice_aq_set_port_params(hw->port_info, 0, false, false, true, + NULL); + if (status) { + ice_debug(hw, ICE_DBG_INIT, "Failed to set port in double VLAN mode, status %d\n", + status); + return status; + } + + status = ice_set_dvm_boost_entries(hw); + if (status) { + ice_debug(hw, ICE_DBG_INIT, "Failed to set boost TCAM entries for double VLAN mode, status %d\n", + status); + return status; + } - return ice_aq_set_port_params(hw->port_info, 0, false, false, false, NULL); + return ICE_SUCCESS; } /** - * ice_init_vlan_mode_ops - initialize VLAN mode configuration ops + * ice_set_svm - set single VLAN mode * @hw: pointer to the HW structure */ -void ice_init_vlan_mode_ops(struct ice_hw *hw) +static enum ice_status ice_set_svm(struct ice_hw *hw) { - hw->vlan_mode_ops.set_dvm = NULL; - hw->vlan_mode_ops.set_svm = ice_set_svm_dflt; + struct ice_aqc_set_vlan_mode *set_params; + enum ice_status status; + + status = ice_aq_set_port_params(hw->port_info, 0, false, false, false, NULL); + if (status) { + ice_debug(hw, ICE_DBG_INIT, "Failed to set port parameters for single VLAN mode\n"); + return status; + } + + set_params = (struct ice_aqc_set_vlan_mode *) + ice_malloc(hw, sizeof(*set_params)); + if (!set_params) + return ICE_ERR_NO_MEMORY; + + /* default configuration for SVM configurations */ + set_params->l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_INNER_CTAG; + set_params->rdma_packet = ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING; + set_params->mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER; + + status = ice_aq_set_vlan_mode(hw, set_params); + if (status) + ice_debug(hw, ICE_DBG_INIT, "Failed to configure port in single VLAN mode\n"); + + ice_free(hw, set_params); + return status; } /** @@ -107,16 +360,17 @@ void ice_init_vlan_mode_ops(struct ice_hw *hw) */ enum ice_status ice_set_vlan_mode(struct ice_hw *hw) { - enum ice_status status = ICE_ERR_NOT_IMPL; + /* DCF only has the ability to query the VLAN mode. Setting the VLAN + * mode is done by the PF. + */ + if (hw->dcf_enabled) + return ICE_SUCCESS; if (!ice_is_dvm_supported(hw)) return ICE_SUCCESS; - if (hw->vlan_mode_ops.set_dvm) - status = hw->vlan_mode_ops.set_dvm(hw); - - if (status) - return hw->vlan_mode_ops.set_svm(hw); + if (!ice_set_dvm(hw)) + return ICE_SUCCESS; - return ICE_SUCCESS; + return ice_set_svm(hw); }