1 /* SPDX-License-Identifier: BSD-3-Clause */ 2 /* Copyright (c) 2024, Intel Corporation 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * 3. Neither the name of the Intel Corporation nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "ice_common.h" 33 34 #include "ice_ddp_common.h" 35 /** 36 * ice_pkg_get_supported_vlan_mode - chk if DDP supports Double VLAN mode (DVM) 37 * @hw: pointer to the HW struct 38 * @dvm: output variable to determine if DDP supports DVM(true) or SVM(false) 39 */ 40 static int 41 ice_pkg_get_supported_vlan_mode(struct ice_hw *hw, bool *dvm) 42 { 43 u16 meta_init_size = sizeof(struct ice_meta_init_section); 44 struct ice_meta_init_section *sect; 45 struct ice_buf_build *bld; 46 int status; 47 48 /* if anything fails, we assume there is no DVM support */ 49 *dvm = false; 50 51 bld = ice_pkg_buf_alloc_single_section(hw, 52 ICE_SID_RXPARSER_METADATA_INIT, 53 meta_init_size, (void **)§); 54 if (!bld) 55 return ICE_ERR_NO_MEMORY; 56 57 /* only need to read a single section */ 58 sect->count = CPU_TO_LE16(1); 59 sect->offset = CPU_TO_LE16(ICE_META_VLAN_MODE_ENTRY); 60 61 status = ice_aq_upload_section(hw, 62 (struct ice_buf_hdr *)ice_pkg_buf(bld), 63 ICE_PKG_BUF_SIZE, NULL); 64 if (!status) { 65 ice_declare_bitmap(entry, ICE_META_INIT_BITS); 66 u32 arr[ICE_META_INIT_DW_CNT]; 67 u16 i; 68 69 /* convert to host bitmap format */ 70 for (i = 0; i < ICE_META_INIT_DW_CNT; i++) 71 arr[i] = LE32_TO_CPU(sect->entry[0].bm[i]); 72 73 ice_bitmap_from_array32(entry, arr, (u16)ICE_META_INIT_BITS); 74 75 /* check if DVM is supported */ 76 *dvm = ice_is_bit_set(entry, ICE_META_VLAN_MODE_BIT); 77 } 78 79 ice_pkg_buf_free(hw, bld); 80 81 return status; 82 } 83 84 /** 85 * ice_aq_get_vlan_mode - get the VLAN mode of the device 86 * @hw: pointer to the HW structure 87 * @get_params: structure FW fills in based on the current VLAN mode config 88 * 89 * Get VLAN Mode Parameters (0x020D) 90 */ 91 static int 92 ice_aq_get_vlan_mode(struct ice_hw *hw, 93 struct ice_aqc_get_vlan_mode *get_params) 94 { 95 struct ice_aq_desc desc; 96 97 if (!get_params) 98 return ICE_ERR_PARAM; 99 100 ice_fill_dflt_direct_cmd_desc(&desc, 101 ice_aqc_opc_get_vlan_mode_parameters); 102 103 return ice_aq_send_cmd(hw, &desc, get_params, sizeof(*get_params), 104 NULL); 105 } 106 107 /** 108 * ice_aq_is_dvm_ena - query FW to check if double VLAN mode is enabled 109 * @hw: pointer to the HW structure 110 * 111 * Returns true if the hardware/firmware is configured in double VLAN mode, 112 * else return false signaling that the hardware/firmware is configured in 113 * single VLAN mode. 114 * 115 * Also, return false if this call fails for any reason (i.e. firmware doesn't 116 * support this AQ call). 117 */ 118 static bool ice_aq_is_dvm_ena(struct ice_hw *hw) 119 { 120 struct ice_aqc_get_vlan_mode get_params = { 0 }; 121 int status; 122 123 status = ice_aq_get_vlan_mode(hw, &get_params); 124 if (status) { 125 ice_debug(hw, ICE_DBG_AQ, "Failed to get VLAN mode, status %d\n", 126 status); 127 return false; 128 } 129 130 return (get_params.vlan_mode & ICE_AQ_VLAN_MODE_DVM_ENA); 131 } 132 133 /** 134 * ice_is_dvm_ena - check if double VLAN mode is enabled 135 * @hw: pointer to the HW structure 136 * 137 * The device is configured in single or double VLAN mode on initialization and 138 * this cannot be dynamically changed during runtime. Based on this there is no 139 * need to make an AQ call every time the driver needs to know the VLAN mode. 140 * Instead, use the cached VLAN mode. 141 */ 142 bool ice_is_dvm_ena(struct ice_hw *hw) 143 { 144 return hw->dvm_ena; 145 } 146 147 /** 148 * ice_cache_vlan_mode - cache VLAN mode after DDP is downloaded 149 * @hw: pointer to the HW structure 150 * 151 * This is only called after downloading the DDP and after the global 152 * configuration lock has been released because all ports on a device need to 153 * cache the VLAN mode. 154 */ 155 static void ice_cache_vlan_mode(struct ice_hw *hw) 156 { 157 hw->dvm_ena = ice_aq_is_dvm_ena(hw) ? true : false; 158 } 159 160 /** 161 * ice_pkg_supports_dvm - find out if DDP supports DVM 162 * @hw: pointer to the HW structure 163 */ 164 static bool ice_pkg_supports_dvm(struct ice_hw *hw) 165 { 166 int status; 167 bool pkg_supports_dvm; 168 169 status = ice_pkg_get_supported_vlan_mode(hw, &pkg_supports_dvm); 170 if (status) { 171 ice_debug(hw, ICE_DBG_PKG, "Failed to get supported VLAN mode, status %d\n", 172 status); 173 return false; 174 } 175 176 return pkg_supports_dvm; 177 } 178 179 /** 180 * ice_fw_supports_dvm - find out if FW supports DVM 181 * @hw: pointer to the HW structure 182 */ 183 static bool ice_fw_supports_dvm(struct ice_hw *hw) 184 { 185 struct ice_aqc_get_vlan_mode get_vlan_mode = { 0 }; 186 int status; 187 188 /* If firmware returns success, then it supports DVM, else it only 189 * supports SVM 190 */ 191 status = ice_aq_get_vlan_mode(hw, &get_vlan_mode); 192 if (status) { 193 ice_debug(hw, ICE_DBG_NVM, "Failed to get VLAN mode, status %d\n", 194 status); 195 return false; 196 } 197 198 return true; 199 } 200 201 /** 202 * ice_is_dvm_supported - check if Double VLAN Mode is supported 203 * @hw: pointer to the hardware structure 204 * 205 * Returns true if Double VLAN Mode (DVM) is supported and false if only Single 206 * VLAN Mode (SVM) is supported. In order for DVM to be supported the DDP and 207 * firmware must support it, otherwise only SVM is supported. This function 208 * should only be called while the global config lock is held and after the 209 * package has been successfully downloaded. 210 */ 211 static bool ice_is_dvm_supported(struct ice_hw *hw) 212 { 213 if (!ice_pkg_supports_dvm(hw)) { 214 ice_debug(hw, ICE_DBG_PKG, "DDP doesn't support DVM\n"); 215 return false; 216 } 217 218 if (!ice_fw_supports_dvm(hw)) { 219 ice_debug(hw, ICE_DBG_PKG, "FW doesn't support DVM\n"); 220 return false; 221 } 222 223 return true; 224 } 225 226 /** 227 * ice_aq_set_vlan_mode - set the VLAN mode of the device 228 * @hw: pointer to the HW structure 229 * @set_params: requested VLAN mode configuration 230 * 231 * Set VLAN Mode Parameters (0x020C) 232 */ 233 static int 234 ice_aq_set_vlan_mode(struct ice_hw *hw, 235 struct ice_aqc_set_vlan_mode *set_params) 236 { 237 u8 rdma_packet, mng_vlan_prot_id; 238 struct ice_aq_desc desc; 239 240 if (!set_params) 241 return ICE_ERR_PARAM; 242 243 if (set_params->l2tag_prio_tagging > ICE_AQ_VLAN_PRIO_TAG_MAX) 244 return ICE_ERR_PARAM; 245 246 rdma_packet = set_params->rdma_packet; 247 if (rdma_packet != ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING && 248 rdma_packet != ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING) 249 return ICE_ERR_PARAM; 250 251 mng_vlan_prot_id = set_params->mng_vlan_prot_id; 252 if (mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER && 253 mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER) 254 return ICE_ERR_PARAM; 255 256 ice_fill_dflt_direct_cmd_desc(&desc, 257 ice_aqc_opc_set_vlan_mode_parameters); 258 desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD); 259 260 return ice_aq_send_cmd(hw, &desc, set_params, sizeof(*set_params), 261 NULL); 262 } 263 264 /** 265 * ice_set_svm - set single VLAN mode 266 * @hw: pointer to the HW structure 267 */ 268 static int ice_set_svm(struct ice_hw *hw) 269 { 270 struct ice_aqc_set_vlan_mode *set_params; 271 int status; 272 273 status = ice_aq_set_port_params(hw->port_info, 0, false, false, false, NULL); 274 if (status) { 275 ice_debug(hw, ICE_DBG_INIT, "Failed to set port parameters for single VLAN mode\n"); 276 return status; 277 } 278 279 set_params = (struct ice_aqc_set_vlan_mode *) 280 ice_malloc(hw, sizeof(*set_params)); 281 if (!set_params) 282 return ICE_ERR_NO_MEMORY; 283 284 /* default configuration for SVM configurations */ 285 set_params->l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_INNER_CTAG; 286 set_params->rdma_packet = ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING; 287 set_params->mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER; 288 289 status = ice_aq_set_vlan_mode(hw, set_params); 290 if (status) 291 ice_debug(hw, ICE_DBG_INIT, "Failed to configure port in single VLAN mode\n"); 292 293 ice_free(hw, set_params); 294 return status; 295 } 296 297 /** 298 * ice_set_vlan_mode 299 * @hw: pointer to the HW structure 300 */ 301 int ice_set_vlan_mode(struct ice_hw *hw) 302 { 303 if (!ice_is_dvm_supported(hw)) 304 return 0; 305 306 return ice_set_svm(hw); 307 } 308 309 /** 310 * ice_post_pkg_dwnld_vlan_mode_cfg - configure VLAN mode after DDP download 311 * @hw: pointer to the HW structure 312 * 313 * This function is meant to configure any VLAN mode specific functionality 314 * after the global configuration lock has been released and the DDP has been 315 * downloaded. 316 * 317 * Since only one PF downloads the DDP and configures the VLAN mode there needs 318 * to be a way to configure the other PFs after the DDP has been downloaded and 319 * the global configuration lock has been released. All such code should go in 320 * this function. 321 */ 322 void ice_post_pkg_dwnld_vlan_mode_cfg(struct ice_hw *hw) 323 { 324 ice_cache_vlan_mode(hw); 325 } 326