brintos

brintos / linux-shallow public Read only

0
0
Text · 12.2 KiB · 1279c1f Raw
439 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (C) 2019-2021, Intel Corporation. */3 4#include "ice_common.h"5 6/**7 * ice_pkg_get_supported_vlan_mode - determine if DDP supports Double VLAN mode8 * @hw: pointer to the HW struct9 * @dvm: output variable to determine if DDP supports DVM(true) or SVM(false)10 */11static int12ice_pkg_get_supported_vlan_mode(struct ice_hw *hw, bool *dvm)13{14	u16 meta_init_size = sizeof(struct ice_meta_init_section);15	struct ice_meta_init_section *sect;16	struct ice_buf_build *bld;17	int status;18 19	/* if anything fails, we assume there is no DVM support */20	*dvm = false;21 22	bld = ice_pkg_buf_alloc_single_section(hw,23					       ICE_SID_RXPARSER_METADATA_INIT,24					       meta_init_size, (void **)&sect);25	if (!bld)26		return -ENOMEM;27 28	/* only need to read a single section */29	sect->count = cpu_to_le16(1);30	sect->offset = cpu_to_le16(ICE_META_VLAN_MODE_ENTRY);31 32	status = ice_aq_upload_section(hw,33				       (struct ice_buf_hdr *)ice_pkg_buf(bld),34				       ICE_PKG_BUF_SIZE, NULL);35	if (!status) {36		DECLARE_BITMAP(entry, ICE_META_INIT_BITS);37		u32 arr[ICE_META_INIT_DW_CNT];38		u16 i;39 40		/* convert to host bitmap format */41		for (i = 0; i < ICE_META_INIT_DW_CNT; i++)42			arr[i] = le32_to_cpu(sect->entry.bm[i]);43 44		bitmap_from_arr32(entry, arr, (u16)ICE_META_INIT_BITS);45 46		/* check if DVM is supported */47		*dvm = test_bit(ICE_META_VLAN_MODE_BIT, entry);48	}49 50	ice_pkg_buf_free(hw, bld);51 52	return status;53}54 55/**56 * ice_aq_get_vlan_mode - get the VLAN mode of the device57 * @hw: pointer to the HW structure58 * @get_params: structure FW fills in based on the current VLAN mode config59 *60 * Get VLAN Mode Parameters (0x020D)61 */62static int63ice_aq_get_vlan_mode(struct ice_hw *hw,64		     struct ice_aqc_get_vlan_mode *get_params)65{66	struct ice_aq_desc desc;67 68	if (!get_params)69		return -EINVAL;70 71	ice_fill_dflt_direct_cmd_desc(&desc,72				      ice_aqc_opc_get_vlan_mode_parameters);73 74	return ice_aq_send_cmd(hw, &desc, get_params, sizeof(*get_params),75			       NULL);76}77 78/**79 * ice_aq_is_dvm_ena - query FW to check if double VLAN mode is enabled80 * @hw: pointer to the HW structure81 *82 * Returns true if the hardware/firmware is configured in double VLAN mode,83 * else return false signaling that the hardware/firmware is configured in84 * single VLAN mode.85 *86 * Also, return false if this call fails for any reason (i.e. firmware doesn't87 * support this AQ call).88 */89static bool ice_aq_is_dvm_ena(struct ice_hw *hw)90{91	struct ice_aqc_get_vlan_mode get_params = { 0 };92	int status;93 94	status = ice_aq_get_vlan_mode(hw, &get_params);95	if (status) {96		ice_debug(hw, ICE_DBG_AQ, "Failed to get VLAN mode, status %d\n",97			  status);98		return false;99	}100 101	return (get_params.vlan_mode & ICE_AQ_VLAN_MODE_DVM_ENA);102}103 104/**105 * ice_is_dvm_ena - check if double VLAN mode is enabled106 * @hw: pointer to the HW structure107 *108 * The device is configured in single or double VLAN mode on initialization and109 * this cannot be dynamically changed during runtime. Based on this there is no110 * need to make an AQ call every time the driver needs to know the VLAN mode.111 * Instead, use the cached VLAN mode.112 */113bool ice_is_dvm_ena(struct ice_hw *hw)114{115	return hw->dvm_ena;116}117 118/**119 * ice_cache_vlan_mode - cache VLAN mode after DDP is downloaded120 * @hw: pointer to the HW structure121 *122 * This is only called after downloading the DDP and after the global123 * configuration lock has been released because all ports on a device need to124 * cache the VLAN mode.125 */126static void ice_cache_vlan_mode(struct ice_hw *hw)127{128	hw->dvm_ena = ice_aq_is_dvm_ena(hw) ? true : false;129}130 131/**132 * ice_pkg_supports_dvm - find out if DDP supports DVM133 * @hw: pointer to the HW structure134 */135static bool ice_pkg_supports_dvm(struct ice_hw *hw)136{137	bool pkg_supports_dvm;138	int status;139 140	status = ice_pkg_get_supported_vlan_mode(hw, &pkg_supports_dvm);141	if (status) {142		ice_debug(hw, ICE_DBG_PKG, "Failed to get supported VLAN mode, status %d\n",143			  status);144		return false;145	}146 147	return pkg_supports_dvm;148}149 150/**151 * ice_fw_supports_dvm - find out if FW supports DVM152 * @hw: pointer to the HW structure153 */154static bool ice_fw_supports_dvm(struct ice_hw *hw)155{156	struct ice_aqc_get_vlan_mode get_vlan_mode = { 0 };157	int status;158 159	/* If firmware returns success, then it supports DVM, else it only160	 * supports SVM161	 */162	status = ice_aq_get_vlan_mode(hw, &get_vlan_mode);163	if (status) {164		ice_debug(hw, ICE_DBG_NVM, "Failed to get VLAN mode, status %d\n",165			  status);166		return false;167	}168 169	return true;170}171 172/**173 * ice_is_dvm_supported - check if Double VLAN Mode is supported174 * @hw: pointer to the hardware structure175 *176 * Returns true if Double VLAN Mode (DVM) is supported and false if only Single177 * VLAN Mode (SVM) is supported. In order for DVM to be supported the DDP and178 * firmware must support it, otherwise only SVM is supported. This function179 * should only be called while the global config lock is held and after the180 * package has been successfully downloaded.181 */182static bool ice_is_dvm_supported(struct ice_hw *hw)183{184	if (!ice_pkg_supports_dvm(hw)) {185		ice_debug(hw, ICE_DBG_PKG, "DDP doesn't support DVM\n");186		return false;187	}188 189	if (!ice_fw_supports_dvm(hw)) {190		ice_debug(hw, ICE_DBG_PKG, "FW doesn't support DVM\n");191		return false;192	}193 194	return true;195}196 197#define ICE_EXTERNAL_VLAN_ID_FV_IDX			11198#define ICE_SW_LKUP_VLAN_LOC_LKUP_IDX			1199#define ICE_SW_LKUP_VLAN_PKT_FLAGS_LKUP_IDX		2200#define ICE_SW_LKUP_PROMISC_VLAN_LOC_LKUP_IDX		2201#define ICE_PKT_FLAGS_0_TO_15_FV_IDX			1202static struct ice_update_recipe_lkup_idx_params ice_dvm_dflt_recipes[] = {203	{204		/* Update recipe ICE_SW_LKUP_VLAN to filter based on the205		 * outer/single VLAN in DVM206		 */207		.rid = ICE_SW_LKUP_VLAN,208		.fv_idx = ICE_EXTERNAL_VLAN_ID_FV_IDX,209		.ignore_valid = true,210		.mask = 0,211		.mask_valid = false, /* use pre-existing mask */212		.lkup_idx = ICE_SW_LKUP_VLAN_LOC_LKUP_IDX,213	},214	{215		/* Update recipe ICE_SW_LKUP_VLAN to filter based on the VLAN216		 * packet flags to support VLAN filtering on multiple VLAN217		 * ethertypes (i.e. 0x8100 and 0x88a8) in DVM218		 */219		.rid = ICE_SW_LKUP_VLAN,220		.fv_idx = ICE_PKT_FLAGS_0_TO_15_FV_IDX,221		.ignore_valid = false,222		.mask = ICE_PKT_VLAN_MASK,223		.mask_valid = true,224		.lkup_idx = ICE_SW_LKUP_VLAN_PKT_FLAGS_LKUP_IDX,225	},226	{227		/* Update recipe ICE_SW_LKUP_PROMISC_VLAN to filter based on the228		 * outer/single VLAN in DVM229		 */230		.rid = ICE_SW_LKUP_PROMISC_VLAN,231		.fv_idx = ICE_EXTERNAL_VLAN_ID_FV_IDX,232		.ignore_valid = true,233		.mask = 0,234		.mask_valid = false,  /* use pre-existing mask */235		.lkup_idx = ICE_SW_LKUP_PROMISC_VLAN_LOC_LKUP_IDX,236	},237};238 239/**240 * ice_dvm_update_dflt_recipes - update default switch recipes in DVM241 * @hw: hardware structure used to update the recipes242 */243static int ice_dvm_update_dflt_recipes(struct ice_hw *hw)244{245	unsigned long i;246 247	for (i = 0; i < ARRAY_SIZE(ice_dvm_dflt_recipes); i++) {248		struct ice_update_recipe_lkup_idx_params *params;249		int status;250 251		params = &ice_dvm_dflt_recipes[i];252 253		status = ice_update_recipe_lkup_idx(hw, params);254		if (status) {255			ice_debug(hw, ICE_DBG_INIT, "Failed to update RID %d lkup_idx %d fv_idx %d mask_valid %s mask 0x%04x\n",256				  params->rid, params->lkup_idx, params->fv_idx,257				  params->mask_valid ? "true" : "false",258				  params->mask);259			return status;260		}261	}262 263	return 0;264}265 266/**267 * ice_aq_set_vlan_mode - set the VLAN mode of the device268 * @hw: pointer to the HW structure269 * @set_params: requested VLAN mode configuration270 *271 * Set VLAN Mode Parameters (0x020C)272 */273static int274ice_aq_set_vlan_mode(struct ice_hw *hw,275		     struct ice_aqc_set_vlan_mode *set_params)276{277	u8 rdma_packet, mng_vlan_prot_id;278	struct ice_aq_desc desc;279 280	if (!set_params)281		return -EINVAL;282 283	if (set_params->l2tag_prio_tagging > ICE_AQ_VLAN_PRIO_TAG_MAX)284		return -EINVAL;285 286	rdma_packet = set_params->rdma_packet;287	if (rdma_packet != ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING &&288	    rdma_packet != ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING)289		return -EINVAL;290 291	mng_vlan_prot_id = set_params->mng_vlan_prot_id;292	if (mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER &&293	    mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER)294		return -EINVAL;295 296	ice_fill_dflt_direct_cmd_desc(&desc,297				      ice_aqc_opc_set_vlan_mode_parameters);298	desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD);299 300	return ice_aq_send_cmd(hw, &desc, set_params, sizeof(*set_params),301			       NULL);302}303 304/**305 * ice_set_dvm - sets up software and hardware for double VLAN mode306 * @hw: pointer to the hardware structure307 */308static int ice_set_dvm(struct ice_hw *hw)309{310	struct ice_aqc_set_vlan_mode params = { 0 };311	int status;312 313	params.l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_OUTER_CTAG;314	params.rdma_packet = ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING;315	params.mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER;316 317	status = ice_aq_set_vlan_mode(hw, &params);318	if (status) {319		ice_debug(hw, ICE_DBG_INIT, "Failed to set double VLAN mode parameters, status %d\n",320			  status);321		return status;322	}323 324	status = ice_dvm_update_dflt_recipes(hw);325	if (status) {326		ice_debug(hw, ICE_DBG_INIT, "Failed to update default recipes for double VLAN mode, status %d\n",327			  status);328		return status;329	}330 331	status = ice_aq_set_port_params(hw->port_info, true, NULL);332	if (status) {333		ice_debug(hw, ICE_DBG_INIT, "Failed to set port in double VLAN mode, status %d\n",334			  status);335		return status;336	}337 338	status = ice_set_dvm_boost_entries(hw);339	if (status) {340		ice_debug(hw, ICE_DBG_INIT, "Failed to set boost TCAM entries for double VLAN mode, status %d\n",341			  status);342		return status;343	}344 345	return 0;346}347 348/**349 * ice_set_svm - set single VLAN mode350 * @hw: pointer to the HW structure351 */352static int ice_set_svm(struct ice_hw *hw)353{354	struct ice_aqc_set_vlan_mode *set_params;355	int status;356 357	status = ice_aq_set_port_params(hw->port_info, false, NULL);358	if (status) {359		ice_debug(hw, ICE_DBG_INIT, "Failed to set port parameters for single VLAN mode\n");360		return status;361	}362 363	set_params = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*set_params),364				  GFP_KERNEL);365	if (!set_params)366		return -ENOMEM;367 368	/* default configuration for SVM configurations */369	set_params->l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_INNER_CTAG;370	set_params->rdma_packet = ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING;371	set_params->mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER;372 373	status = ice_aq_set_vlan_mode(hw, set_params);374	if (status)375		ice_debug(hw, ICE_DBG_INIT, "Failed to configure port in single VLAN mode\n");376 377	devm_kfree(ice_hw_to_dev(hw), set_params);378	return status;379}380 381/**382 * ice_set_vlan_mode383 * @hw: pointer to the HW structure384 */385int ice_set_vlan_mode(struct ice_hw *hw)386{387	if (!ice_is_dvm_supported(hw))388		return 0;389 390	if (!ice_set_dvm(hw))391		return 0;392 393	return ice_set_svm(hw);394}395 396/**397 * ice_print_dvm_not_supported - print if DDP and/or FW doesn't support DVM398 * @hw: pointer to the HW structure399 *400 * The purpose of this function is to print that  QinQ is not supported due to401 * incompatibilty from the DDP and/or FW. This will give a hint to the user to402 * update one and/or both components if they expect QinQ functionality.403 */404static void ice_print_dvm_not_supported(struct ice_hw *hw)405{406	bool pkg_supports_dvm = ice_pkg_supports_dvm(hw);407	bool fw_supports_dvm = ice_fw_supports_dvm(hw);408 409	if (!fw_supports_dvm && !pkg_supports_dvm)410		dev_info(ice_hw_to_dev(hw), "QinQ functionality cannot be enabled on this device. Update your DDP package and NVM to versions that support QinQ.\n");411	else if (!pkg_supports_dvm)412		dev_info(ice_hw_to_dev(hw), "QinQ functionality cannot be enabled on this device. Update your DDP package to a version that supports QinQ.\n");413	else if (!fw_supports_dvm)414		dev_info(ice_hw_to_dev(hw), "QinQ functionality cannot be enabled on this device. Update your NVM to a version that supports QinQ.\n");415}416 417/**418 * ice_post_pkg_dwnld_vlan_mode_cfg - configure VLAN mode after DDP download419 * @hw: pointer to the HW structure420 *421 * This function is meant to configure any VLAN mode specific functionality422 * after the global configuration lock has been released and the DDP has been423 * downloaded.424 *425 * Since only one PF downloads the DDP and configures the VLAN mode there needs426 * to be a way to configure the other PFs after the DDP has been downloaded and427 * the global configuration lock has been released. All such code should go in428 * this function.429 */430void ice_post_pkg_dwnld_vlan_mode_cfg(struct ice_hw *hw)431{432	ice_cache_vlan_mode(hw);433 434	if (ice_is_dvm_ena(hw))435		ice_change_proto_id_to_dvm();436	else437		ice_print_dvm_not_supported(hw);438}439