dpdk/drivers/net/ice/base/ice_vlan_mode.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2001-2021 Intel Corporation
   3 */
   4
   5#include "ice_common.h"
   6
   7/**
   8 * ice_pkg_get_supported_vlan_mode - chk if DDP supports Double VLAN mode (DVM)
   9 * @hw: pointer to the HW struct
  10 * @dvm: output variable to determine if DDP supports DVM(true) or SVM(false)
  11 */
  12static enum ice_status
  13ice_pkg_get_supported_vlan_mode(struct ice_hw *hw, bool *dvm)
  14{
  15        u16 meta_init_size = sizeof(struct ice_meta_init_section);
  16        struct ice_meta_init_section *sect;
  17        struct ice_buf_build *bld;
  18        enum ice_status status;
  19
  20        /* if anything fails, we assume there is no DVM support */
  21        *dvm = false;
  22
  23        bld = ice_pkg_buf_alloc_single_section(hw,
  24                                               ICE_SID_RXPARSER_METADATA_INIT,
  25                                               meta_init_size, (void **)&sect);
  26        if (!bld)
  27                return ICE_ERR_NO_MEMORY;
  28
  29        /* only need to read a single section */
  30        sect->count = CPU_TO_LE16(1);
  31        sect->offset = CPU_TO_LE16(ICE_META_VLAN_MODE_ENTRY);
  32
  33        status = ice_aq_upload_section(hw,
  34                                       (struct ice_buf_hdr *)ice_pkg_buf(bld),
  35                                       ICE_PKG_BUF_SIZE, NULL);
  36        if (!status) {
  37                ice_declare_bitmap(entry, ICE_META_INIT_BITS);
  38                u32 arr[ICE_META_INIT_DW_CNT];
  39                u16 i;
  40
  41                /* convert to host bitmap format */
  42                for (i = 0; i < ICE_META_INIT_DW_CNT; i++)
  43                        arr[i] = LE32_TO_CPU(sect->entry[0].bm[i]);
  44
  45                ice_bitmap_from_array32(entry, arr, (u16)ICE_META_INIT_BITS);
  46
  47                /* check if DVM is supported */
  48                *dvm = ice_is_bit_set(entry, ICE_META_VLAN_MODE_BIT);
  49        }
  50
  51        ice_pkg_buf_free(hw, bld);
  52
  53        return status;
  54}
  55
  56/**
  57 * ice_aq_get_vlan_mode - get the VLAN mode of the device
  58 * @hw: pointer to the HW structure
  59 * @get_params: structure FW fills in based on the current VLAN mode config
  60 *
  61 * Get VLAN Mode Parameters (0x020D)
  62 */
  63static enum ice_status
  64ice_aq_get_vlan_mode(struct ice_hw *hw,
  65                     struct ice_aqc_get_vlan_mode *get_params)
  66{
  67        struct ice_aq_desc desc;
  68
  69        if (!get_params)
  70                return ICE_ERR_PARAM;
  71
  72        ice_fill_dflt_direct_cmd_desc(&desc,
  73                                      ice_aqc_opc_get_vlan_mode_parameters);
  74
  75        return ice_aq_send_cmd(hw, &desc, get_params, sizeof(*get_params),
  76                               NULL);
  77}
  78
  79/**
  80 * ice_aq_is_dvm_ena - query FW to check if double VLAN mode is enabled
  81 * @hw: pointer to the HW structure
  82 *
  83 * Returns true if the hardware/firmware is configured in double VLAN mode,
  84 * else return false signaling that the hardware/firmware is configured in
  85 * single VLAN mode.
  86 *
  87 * Also, return false if this call fails for any reason (i.e. firmware doesn't
  88 * support this AQ call).
  89 */
  90static bool ice_aq_is_dvm_ena(struct ice_hw *hw)
  91{
  92        struct ice_aqc_get_vlan_mode get_params = { 0 };
  93        enum ice_status status;
  94
  95        status = ice_aq_get_vlan_mode(hw, &get_params);
  96        if (status) {
  97                ice_debug(hw, ICE_DBG_AQ, "Failed to get VLAN mode, status %d\n",
  98                          status);
  99                return false;
 100        }
 101
 102        return (get_params.vlan_mode & ICE_AQ_VLAN_MODE_DVM_ENA);
 103}
 104
 105/**
 106 * ice_is_dvm_ena - check if double VLAN mode is enabled
 107 * @hw: pointer to the HW structure
 108 *
 109 * The device is configured in single or double VLAN mode on initialization and
 110 * this cannot be dynamically changed during runtime. Based on this there is no
 111 * need to make an AQ call every time the driver needs to know the VLAN mode.
 112 * Instead, use the cached VLAN mode.
 113 */
 114bool ice_is_dvm_ena(struct ice_hw *hw)
 115{
 116        return hw->dvm_ena;
 117}
 118
 119/**
 120 * ice_cache_vlan_mode - cache VLAN mode after DDP is downloaded
 121 * @hw: pointer to the HW structure
 122 *
 123 * This is only called after downloading the DDP and after the global
 124 * configuration lock has been released because all ports on a device need to
 125 * cache the VLAN mode.
 126 */
 127static void ice_cache_vlan_mode(struct ice_hw *hw)
 128{
 129        hw->dvm_ena = ice_aq_is_dvm_ena(hw) ? true : false;
 130}
 131
 132/**
 133 * ice_pkg_supports_dvm - find out if DDP supports DVM
 134 * @hw: pointer to the HW structure
 135 */
 136static bool ice_pkg_supports_dvm(struct ice_hw *hw)
 137{
 138        enum ice_status status;
 139        bool pkg_supports_dvm;
 140
 141        status = ice_pkg_get_supported_vlan_mode(hw, &pkg_supports_dvm);
 142        if (status) {
 143                ice_debug(hw, ICE_DBG_PKG, "Failed to get supported VLAN mode, status %d\n",
 144                          status);
 145                return false;
 146        }
 147
 148        return pkg_supports_dvm;
 149}
 150
 151/**
 152 * ice_fw_supports_dvm - find out if FW supports DVM
 153 * @hw: pointer to the HW structure
 154 */
 155static bool ice_fw_supports_dvm(struct ice_hw *hw)
 156{
 157        struct ice_aqc_get_vlan_mode get_vlan_mode = { 0 };
 158        enum ice_status status;
 159
 160        /* If firmware returns success, then it supports DVM, else it only
 161         * supports SVM
 162         */
 163        status = ice_aq_get_vlan_mode(hw, &get_vlan_mode);
 164        if (status) {
 165                ice_debug(hw, ICE_DBG_NVM, "Failed to get VLAN mode, status %d\n",
 166                          status);
 167                return false;
 168        }
 169
 170        return true;
 171}
 172
 173/**
 174 * ice_is_dvm_supported - check if Double VLAN Mode is supported
 175 * @hw: pointer to the hardware structure
 176 *
 177 * Returns true if Double VLAN Mode (DVM) is supported and false if only Single
 178 * VLAN Mode (SVM) is supported. In order for DVM to be supported the DDP and
 179 * firmware must support it, otherwise only SVM is supported. This function
 180 * should only be called while the global config lock is held and after the
 181 * package has been successfully downloaded.
 182 */
 183static bool ice_is_dvm_supported(struct ice_hw *hw)
 184{
 185        if (!ice_pkg_supports_dvm(hw)) {
 186                ice_debug(hw, ICE_DBG_PKG, "DDP doesn't support DVM\n");
 187                return false;
 188        }
 189
 190        if (!ice_fw_supports_dvm(hw)) {
 191                ice_debug(hw, ICE_DBG_PKG, "FW doesn't support DVM\n");
 192                return false;
 193        }
 194
 195        return true;
 196}
 197
 198#define ICE_EXTERNAL_VLAN_ID_FV_IDX                     11
 199#define ICE_SW_LKUP_VLAN_LOC_LKUP_IDX                   1
 200#define ICE_SW_LKUP_VLAN_PKT_FLAGS_LKUP_IDX             2
 201#define ICE_SW_LKUP_PROMISC_VLAN_LOC_LKUP_IDX           2
 202#define ICE_PKT_FLAGS_0_TO_15_FV_IDX                    1
 203#define ICE_PKT_FLAGS_0_TO_15_VLAN_FLAGS_MASK           0xD000
 204static struct ice_update_recipe_lkup_idx_params ice_dvm_dflt_recipes[] = {
 205        {
 206                /* Update recipe ICE_SW_LKUP_VLAN to filter based on the
 207                 * outer/single VLAN in DVM
 208                 */
 209                .rid = ICE_SW_LKUP_VLAN,
 210                .fv_idx = ICE_EXTERNAL_VLAN_ID_FV_IDX,
 211                .ignore_valid = true,
 212                .mask = 0,
 213                .mask_valid = false, /* use pre-existing mask */
 214                .lkup_idx = ICE_SW_LKUP_VLAN_LOC_LKUP_IDX,
 215        },
 216        {
 217                /* Update recipe ICE_SW_LKUP_VLAN to filter based on the VLAN
 218                 * packet flags to support VLAN filtering on multiple VLAN
 219                 * ethertypes (i.e. 0x8100 and 0x88a8) in DVM
 220                 */
 221                .rid = ICE_SW_LKUP_VLAN,
 222                .fv_idx = ICE_PKT_FLAGS_0_TO_15_FV_IDX,
 223                .ignore_valid = false,
 224                .mask = ICE_PKT_FLAGS_0_TO_15_VLAN_FLAGS_MASK,
 225                .mask_valid = true,
 226                .lkup_idx = ICE_SW_LKUP_VLAN_PKT_FLAGS_LKUP_IDX,
 227        },
 228        {
 229                /* Update recipe ICE_SW_LKUP_PROMISC_VLAN to filter based on the
 230                 * outer/single VLAN in DVM
 231                 */
 232                .rid = ICE_SW_LKUP_PROMISC_VLAN,
 233                .fv_idx = ICE_EXTERNAL_VLAN_ID_FV_IDX,
 234                .ignore_valid = true,
 235                .mask = 0,
 236                .mask_valid = false,  /* use pre-existing mask */
 237                .lkup_idx = ICE_SW_LKUP_PROMISC_VLAN_LOC_LKUP_IDX,
 238        },
 239};
 240
 241/**
 242 * ice_dvm_update_dflt_recipes - update default switch recipes in DVM
 243 * @hw: hardware structure used to update the recipes
 244 */
 245static enum ice_status ice_dvm_update_dflt_recipes(struct ice_hw *hw)
 246{
 247        unsigned long i;
 248
 249        for (i = 0; i < ARRAY_SIZE(ice_dvm_dflt_recipes); i++) {
 250                struct ice_update_recipe_lkup_idx_params *params;
 251                enum ice_status status;
 252
 253                params = &ice_dvm_dflt_recipes[i];
 254
 255                status = ice_update_recipe_lkup_idx(hw, params);
 256                if (status) {
 257                        ice_debug(hw, ICE_DBG_INIT, "Failed to update RID %d lkup_idx %d fv_idx %d mask_valid %s mask 0x%04x\n",
 258                                  params->rid, params->lkup_idx, params->fv_idx,
 259                                  params->mask_valid ? "true" : "false",
 260                                  params->mask);
 261                        return status;
 262                }
 263        }
 264
 265        return ICE_SUCCESS;
 266}
 267
 268/**
 269 * ice_aq_set_vlan_mode - set the VLAN mode of the device
 270 * @hw: pointer to the HW structure
 271 * @set_params: requested VLAN mode configuration
 272 *
 273 * Set VLAN Mode Parameters (0x020C)
 274 */
 275static enum ice_status
 276ice_aq_set_vlan_mode(struct ice_hw *hw,
 277                     struct ice_aqc_set_vlan_mode *set_params)
 278{
 279        u8 rdma_packet, mng_vlan_prot_id;
 280        struct ice_aq_desc desc;
 281
 282        if (!set_params)
 283                return ICE_ERR_PARAM;
 284
 285        if (set_params->l2tag_prio_tagging > ICE_AQ_VLAN_PRIO_TAG_MAX)
 286                return ICE_ERR_PARAM;
 287
 288        rdma_packet = set_params->rdma_packet;
 289        if (rdma_packet != ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING &&
 290            rdma_packet != ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING)
 291                return ICE_ERR_PARAM;
 292
 293        mng_vlan_prot_id = set_params->mng_vlan_prot_id;
 294        if (mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER &&
 295            mng_vlan_prot_id != ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER)
 296                return ICE_ERR_PARAM;
 297
 298        ice_fill_dflt_direct_cmd_desc(&desc,
 299                                      ice_aqc_opc_set_vlan_mode_parameters);
 300        desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
 301
 302        return ice_aq_send_cmd(hw, &desc, set_params, sizeof(*set_params),
 303                               NULL);
 304}
 305
 306/**
 307 * ice_set_dvm - sets up software and hardware for double VLAN mode
 308 * @hw: pointer to the hardware structure
 309 */
 310static enum ice_status ice_set_dvm(struct ice_hw *hw)
 311{
 312        struct ice_aqc_set_vlan_mode params = { 0 };
 313        enum ice_status status;
 314
 315        params.l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_OUTER_CTAG;
 316        params.rdma_packet = ICE_AQ_DVM_VLAN_RDMA_PKT_FLAG_SETTING;
 317        params.mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_OUTER;
 318
 319        status = ice_aq_set_vlan_mode(hw, &params);
 320        if (status) {
 321                ice_debug(hw, ICE_DBG_INIT, "Failed to set double VLAN mode parameters, status %d\n",
 322                          status);
 323                return status;
 324        }
 325
 326        status = ice_dvm_update_dflt_recipes(hw);
 327        if (status) {
 328                ice_debug(hw, ICE_DBG_INIT, "Failed to update default recipes for double VLAN mode, status %d\n",
 329                          status);
 330                return status;
 331        }
 332
 333        status = ice_aq_set_port_params(hw->port_info, 0, false, false, true,
 334                                        NULL);
 335        if (status) {
 336                ice_debug(hw, ICE_DBG_INIT, "Failed to set port in double VLAN mode, status %d\n",
 337                          status);
 338                return status;
 339        }
 340
 341        status = ice_set_dvm_boost_entries(hw);
 342        if (status) {
 343                ice_debug(hw, ICE_DBG_INIT, "Failed to set boost TCAM entries for double VLAN mode, status %d\n",
 344                          status);
 345                return status;
 346        }
 347
 348        return ICE_SUCCESS;
 349}
 350
 351/**
 352 * ice_set_svm - set single VLAN mode
 353 * @hw: pointer to the HW structure
 354 */
 355static enum ice_status ice_set_svm(struct ice_hw *hw)
 356{
 357        struct ice_aqc_set_vlan_mode *set_params;
 358        enum ice_status status;
 359
 360        status = ice_aq_set_port_params(hw->port_info, 0, false, false, false, NULL);
 361        if (status) {
 362                ice_debug(hw, ICE_DBG_INIT, "Failed to set port parameters for single VLAN mode\n");
 363                return status;
 364        }
 365
 366        set_params = (struct ice_aqc_set_vlan_mode *)
 367                ice_malloc(hw, sizeof(*set_params));
 368        if (!set_params)
 369                return ICE_ERR_NO_MEMORY;
 370
 371        /* default configuration for SVM configurations */
 372        set_params->l2tag_prio_tagging = ICE_AQ_VLAN_PRIO_TAG_INNER_CTAG;
 373        set_params->rdma_packet = ICE_AQ_SVM_VLAN_RDMA_PKT_FLAG_SETTING;
 374        set_params->mng_vlan_prot_id = ICE_AQ_VLAN_MNG_PROTOCOL_ID_INNER;
 375
 376        status = ice_aq_set_vlan_mode(hw, set_params);
 377        if (status)
 378                ice_debug(hw, ICE_DBG_INIT, "Failed to configure port in single VLAN mode\n");
 379
 380        ice_free(hw, set_params);
 381        return status;
 382}
 383
 384/**
 385 * ice_set_vlan_mode
 386 * @hw: pointer to the HW structure
 387 */
 388enum ice_status ice_set_vlan_mode(struct ice_hw *hw)
 389{
 390        /* DCF only has the ability to query the VLAN mode. Setting the VLAN
 391         * mode is done by the PF.
 392         */
 393        if (hw->dcf_enabled)
 394                return ICE_SUCCESS;
 395
 396        if (!ice_is_dvm_supported(hw))
 397                return ICE_SUCCESS;
 398
 399        if (!ice_set_dvm(hw))
 400                return ICE_SUCCESS;
 401
 402        return ice_set_svm(hw);
 403}
 404
 405/**
 406 * ice_print_dvm_not_supported - print if DDP and/or FW doesn't support DVM
 407 * @hw: pointer to the HW structure
 408 *
 409 * The purpose of this function is to print that  QinQ is not supported due to
 410 * incompatibilty from the DDP and/or FW. This will give a hint to the user to
 411 * update one and/or both components if they expect QinQ functionality.
 412 */
 413static void ice_print_dvm_not_supported(struct ice_hw *hw)
 414{
 415        bool pkg_supports_dvm = ice_pkg_supports_dvm(hw);
 416        bool fw_supports_dvm = ice_fw_supports_dvm(hw);
 417
 418        if (!fw_supports_dvm && !pkg_supports_dvm)
 419                ice_info(hw, "QinQ functionality cannot be enabled on this device. "
 420                             "Update your DDP package and NVM to versions that support QinQ.\n");
 421        else if (!pkg_supports_dvm)
 422                ice_info(hw, "QinQ functionality cannot be enabled on this device. "
 423                             "Update your DDP package to a version that supports QinQ.\n");
 424        else if (!fw_supports_dvm)
 425                ice_info(hw, "QinQ functionality cannot be enabled on this device. "
 426                             "Update your NVM to a version that supports QinQ.\n");
 427}
 428
 429/**
 430 * ice_post_pkg_dwnld_vlan_mode_cfg - configure VLAN mode after DDP download
 431 * @hw: pointer to the HW structure
 432 *
 433 * This function is meant to configure any VLAN mode specific functionality
 434 * after the global configuration lock has been released and the DDP has been
 435 * downloaded.
 436 *
 437 * Since only one PF downloads the DDP and configures the VLAN mode there needs
 438 * to be a way to configure the other PFs after the DDP has been downloaded and
 439 * the global configuration lock has been released. All such code should go in
 440 * this function.
 441 */
 442void ice_post_pkg_dwnld_vlan_mode_cfg(struct ice_hw *hw)
 443{
 444        ice_cache_vlan_mode(hw);
 445
 446        if (ice_is_dvm_ena(hw))
 447                ice_change_proto_id_to_dvm();
 448        else
 449                ice_print_dvm_not_supported(hw);
 450}
 451