cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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 **)&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 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, &params);
    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}