xref: /freebsd/sys/dev/ice/ice_vlan_mode.c (revision f2635e844dd138ac9dfba676f27d41750049af26)
1d08b8680SEric Joyner /* SPDX-License-Identifier: BSD-3-Clause */
2015f8cc5SEric Joyner /*  Copyright (c) 2024, Intel Corporation
3d08b8680SEric Joyner  *  All rights reserved.
4d08b8680SEric Joyner  *
5d08b8680SEric Joyner  *  Redistribution and use in source and binary forms, with or without
6d08b8680SEric Joyner  *  modification, are permitted provided that the following conditions are met:
7d08b8680SEric Joyner  *
8d08b8680SEric Joyner  *   1. Redistributions of source code must retain the above copyright notice,
9d08b8680SEric Joyner  *      this list of conditions and the following disclaimer.
10d08b8680SEric Joyner  *
11d08b8680SEric Joyner  *   2. Redistributions in binary form must reproduce the above copyright
12d08b8680SEric Joyner  *      notice, this list of conditions and the following disclaimer in the
13d08b8680SEric Joyner  *      documentation and/or other materials provided with the distribution.
14d08b8680SEric Joyner  *
15d08b8680SEric Joyner  *   3. Neither the name of the Intel Corporation nor the names of its
16d08b8680SEric Joyner  *      contributors may be used to endorse or promote products derived from
17d08b8680SEric Joyner  *      this software without specific prior written permission.
18d08b8680SEric Joyner  *
19d08b8680SEric Joyner  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20d08b8680SEric Joyner  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21d08b8680SEric Joyner  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22d08b8680SEric Joyner  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23d08b8680SEric Joyner  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24d08b8680SEric Joyner  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25d08b8680SEric Joyner  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26d08b8680SEric Joyner  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27d08b8680SEric Joyner  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28d08b8680SEric Joyner  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29d08b8680SEric Joyner  *  POSSIBILITY OF SUCH DAMAGE.
30d08b8680SEric Joyner  */
31d08b8680SEric Joyner 
32d08b8680SEric Joyner #include "ice_common.h"
33d08b8680SEric Joyner 
348923de59SPiotr Kubaj #include "ice_ddp_common.h"
35d08b8680SEric Joyner /**
3656429daeSEric Joyner  * ice_pkg_get_supported_vlan_mode - chk if DDP supports Double VLAN mode (DVM)
379cf1841cSEric Joyner  * @hw: pointer to the HW struct
389cf1841cSEric Joyner  * @dvm: output variable to determine if DDP supports DVM(true) or SVM(false)
399cf1841cSEric Joyner  */
40*f2635e84SEric Joyner static int
419cf1841cSEric Joyner ice_pkg_get_supported_vlan_mode(struct ice_hw *hw, bool *dvm)
429cf1841cSEric Joyner {
439cf1841cSEric Joyner 	u16 meta_init_size = sizeof(struct ice_meta_init_section);
449cf1841cSEric Joyner 	struct ice_meta_init_section *sect;
459cf1841cSEric Joyner 	struct ice_buf_build *bld;
46*f2635e84SEric Joyner 	int status;
479cf1841cSEric Joyner 
489cf1841cSEric Joyner 	/* if anything fails, we assume there is no DVM support */
499cf1841cSEric Joyner 	*dvm = false;
509cf1841cSEric Joyner 
519cf1841cSEric Joyner 	bld = ice_pkg_buf_alloc_single_section(hw,
529cf1841cSEric Joyner 					       ICE_SID_RXPARSER_METADATA_INIT,
539cf1841cSEric Joyner 					       meta_init_size, (void **)&sect);
549cf1841cSEric Joyner 	if (!bld)
559cf1841cSEric Joyner 		return ICE_ERR_NO_MEMORY;
569cf1841cSEric Joyner 
579cf1841cSEric Joyner 	/* only need to read a single section */
589cf1841cSEric Joyner 	sect->count = CPU_TO_LE16(1);
599cf1841cSEric Joyner 	sect->offset = CPU_TO_LE16(ICE_META_VLAN_MODE_ENTRY);
609cf1841cSEric Joyner 
619cf1841cSEric Joyner 	status = ice_aq_upload_section(hw,
629cf1841cSEric Joyner 				       (struct ice_buf_hdr *)ice_pkg_buf(bld),
639cf1841cSEric Joyner 				       ICE_PKG_BUF_SIZE, NULL);
649cf1841cSEric Joyner 	if (!status) {
659cf1841cSEric Joyner 		ice_declare_bitmap(entry, ICE_META_INIT_BITS);
669cf1841cSEric Joyner 		u32 arr[ICE_META_INIT_DW_CNT];
679cf1841cSEric Joyner 		u16 i;
689cf1841cSEric Joyner 
699cf1841cSEric Joyner 		/* convert to host bitmap format */
709cf1841cSEric Joyner 		for (i = 0; i < ICE_META_INIT_DW_CNT; i++)
719cf1841cSEric Joyner 			arr[i] = LE32_TO_CPU(sect->entry[0].bm[i]);
729cf1841cSEric Joyner 
739cf1841cSEric Joyner 		ice_bitmap_from_array32(entry, arr, (u16)ICE_META_INIT_BITS);
749cf1841cSEric Joyner 
759cf1841cSEric Joyner 		/* check if DVM is supported */
769cf1841cSEric Joyner 		*dvm = ice_is_bit_set(entry, ICE_META_VLAN_MODE_BIT);
779cf1841cSEric Joyner 	}
789cf1841cSEric Joyner 
799cf1841cSEric Joyner 	ice_pkg_buf_free(hw, bld);
809cf1841cSEric Joyner 
819cf1841cSEric Joyner 	return status;
829cf1841cSEric Joyner }
839cf1841cSEric Joyner 
849cf1841cSEric Joyner /**
859cf1841cSEric Joyner  * ice_aq_get_vlan_mode - get the VLAN mode of the device
869cf1841cSEric Joyner  * @hw: pointer to the HW structure
879cf1841cSEric Joyner  * @get_params: structure FW fills in based on the current VLAN mode config
889cf1841cSEric Joyner  *
899cf1841cSEric Joyner  * Get VLAN Mode Parameters (0x020D)
909cf1841cSEric Joyner  */
91*f2635e84SEric Joyner static int
929cf1841cSEric Joyner ice_aq_get_vlan_mode(struct ice_hw *hw,
939cf1841cSEric Joyner 		     struct ice_aqc_get_vlan_mode *get_params)
949cf1841cSEric Joyner {
959cf1841cSEric Joyner 	struct ice_aq_desc desc;
969cf1841cSEric Joyner 
979cf1841cSEric Joyner 	if (!get_params)
989cf1841cSEric Joyner 		return ICE_ERR_PARAM;
999cf1841cSEric Joyner 
1009cf1841cSEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc,
1019cf1841cSEric Joyner 				      ice_aqc_opc_get_vlan_mode_parameters);
1029cf1841cSEric Joyner 
1039cf1841cSEric Joyner 	return ice_aq_send_cmd(hw, &desc, get_params, sizeof(*get_params),
1049cf1841cSEric Joyner 			       NULL);
1059cf1841cSEric Joyner }
1069cf1841cSEric Joyner 
1079cf1841cSEric Joyner /**
1089cf1841cSEric Joyner  * ice_aq_is_dvm_ena - query FW to check if double VLAN mode is enabled
1099cf1841cSEric Joyner  * @hw: pointer to the HW structure
1109cf1841cSEric Joyner  *
1119cf1841cSEric Joyner  * Returns true if the hardware/firmware is configured in double VLAN mode,
1129cf1841cSEric Joyner  * else return false signaling that the hardware/firmware is configured in
1139cf1841cSEric Joyner  * single VLAN mode.
1149cf1841cSEric Joyner  *
1159cf1841cSEric Joyner  * Also, return false if this call fails for any reason (i.e. firmware doesn't
1169cf1841cSEric Joyner  * support this AQ call).
1179cf1841cSEric Joyner  */
1189cf1841cSEric Joyner static bool ice_aq_is_dvm_ena(struct ice_hw *hw)
1199cf1841cSEric Joyner {
1209cf1841cSEric Joyner 	struct ice_aqc_get_vlan_mode get_params = { 0 };
121*f2635e84SEric Joyner 	int status;
1229cf1841cSEric Joyner 
1239cf1841cSEric Joyner 	status = ice_aq_get_vlan_mode(hw, &get_params);
1249cf1841cSEric Joyner 	if (status) {
1259cf1841cSEric Joyner 		ice_debug(hw, ICE_DBG_AQ, "Failed to get VLAN mode, status %d\n",
1269cf1841cSEric Joyner 			  status);
1279cf1841cSEric Joyner 		return false;
1289cf1841cSEric Joyner 	}
1299cf1841cSEric Joyner 
1309cf1841cSEric Joyner 	return (get_params.vlan_mode & ICE_AQ_VLAN_MODE_DVM_ENA);
1319cf1841cSEric Joyner }
1329cf1841cSEric Joyner 
1339cf1841cSEric Joyner /**
1349cf1841cSEric Joyner  * ice_is_dvm_ena - check if double VLAN mode is enabled
1359cf1841cSEric Joyner  * @hw: pointer to the HW structure
1369cf1841cSEric Joyner  *
1379cf1841cSEric Joyner  * The device is configured in single or double VLAN mode on initialization and
1389cf1841cSEric Joyner  * this cannot be dynamically changed during runtime. Based on this there is no
1399cf1841cSEric Joyner  * need to make an AQ call every time the driver needs to know the VLAN mode.
1409cf1841cSEric Joyner  * Instead, use the cached VLAN mode.
1419cf1841cSEric Joyner  */
1429cf1841cSEric Joyner bool ice_is_dvm_ena(struct ice_hw *hw)
1439cf1841cSEric Joyner {
1449cf1841cSEric Joyner 	return hw->dvm_ena;
1459cf1841cSEric Joyner }
1469cf1841cSEric Joyner 
1479cf1841cSEric Joyner /**
1489cf1841cSEric Joyner  * ice_cache_vlan_mode - cache VLAN mode after DDP is downloaded
1499cf1841cSEric Joyner  * @hw: pointer to the HW structure
1509cf1841cSEric Joyner  *
1519cf1841cSEric Joyner  * This is only called after downloading the DDP and after the global
1529cf1841cSEric Joyner  * configuration lock has been released because all ports on a device need to
1539cf1841cSEric Joyner  * cache the VLAN mode.
1549cf1841cSEric Joyner  */
15556429daeSEric Joyner static void ice_cache_vlan_mode(struct ice_hw *hw)
1569cf1841cSEric Joyner {
1579cf1841cSEric Joyner 	hw->dvm_ena = ice_aq_is_dvm_ena(hw) ? true : false;
1589cf1841cSEric Joyner }
1599cf1841cSEric Joyner 
1609cf1841cSEric Joyner /**
16156429daeSEric Joyner  * ice_pkg_supports_dvm - find out if DDP supports DVM
16256429daeSEric Joyner  * @hw: pointer to the HW structure
16356429daeSEric Joyner  */
16456429daeSEric Joyner static bool ice_pkg_supports_dvm(struct ice_hw *hw)
16556429daeSEric Joyner {
166*f2635e84SEric Joyner 	int status;
16756429daeSEric Joyner 	bool pkg_supports_dvm;
16856429daeSEric Joyner 
16956429daeSEric Joyner 	status = ice_pkg_get_supported_vlan_mode(hw, &pkg_supports_dvm);
17056429daeSEric Joyner 	if (status) {
17156429daeSEric Joyner 		ice_debug(hw, ICE_DBG_PKG, "Failed to get supported VLAN mode, status %d\n",
17256429daeSEric Joyner 			  status);
17356429daeSEric Joyner 		return false;
17456429daeSEric Joyner 	}
17556429daeSEric Joyner 
17656429daeSEric Joyner 	return pkg_supports_dvm;
17756429daeSEric Joyner }
17856429daeSEric Joyner 
17956429daeSEric Joyner /**
18056429daeSEric Joyner  * ice_fw_supports_dvm - find out if FW supports DVM
18156429daeSEric Joyner  * @hw: pointer to the HW structure
18256429daeSEric Joyner  */
18356429daeSEric Joyner static bool ice_fw_supports_dvm(struct ice_hw *hw)
18456429daeSEric Joyner {
18556429daeSEric Joyner 	struct ice_aqc_get_vlan_mode get_vlan_mode = { 0 };
186*f2635e84SEric Joyner 	int status;
18756429daeSEric Joyner 
18856429daeSEric Joyner 	/* If firmware returns success, then it supports DVM, else it only
18956429daeSEric Joyner 	 * supports SVM
19056429daeSEric Joyner 	 */
19156429daeSEric Joyner 	status = ice_aq_get_vlan_mode(hw, &get_vlan_mode);
19256429daeSEric Joyner 	if (status) {
19356429daeSEric Joyner 		ice_debug(hw, ICE_DBG_NVM, "Failed to get VLAN mode, status %d\n",
19456429daeSEric Joyner 			  status);
19556429daeSEric Joyner 		return false;
19656429daeSEric Joyner 	}
19756429daeSEric Joyner 
19856429daeSEric Joyner 	return true;
19956429daeSEric Joyner }
20056429daeSEric Joyner 
20156429daeSEric Joyner /**
2029cf1841cSEric Joyner  * ice_is_dvm_supported - check if Double VLAN Mode is supported
2039cf1841cSEric Joyner  * @hw: pointer to the hardware structure
2049cf1841cSEric Joyner  *
2059cf1841cSEric Joyner  * Returns true if Double VLAN Mode (DVM) is supported and false if only Single
2069cf1841cSEric Joyner  * VLAN Mode (SVM) is supported. In order for DVM to be supported the DDP and
2079cf1841cSEric Joyner  * firmware must support it, otherwise only SVM is supported. This function
2089cf1841cSEric Joyner  * should only be called while the global config lock is held and after the
2099cf1841cSEric Joyner  * package has been successfully downloaded.
2109cf1841cSEric Joyner  */
2119cf1841cSEric Joyner static bool ice_is_dvm_supported(struct ice_hw *hw)
2129cf1841cSEric Joyner {
21356429daeSEric Joyner 	if (!ice_pkg_supports_dvm(hw)) {
21456429daeSEric Joyner 		ice_debug(hw, ICE_DBG_PKG, "DDP doesn't support DVM\n");
2159cf1841cSEric Joyner 		return false;
2169cf1841cSEric Joyner 	}
2179cf1841cSEric Joyner 
21856429daeSEric Joyner 	if (!ice_fw_supports_dvm(hw)) {
21956429daeSEric Joyner 		ice_debug(hw, ICE_DBG_PKG, "FW doesn't support DVM\n");
2209cf1841cSEric Joyner 		return false;
2219cf1841cSEric Joyner 	}
2229cf1841cSEric Joyner 
2239cf1841cSEric Joyner 	return true;
2249cf1841cSEric Joyner }
2259cf1841cSEric Joyner 
2269cf1841cSEric Joyner /**
2279cf1841cSEric Joyner  * ice_aq_set_vlan_mode - set the VLAN mode of the device
2289cf1841cSEric Joyner  * @hw: pointer to the HW structure
2299cf1841cSEric Joyner  * @set_params: requested VLAN mode configuration
2309cf1841cSEric Joyner  *
2319cf1841cSEric Joyner  * Set VLAN Mode Parameters (0x020C)
2329cf1841cSEric Joyner  */
233*f2635e84SEric Joyner static int
2349cf1841cSEric Joyner ice_aq_set_vlan_mode(struct ice_hw *hw,
2359cf1841cSEric Joyner 		     struct ice_aqc_set_vlan_mode *set_params)
2369cf1841cSEric Joyner {
2379cf1841cSEric Joyner 	u8 rdma_packet, mng_vlan_prot_id;
2389cf1841cSEric Joyner 	struct ice_aq_desc desc;
2399cf1841cSEric Joyner 
2409cf1841cSEric Joyner 	if (!set_params)
2419cf1841cSEric Joyner 		return ICE_ERR_PARAM;
2429cf1841cSEric Joyner 
2439cf1841cSEric Joyner 	if (set_params->l2tag_prio_tagging > ICE_AQ_VLAN_PRIO_TAG_MAX)
2449cf1841cSEric Joyner 		return ICE_ERR_PARAM;
2459cf1841cSEric Joyner 
2469cf1841cSEric Joyner 	rdma_packet = set_params->rdma_packet;
2479cf1841cSEric Joyner 	if (rdma_packet != ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING &&
2489cf1841cSEric Joyner 	    rdma_packet != ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING)
2499cf1841cSEric Joyner 		return ICE_ERR_PARAM;
2509cf1841cSEric Joyner 
2519cf1841cSEric Joyner 	mng_vlan_prot_id = set_params->mng_vlan_prot_id;
2529cf1841cSEric Joyner 	if (mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER &&
2539cf1841cSEric Joyner 	    mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER)
2549cf1841cSEric Joyner 		return ICE_ERR_PARAM;
2559cf1841cSEric Joyner 
2569cf1841cSEric Joyner 	ice_fill_dflt_direct_cmd_desc(&desc,
2579cf1841cSEric Joyner 				      ice_aqc_opc_set_vlan_mode_parameters);
2589cf1841cSEric Joyner 	desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
2599cf1841cSEric Joyner 
2609cf1841cSEric Joyner 	return ice_aq_send_cmd(hw, &desc, set_params, sizeof(*set_params),
2619cf1841cSEric Joyner 			       NULL);
2629cf1841cSEric Joyner }
2639cf1841cSEric Joyner 
2649cf1841cSEric Joyner /**
265d08b8680SEric Joyner  * ice_set_svm - set single VLAN mode
266d08b8680SEric Joyner  * @hw: pointer to the HW structure
267d08b8680SEric Joyner  */
268*f2635e84SEric Joyner static int ice_set_svm(struct ice_hw *hw)
269d08b8680SEric Joyner {
2709cf1841cSEric Joyner 	struct ice_aqc_set_vlan_mode *set_params;
271*f2635e84SEric Joyner 	int status;
272d08b8680SEric Joyner 
2739cf1841cSEric Joyner 	status = ice_aq_set_port_params(hw->port_info, 0, false, false, false, NULL);
2749cf1841cSEric Joyner 	if (status) {
2759cf1841cSEric Joyner 		ice_debug(hw, ICE_DBG_INIT, "Failed to set port parameters for single VLAN mode\n");
2769cf1841cSEric Joyner 		return status;
277d08b8680SEric Joyner 	}
278d08b8680SEric Joyner 
2799cf1841cSEric Joyner 	set_params = (struct ice_aqc_set_vlan_mode *)
2809cf1841cSEric Joyner 		ice_malloc(hw, sizeof(*set_params));
2819cf1841cSEric Joyner 	if (!set_params)
2829cf1841cSEric Joyner 		return ICE_ERR_NO_MEMORY;
2839cf1841cSEric Joyner 
2849cf1841cSEric Joyner 	/* default configuration for SVM configurations */
2859cf1841cSEric Joyner 	set_params->l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_INNER_CTAG;
2869cf1841cSEric Joyner 	set_params->rdma_packet = ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING;
2879cf1841cSEric Joyner 	set_params->mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER;
2889cf1841cSEric Joyner 
2899cf1841cSEric Joyner 	status = ice_aq_set_vlan_mode(hw, set_params);
2909cf1841cSEric Joyner 	if (status)
2919cf1841cSEric Joyner 		ice_debug(hw, ICE_DBG_INIT, "Failed to configure port in single VLAN mode\n");
2929cf1841cSEric Joyner 
2939cf1841cSEric Joyner 	ice_free(hw, set_params);
2949cf1841cSEric Joyner 	return status;
295d08b8680SEric Joyner }
296d08b8680SEric Joyner 
297d08b8680SEric Joyner /**
298d08b8680SEric Joyner  * ice_set_vlan_mode
299d08b8680SEric Joyner  * @hw: pointer to the HW structure
300d08b8680SEric Joyner  */
301*f2635e84SEric Joyner int ice_set_vlan_mode(struct ice_hw *hw)
302d08b8680SEric Joyner {
3039cf1841cSEric Joyner 	if (!ice_is_dvm_supported(hw))
304*f2635e84SEric Joyner 		return 0;
305d08b8680SEric Joyner 
3069cf1841cSEric Joyner 	return ice_set_svm(hw);
307d08b8680SEric Joyner }
30856429daeSEric Joyner 
30956429daeSEric Joyner /**
31056429daeSEric Joyner  * ice_post_pkg_dwnld_vlan_mode_cfg - configure VLAN mode after DDP download
31156429daeSEric Joyner  * @hw: pointer to the HW structure
31256429daeSEric Joyner  *
31356429daeSEric Joyner  * This function is meant to configure any VLAN mode specific functionality
31456429daeSEric Joyner  * after the global configuration lock has been released and the DDP has been
31556429daeSEric Joyner  * downloaded.
31656429daeSEric Joyner  *
31756429daeSEric Joyner  * Since only one PF downloads the DDP and configures the VLAN mode there needs
31856429daeSEric Joyner  * to be a way to configure the other PFs after the DDP has been downloaded and
31956429daeSEric Joyner  * the global configuration lock has been released. All such code should go in
32056429daeSEric Joyner  * this function.
32156429daeSEric Joyner  */
32256429daeSEric Joyner void ice_post_pkg_dwnld_vlan_mode_cfg(struct ice_hw *hw)
32356429daeSEric Joyner {
32456429daeSEric Joyner 	ice_cache_vlan_mode(hw);
32556429daeSEric Joyner }
326