ice_vlan_mode.c (12565B)
1// SPDX-License-Identifier: GPL-2.0 2/* 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 mode 8 * @hw: pointer to the HW struct 9 * @dvm: output variable to determine if DDP supports DVM(true) or SVM(false) 10 */ 11static int 12ice_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 **)§); 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 device 57 * @hw: pointer to the HW structure 58 * @get_params: structure FW fills in based on the current VLAN mode config 59 * 60 * Get VLAN Mode Parameters (0x020D) 61 */ 62static int 63ice_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 enabled 80 * @hw: pointer to the HW structure 81 * 82 * Returns true if the hardware/firmware is configured in double VLAN mode, 83 * else return false signaling that the hardware/firmware is configured in 84 * single VLAN mode. 85 * 86 * Also, return false if this call fails for any reason (i.e. firmware doesn't 87 * 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 enabled 106 * @hw: pointer to the HW structure 107 * 108 * The device is configured in single or double VLAN mode on initialization and 109 * this cannot be dynamically changed during runtime. Based on this there is no 110 * 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 downloaded 120 * @hw: pointer to the HW structure 121 * 122 * This is only called after downloading the DDP and after the global 123 * configuration lock has been released because all ports on a device need to 124 * 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 DVM 133 * @hw: pointer to the HW structure 134 */ 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 DVM 152 * @hw: pointer to the HW structure 153 */ 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 only 160 * supports SVM 161 */ 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 supported 174 * @hw: pointer to the hardware structure 175 * 176 * Returns true if Double VLAN Mode (DVM) is supported and false if only Single 177 * VLAN Mode (SVM) is supported. In order for DVM to be supported the DDP and 178 * firmware must support it, otherwise only SVM is supported. This function 179 * should only be called while the global config lock is held and after the 180 * 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 11 198#define ICE_SW_LKUP_VLAN_LOC_LKUP_IDX 1 199#define ICE_SW_LKUP_VLAN_PKT_FLAGS_LKUP_IDX 2 200#define ICE_SW_LKUP_PROMISC_VLAN_LOC_LKUP_IDX 2 201#define ICE_PKT_FLAGS_0_TO_15_FV_IDX 1 202#define ICE_PKT_FLAGS_0_TO_15_VLAN_FLAGS_MASK 0xD000 203static struct ice_update_recipe_lkup_idx_params ice_dvm_dflt_recipes[] = { 204 { 205 /* Update recipe ICE_SW_LKUP_VLAN to filter based on the 206 * outer/single VLAN in DVM 207 */ 208 .rid = ICE_SW_LKUP_VLAN, 209 .fv_idx = ICE_EXTERNAL_VLAN_ID_FV_IDX, 210 .ignore_valid = true, 211 .mask = 0, 212 .mask_valid = false, /* use pre-existing mask */ 213 .lkup_idx = ICE_SW_LKUP_VLAN_LOC_LKUP_IDX, 214 }, 215 { 216 /* Update recipe ICE_SW_LKUP_VLAN to filter based on the VLAN 217 * packet flags to support VLAN filtering on multiple VLAN 218 * ethertypes (i.e. 0x8100 and 0x88a8) in DVM 219 */ 220 .rid = ICE_SW_LKUP_VLAN, 221 .fv_idx = ICE_PKT_FLAGS_0_TO_15_FV_IDX, 222 .ignore_valid = false, 223 .mask = ICE_PKT_FLAGS_0_TO_15_VLAN_FLAGS_MASK, 224 .mask_valid = true, 225 .lkup_idx = ICE_SW_LKUP_VLAN_PKT_FLAGS_LKUP_IDX, 226 }, 227 { 228 /* Update recipe ICE_SW_LKUP_PROMISC_VLAN to filter based on the 229 * outer/single VLAN in DVM 230 */ 231 .rid = ICE_SW_LKUP_PROMISC_VLAN, 232 .fv_idx = ICE_EXTERNAL_VLAN_ID_FV_IDX, 233 .ignore_valid = true, 234 .mask = 0, 235 .mask_valid = false, /* use pre-existing mask */ 236 .lkup_idx = ICE_SW_LKUP_PROMISC_VLAN_LOC_LKUP_IDX, 237 }, 238}; 239 240/** 241 * ice_dvm_update_dflt_recipes - update default switch recipes in DVM 242 * @hw: hardware structure used to update the recipes 243 */ 244static int ice_dvm_update_dflt_recipes(struct ice_hw *hw) 245{ 246 unsigned long i; 247 248 for (i = 0; i < ARRAY_SIZE(ice_dvm_dflt_recipes); i++) { 249 struct ice_update_recipe_lkup_idx_params *params; 250 int status; 251 252 params = &ice_dvm_dflt_recipes[i]; 253 254 status = ice_update_recipe_lkup_idx(hw, params); 255 if (status) { 256 ice_debug(hw, ICE_DBG_INIT, "Failed to update RID %d lkup_idx %d fv_idx %d mask_valid %s mask 0x%04x\n", 257 params->rid, params->lkup_idx, params->fv_idx, 258 params->mask_valid ? "true" : "false", 259 params->mask); 260 return status; 261 } 262 } 263 264 return 0; 265} 266 267/** 268 * ice_aq_set_vlan_mode - set the VLAN mode of the device 269 * @hw: pointer to the HW structure 270 * @set_params: requested VLAN mode configuration 271 * 272 * Set VLAN Mode Parameters (0x020C) 273 */ 274static int 275ice_aq_set_vlan_mode(struct ice_hw *hw, 276 struct ice_aqc_set_vlan_mode *set_params) 277{ 278 u8 rdma_packet, mng_vlan_prot_id; 279 struct ice_aq_desc desc; 280 281 if (!set_params) 282 return -EINVAL; 283 284 if (set_params->l2tag_prio_tagging > ICE_AQ_VLAN_PRIO_TAG_MAX) 285 return -EINVAL; 286 287 rdma_packet = set_params->rdma_packet; 288 if (rdma_packet != ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING && 289 rdma_packet != ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING) 290 return -EINVAL; 291 292 mng_vlan_prot_id = set_params->mng_vlan_prot_id; 293 if (mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER && 294 mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER) 295 return -EINVAL; 296 297 ice_fill_dflt_direct_cmd_desc(&desc, 298 ice_aqc_opc_set_vlan_mode_parameters); 299 desc.flags |= cpu_to_le16(ICE_AQ_FLAG_RD); 300 301 return ice_aq_send_cmd(hw, &desc, set_params, sizeof(*set_params), 302 NULL); 303} 304 305/** 306 * ice_set_dvm - sets up software and hardware for double VLAN mode 307 * @hw: pointer to the hardware structure 308 */ 309static int ice_set_dvm(struct ice_hw *hw) 310{ 311 struct ice_aqc_set_vlan_mode params = { 0 }; 312 int status; 313 314 params.l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_OUTER_CTAG; 315 params.rdma_packet = ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING; 316 params.mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER; 317 318 status = ice_aq_set_vlan_mode(hw, ¶ms); 319 if (status) { 320 ice_debug(hw, ICE_DBG_INIT, "Failed to set double VLAN mode parameters, status %d\n", 321 status); 322 return status; 323 } 324 325 status = ice_dvm_update_dflt_recipes(hw); 326 if (status) { 327 ice_debug(hw, ICE_DBG_INIT, "Failed to update default recipes for double VLAN mode, status %d\n", 328 status); 329 return status; 330 } 331 332 status = ice_aq_set_port_params(hw->port_info, true, NULL); 333 if (status) { 334 ice_debug(hw, ICE_DBG_INIT, "Failed to set port in double VLAN mode, status %d\n", 335 status); 336 return status; 337 } 338 339 status = ice_set_dvm_boost_entries(hw); 340 if (status) { 341 ice_debug(hw, ICE_DBG_INIT, "Failed to set boost TCAM entries for double VLAN mode, status %d\n", 342 status); 343 return status; 344 } 345 346 return 0; 347} 348 349/** 350 * ice_set_svm - set single VLAN mode 351 * @hw: pointer to the HW structure 352 */ 353static int ice_set_svm(struct ice_hw *hw) 354{ 355 struct ice_aqc_set_vlan_mode *set_params; 356 int status; 357 358 status = ice_aq_set_port_params(hw->port_info, false, NULL); 359 if (status) { 360 ice_debug(hw, ICE_DBG_INIT, "Failed to set port parameters for single VLAN mode\n"); 361 return status; 362 } 363 364 set_params = devm_kzalloc(ice_hw_to_dev(hw), sizeof(*set_params), 365 GFP_KERNEL); 366 if (!set_params) 367 return -ENOMEM; 368 369 /* default configuration for SVM configurations */ 370 set_params->l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_INNER_CTAG; 371 set_params->rdma_packet = ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING; 372 set_params->mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER; 373 374 status = ice_aq_set_vlan_mode(hw, set_params); 375 if (status) 376 ice_debug(hw, ICE_DBG_INIT, "Failed to configure port in single VLAN mode\n"); 377 378 devm_kfree(ice_hw_to_dev(hw), set_params); 379 return status; 380} 381 382/** 383 * ice_set_vlan_mode 384 * @hw: pointer to the HW structure 385 */ 386int ice_set_vlan_mode(struct ice_hw *hw) 387{ 388 if (!ice_is_dvm_supported(hw)) 389 return 0; 390 391 if (!ice_set_dvm(hw)) 392 return 0; 393 394 return ice_set_svm(hw); 395} 396 397/** 398 * ice_print_dvm_not_supported - print if DDP and/or FW doesn't support DVM 399 * @hw: pointer to the HW structure 400 * 401 * The purpose of this function is to print that QinQ is not supported due to 402 * incompatibilty from the DDP and/or FW. This will give a hint to the user to 403 * update one and/or both components if they expect QinQ functionality. 404 */ 405static void ice_print_dvm_not_supported(struct ice_hw *hw) 406{ 407 bool pkg_supports_dvm = ice_pkg_supports_dvm(hw); 408 bool fw_supports_dvm = ice_fw_supports_dvm(hw); 409 410 if (!fw_supports_dvm && !pkg_supports_dvm) 411 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"); 412 else if (!pkg_supports_dvm) 413 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"); 414 else if (!fw_supports_dvm) 415 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"); 416} 417 418/** 419 * ice_post_pkg_dwnld_vlan_mode_cfg - configure VLAN mode after DDP download 420 * @hw: pointer to the HW structure 421 * 422 * This function is meant to configure any VLAN mode specific functionality 423 * after the global configuration lock has been released and the DDP has been 424 * downloaded. 425 * 426 * Since only one PF downloads the DDP and configures the VLAN mode there needs 427 * to be a way to configure the other PFs after the DDP has been downloaded and 428 * the global configuration lock has been released. All such code should go in 429 * this function. 430 */ 431void ice_post_pkg_dwnld_vlan_mode_cfg(struct ice_hw *hw) 432{ 433 ice_cache_vlan_mode(hw); 434 435 if (ice_is_dvm_ena(hw)) 436 ice_change_proto_id_to_dvm(); 437 else 438 ice_print_dvm_not_supported(hw); 439}