162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) 2018, Intel Corporation. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include "ice.h"
562306a36Sopenharmony_ci#include "ice_vf_lib_private.h"
662306a36Sopenharmony_ci#include "ice_base.h"
762306a36Sopenharmony_ci#include "ice_lib.h"
862306a36Sopenharmony_ci#include "ice_fltr.h"
962306a36Sopenharmony_ci#include "ice_dcb_lib.h"
1062306a36Sopenharmony_ci#include "ice_flow.h"
1162306a36Sopenharmony_ci#include "ice_eswitch.h"
1262306a36Sopenharmony_ci#include "ice_virtchnl_allowlist.h"
1362306a36Sopenharmony_ci#include "ice_flex_pipe.h"
1462306a36Sopenharmony_ci#include "ice_vf_vsi_vlan_ops.h"
1562306a36Sopenharmony_ci#include "ice_vlan.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/**
1862306a36Sopenharmony_ci * ice_free_vf_entries - Free all VF entries from the hash table
1962306a36Sopenharmony_ci * @pf: pointer to the PF structure
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * Iterate over the VF hash table, removing and releasing all VF entries.
2262306a36Sopenharmony_ci * Called during VF teardown or as cleanup during failed VF initialization.
2362306a36Sopenharmony_ci */
2462306a36Sopenharmony_cistatic void ice_free_vf_entries(struct ice_pf *pf)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	struct ice_vfs *vfs = &pf->vfs;
2762306a36Sopenharmony_ci	struct hlist_node *tmp;
2862306a36Sopenharmony_ci	struct ice_vf *vf;
2962306a36Sopenharmony_ci	unsigned int bkt;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	/* Remove all VFs from the hash table and release their main
3262306a36Sopenharmony_ci	 * reference. Once all references to the VF are dropped, ice_put_vf()
3362306a36Sopenharmony_ci	 * will call ice_release_vf which will remove the VF memory.
3462306a36Sopenharmony_ci	 */
3562306a36Sopenharmony_ci	lockdep_assert_held(&vfs->table_lock);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	hash_for_each_safe(vfs->table, bkt, tmp, vf, entry) {
3862306a36Sopenharmony_ci		hash_del_rcu(&vf->entry);
3962306a36Sopenharmony_ci		ice_put_vf(vf);
4062306a36Sopenharmony_ci	}
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/**
4462306a36Sopenharmony_ci * ice_free_vf_res - Free a VF's resources
4562306a36Sopenharmony_ci * @vf: pointer to the VF info
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_cistatic void ice_free_vf_res(struct ice_vf *vf)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct ice_pf *pf = vf->pf;
5062306a36Sopenharmony_ci	int i, last_vector_idx;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	/* First, disable VF's configuration API to prevent OS from
5362306a36Sopenharmony_ci	 * accessing the VF's VSI after it's freed or invalidated.
5462306a36Sopenharmony_ci	 */
5562306a36Sopenharmony_ci	clear_bit(ICE_VF_STATE_INIT, vf->vf_states);
5662306a36Sopenharmony_ci	ice_vf_fdir_exit(vf);
5762306a36Sopenharmony_ci	/* free VF control VSI */
5862306a36Sopenharmony_ci	if (vf->ctrl_vsi_idx != ICE_NO_VSI)
5962306a36Sopenharmony_ci		ice_vf_ctrl_vsi_release(vf);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	/* free VSI and disconnect it from the parent uplink */
6262306a36Sopenharmony_ci	if (vf->lan_vsi_idx != ICE_NO_VSI) {
6362306a36Sopenharmony_ci		ice_vf_vsi_release(vf);
6462306a36Sopenharmony_ci		vf->num_mac = 0;
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	last_vector_idx = vf->first_vector_idx + pf->vfs.num_msix_per - 1;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* clear VF MDD event information */
7062306a36Sopenharmony_ci	memset(&vf->mdd_tx_events, 0, sizeof(vf->mdd_tx_events));
7162306a36Sopenharmony_ci	memset(&vf->mdd_rx_events, 0, sizeof(vf->mdd_rx_events));
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	/* Disable interrupts so that VF starts in a known state */
7462306a36Sopenharmony_ci	for (i = vf->first_vector_idx; i <= last_vector_idx; i++) {
7562306a36Sopenharmony_ci		wr32(&pf->hw, GLINT_DYN_CTL(i), GLINT_DYN_CTL_CLEARPBA_M);
7662306a36Sopenharmony_ci		ice_flush(&pf->hw);
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci	/* reset some of the state variables keeping track of the resources */
7962306a36Sopenharmony_ci	clear_bit(ICE_VF_STATE_MC_PROMISC, vf->vf_states);
8062306a36Sopenharmony_ci	clear_bit(ICE_VF_STATE_UC_PROMISC, vf->vf_states);
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/**
8462306a36Sopenharmony_ci * ice_dis_vf_mappings
8562306a36Sopenharmony_ci * @vf: pointer to the VF structure
8662306a36Sopenharmony_ci */
8762306a36Sopenharmony_cistatic void ice_dis_vf_mappings(struct ice_vf *vf)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	struct ice_pf *pf = vf->pf;
9062306a36Sopenharmony_ci	struct ice_vsi *vsi;
9162306a36Sopenharmony_ci	struct device *dev;
9262306a36Sopenharmony_ci	int first, last, v;
9362306a36Sopenharmony_ci	struct ice_hw *hw;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	hw = &pf->hw;
9662306a36Sopenharmony_ci	vsi = ice_get_vf_vsi(vf);
9762306a36Sopenharmony_ci	if (WARN_ON(!vsi))
9862306a36Sopenharmony_ci		return;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
10162306a36Sopenharmony_ci	wr32(hw, VPINT_ALLOC(vf->vf_id), 0);
10262306a36Sopenharmony_ci	wr32(hw, VPINT_ALLOC_PCI(vf->vf_id), 0);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	first = vf->first_vector_idx;
10562306a36Sopenharmony_ci	last = first + pf->vfs.num_msix_per - 1;
10662306a36Sopenharmony_ci	for (v = first; v <= last; v++) {
10762306a36Sopenharmony_ci		u32 reg;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		reg = (((1 << GLINT_VECT2FUNC_IS_PF_S) &
11062306a36Sopenharmony_ci			GLINT_VECT2FUNC_IS_PF_M) |
11162306a36Sopenharmony_ci		       ((hw->pf_id << GLINT_VECT2FUNC_PF_NUM_S) &
11262306a36Sopenharmony_ci			GLINT_VECT2FUNC_PF_NUM_M));
11362306a36Sopenharmony_ci		wr32(hw, GLINT_VECT2FUNC(v), reg);
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (vsi->tx_mapping_mode == ICE_VSI_MAP_CONTIG)
11762306a36Sopenharmony_ci		wr32(hw, VPLAN_TX_QBASE(vf->vf_id), 0);
11862306a36Sopenharmony_ci	else
11962306a36Sopenharmony_ci		dev_err(dev, "Scattered mode for VF Tx queues is not yet implemented\n");
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (vsi->rx_mapping_mode == ICE_VSI_MAP_CONTIG)
12262306a36Sopenharmony_ci		wr32(hw, VPLAN_RX_QBASE(vf->vf_id), 0);
12362306a36Sopenharmony_ci	else
12462306a36Sopenharmony_ci		dev_err(dev, "Scattered mode for VF Rx queues is not yet implemented\n");
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci/**
12862306a36Sopenharmony_ci * ice_sriov_free_msix_res - Reset/free any used MSIX resources
12962306a36Sopenharmony_ci * @pf: pointer to the PF structure
13062306a36Sopenharmony_ci *
13162306a36Sopenharmony_ci * Since no MSIX entries are taken from the pf->irq_tracker then just clear
13262306a36Sopenharmony_ci * the pf->sriov_base_vector.
13362306a36Sopenharmony_ci *
13462306a36Sopenharmony_ci * Returns 0 on success, and -EINVAL on error.
13562306a36Sopenharmony_ci */
13662306a36Sopenharmony_cistatic int ice_sriov_free_msix_res(struct ice_pf *pf)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	if (!pf)
13962306a36Sopenharmony_ci		return -EINVAL;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	pf->sriov_base_vector = 0;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	return 0;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/**
14762306a36Sopenharmony_ci * ice_free_vfs - Free all VFs
14862306a36Sopenharmony_ci * @pf: pointer to the PF structure
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_civoid ice_free_vfs(struct ice_pf *pf)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
15362306a36Sopenharmony_ci	struct ice_vfs *vfs = &pf->vfs;
15462306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
15562306a36Sopenharmony_ci	struct ice_vf *vf;
15662306a36Sopenharmony_ci	unsigned int bkt;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	if (!ice_has_vfs(pf))
15962306a36Sopenharmony_ci		return;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	while (test_and_set_bit(ICE_VF_DIS, pf->state))
16262306a36Sopenharmony_ci		usleep_range(1000, 2000);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	/* Disable IOV before freeing resources. This lets any VF drivers
16562306a36Sopenharmony_ci	 * running in the host get themselves cleaned up before we yank
16662306a36Sopenharmony_ci	 * the carpet out from underneath their feet.
16762306a36Sopenharmony_ci	 */
16862306a36Sopenharmony_ci	if (!pci_vfs_assigned(pf->pdev))
16962306a36Sopenharmony_ci		pci_disable_sriov(pf->pdev);
17062306a36Sopenharmony_ci	else
17162306a36Sopenharmony_ci		dev_warn(dev, "VFs are assigned - not disabling SR-IOV\n");
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	mutex_lock(&vfs->table_lock);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	ice_eswitch_release(pf);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	ice_for_each_vf(pf, bkt, vf) {
17862306a36Sopenharmony_ci		mutex_lock(&vf->cfg_lock);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci		ice_dis_vf_qs(vf);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci		if (test_bit(ICE_VF_STATE_INIT, vf->vf_states)) {
18362306a36Sopenharmony_ci			/* disable VF qp mappings and set VF disable state */
18462306a36Sopenharmony_ci			ice_dis_vf_mappings(vf);
18562306a36Sopenharmony_ci			set_bit(ICE_VF_STATE_DIS, vf->vf_states);
18662306a36Sopenharmony_ci			ice_free_vf_res(vf);
18762306a36Sopenharmony_ci		}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci		if (!pci_vfs_assigned(pf->pdev)) {
19062306a36Sopenharmony_ci			u32 reg_idx, bit_idx;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci			reg_idx = (hw->func_caps.vf_base_id + vf->vf_id) / 32;
19362306a36Sopenharmony_ci			bit_idx = (hw->func_caps.vf_base_id + vf->vf_id) % 32;
19462306a36Sopenharmony_ci			wr32(hw, GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx));
19562306a36Sopenharmony_ci		}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci		/* clear malicious info since the VF is getting released */
19862306a36Sopenharmony_ci		list_del(&vf->mbx_info.list_entry);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci		mutex_unlock(&vf->cfg_lock);
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (ice_sriov_free_msix_res(pf))
20462306a36Sopenharmony_ci		dev_err(dev, "Failed to free MSIX resources used by SR-IOV\n");
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	vfs->num_qps_per = 0;
20762306a36Sopenharmony_ci	ice_free_vf_entries(pf);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	mutex_unlock(&vfs->table_lock);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	clear_bit(ICE_VF_DIS, pf->state);
21262306a36Sopenharmony_ci	clear_bit(ICE_FLAG_SRIOV_ENA, pf->flags);
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci/**
21662306a36Sopenharmony_ci * ice_vf_vsi_setup - Set up a VF VSI
21762306a36Sopenharmony_ci * @vf: VF to setup VSI for
21862306a36Sopenharmony_ci *
21962306a36Sopenharmony_ci * Returns pointer to the successfully allocated VSI struct on success,
22062306a36Sopenharmony_ci * otherwise returns NULL on failure.
22162306a36Sopenharmony_ci */
22262306a36Sopenharmony_cistatic struct ice_vsi *ice_vf_vsi_setup(struct ice_vf *vf)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	struct ice_vsi_cfg_params params = {};
22562306a36Sopenharmony_ci	struct ice_pf *pf = vf->pf;
22662306a36Sopenharmony_ci	struct ice_vsi *vsi;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	params.type = ICE_VSI_VF;
22962306a36Sopenharmony_ci	params.pi = ice_vf_get_port_info(vf);
23062306a36Sopenharmony_ci	params.vf = vf;
23162306a36Sopenharmony_ci	params.flags = ICE_VSI_FLAG_INIT;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	vsi = ice_vsi_setup(pf, &params);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	if (!vsi) {
23662306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "Failed to create VF VSI\n");
23762306a36Sopenharmony_ci		ice_vf_invalidate_vsi(vf);
23862306a36Sopenharmony_ci		return NULL;
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	vf->lan_vsi_idx = vsi->idx;
24262306a36Sopenharmony_ci	vf->lan_vsi_num = vsi->vsi_num;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	return vsi;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci/**
24862306a36Sopenharmony_ci * ice_calc_vf_first_vector_idx - Calculate MSIX vector index in the PF space
24962306a36Sopenharmony_ci * @pf: pointer to PF structure
25062306a36Sopenharmony_ci * @vf: pointer to VF that the first MSIX vector index is being calculated for
25162306a36Sopenharmony_ci *
25262306a36Sopenharmony_ci * This returns the first MSIX vector index in PF space that is used by this VF.
25362306a36Sopenharmony_ci * This index is used when accessing PF relative registers such as
25462306a36Sopenharmony_ci * GLINT_VECT2FUNC and GLINT_DYN_CTL.
25562306a36Sopenharmony_ci * This will always be the OICR index in the AVF driver so any functionality
25662306a36Sopenharmony_ci * using vf->first_vector_idx for queue configuration will have to increment by
25762306a36Sopenharmony_ci * 1 to avoid meddling with the OICR index.
25862306a36Sopenharmony_ci */
25962306a36Sopenharmony_cistatic int ice_calc_vf_first_vector_idx(struct ice_pf *pf, struct ice_vf *vf)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	return pf->sriov_base_vector + vf->vf_id * pf->vfs.num_msix_per;
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci/**
26562306a36Sopenharmony_ci * ice_ena_vf_msix_mappings - enable VF MSIX mappings in hardware
26662306a36Sopenharmony_ci * @vf: VF to enable MSIX mappings for
26762306a36Sopenharmony_ci *
26862306a36Sopenharmony_ci * Some of the registers need to be indexed/configured using hardware global
26962306a36Sopenharmony_ci * device values and other registers need 0-based values, which represent PF
27062306a36Sopenharmony_ci * based values.
27162306a36Sopenharmony_ci */
27262306a36Sopenharmony_cistatic void ice_ena_vf_msix_mappings(struct ice_vf *vf)
27362306a36Sopenharmony_ci{
27462306a36Sopenharmony_ci	int device_based_first_msix, device_based_last_msix;
27562306a36Sopenharmony_ci	int pf_based_first_msix, pf_based_last_msix, v;
27662306a36Sopenharmony_ci	struct ice_pf *pf = vf->pf;
27762306a36Sopenharmony_ci	int device_based_vf_id;
27862306a36Sopenharmony_ci	struct ice_hw *hw;
27962306a36Sopenharmony_ci	u32 reg;
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	hw = &pf->hw;
28262306a36Sopenharmony_ci	pf_based_first_msix = vf->first_vector_idx;
28362306a36Sopenharmony_ci	pf_based_last_msix = (pf_based_first_msix + pf->vfs.num_msix_per) - 1;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	device_based_first_msix = pf_based_first_msix +
28662306a36Sopenharmony_ci		pf->hw.func_caps.common_cap.msix_vector_first_id;
28762306a36Sopenharmony_ci	device_based_last_msix =
28862306a36Sopenharmony_ci		(device_based_first_msix + pf->vfs.num_msix_per) - 1;
28962306a36Sopenharmony_ci	device_based_vf_id = vf->vf_id + hw->func_caps.vf_base_id;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	reg = (((device_based_first_msix << VPINT_ALLOC_FIRST_S) &
29262306a36Sopenharmony_ci		VPINT_ALLOC_FIRST_M) |
29362306a36Sopenharmony_ci	       ((device_based_last_msix << VPINT_ALLOC_LAST_S) &
29462306a36Sopenharmony_ci		VPINT_ALLOC_LAST_M) | VPINT_ALLOC_VALID_M);
29562306a36Sopenharmony_ci	wr32(hw, VPINT_ALLOC(vf->vf_id), reg);
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	reg = (((device_based_first_msix << VPINT_ALLOC_PCI_FIRST_S)
29862306a36Sopenharmony_ci		 & VPINT_ALLOC_PCI_FIRST_M) |
29962306a36Sopenharmony_ci	       ((device_based_last_msix << VPINT_ALLOC_PCI_LAST_S) &
30062306a36Sopenharmony_ci		VPINT_ALLOC_PCI_LAST_M) | VPINT_ALLOC_PCI_VALID_M);
30162306a36Sopenharmony_ci	wr32(hw, VPINT_ALLOC_PCI(vf->vf_id), reg);
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	/* map the interrupts to its functions */
30462306a36Sopenharmony_ci	for (v = pf_based_first_msix; v <= pf_based_last_msix; v++) {
30562306a36Sopenharmony_ci		reg = (((device_based_vf_id << GLINT_VECT2FUNC_VF_NUM_S) &
30662306a36Sopenharmony_ci			GLINT_VECT2FUNC_VF_NUM_M) |
30762306a36Sopenharmony_ci		       ((hw->pf_id << GLINT_VECT2FUNC_PF_NUM_S) &
30862306a36Sopenharmony_ci			GLINT_VECT2FUNC_PF_NUM_M));
30962306a36Sopenharmony_ci		wr32(hw, GLINT_VECT2FUNC(v), reg);
31062306a36Sopenharmony_ci	}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	/* Map mailbox interrupt to VF MSI-X vector 0 */
31362306a36Sopenharmony_ci	wr32(hw, VPINT_MBX_CTL(device_based_vf_id), VPINT_MBX_CTL_CAUSE_ENA_M);
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci/**
31762306a36Sopenharmony_ci * ice_ena_vf_q_mappings - enable Rx/Tx queue mappings for a VF
31862306a36Sopenharmony_ci * @vf: VF to enable the mappings for
31962306a36Sopenharmony_ci * @max_txq: max Tx queues allowed on the VF's VSI
32062306a36Sopenharmony_ci * @max_rxq: max Rx queues allowed on the VF's VSI
32162306a36Sopenharmony_ci */
32262306a36Sopenharmony_cistatic void ice_ena_vf_q_mappings(struct ice_vf *vf, u16 max_txq, u16 max_rxq)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(vf->pf);
32562306a36Sopenharmony_ci	struct ice_vsi *vsi = ice_get_vf_vsi(vf);
32662306a36Sopenharmony_ci	struct ice_hw *hw = &vf->pf->hw;
32762306a36Sopenharmony_ci	u32 reg;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	if (WARN_ON(!vsi))
33062306a36Sopenharmony_ci		return;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	/* set regardless of mapping mode */
33362306a36Sopenharmony_ci	wr32(hw, VPLAN_TXQ_MAPENA(vf->vf_id), VPLAN_TXQ_MAPENA_TX_ENA_M);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/* VF Tx queues allocation */
33662306a36Sopenharmony_ci	if (vsi->tx_mapping_mode == ICE_VSI_MAP_CONTIG) {
33762306a36Sopenharmony_ci		/* set the VF PF Tx queue range
33862306a36Sopenharmony_ci		 * VFNUMQ value should be set to (number of queues - 1). A value
33962306a36Sopenharmony_ci		 * of 0 means 1 queue and a value of 255 means 256 queues
34062306a36Sopenharmony_ci		 */
34162306a36Sopenharmony_ci		reg = (((vsi->txq_map[0] << VPLAN_TX_QBASE_VFFIRSTQ_S) &
34262306a36Sopenharmony_ci			VPLAN_TX_QBASE_VFFIRSTQ_M) |
34362306a36Sopenharmony_ci		       (((max_txq - 1) << VPLAN_TX_QBASE_VFNUMQ_S) &
34462306a36Sopenharmony_ci			VPLAN_TX_QBASE_VFNUMQ_M));
34562306a36Sopenharmony_ci		wr32(hw, VPLAN_TX_QBASE(vf->vf_id), reg);
34662306a36Sopenharmony_ci	} else {
34762306a36Sopenharmony_ci		dev_err(dev, "Scattered mode for VF Tx queues is not yet implemented\n");
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	/* set regardless of mapping mode */
35162306a36Sopenharmony_ci	wr32(hw, VPLAN_RXQ_MAPENA(vf->vf_id), VPLAN_RXQ_MAPENA_RX_ENA_M);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* VF Rx queues allocation */
35462306a36Sopenharmony_ci	if (vsi->rx_mapping_mode == ICE_VSI_MAP_CONTIG) {
35562306a36Sopenharmony_ci		/* set the VF PF Rx queue range
35662306a36Sopenharmony_ci		 * VFNUMQ value should be set to (number of queues - 1). A value
35762306a36Sopenharmony_ci		 * of 0 means 1 queue and a value of 255 means 256 queues
35862306a36Sopenharmony_ci		 */
35962306a36Sopenharmony_ci		reg = (((vsi->rxq_map[0] << VPLAN_RX_QBASE_VFFIRSTQ_S) &
36062306a36Sopenharmony_ci			VPLAN_RX_QBASE_VFFIRSTQ_M) |
36162306a36Sopenharmony_ci		       (((max_rxq - 1) << VPLAN_RX_QBASE_VFNUMQ_S) &
36262306a36Sopenharmony_ci			VPLAN_RX_QBASE_VFNUMQ_M));
36362306a36Sopenharmony_ci		wr32(hw, VPLAN_RX_QBASE(vf->vf_id), reg);
36462306a36Sopenharmony_ci	} else {
36562306a36Sopenharmony_ci		dev_err(dev, "Scattered mode for VF Rx queues is not yet implemented\n");
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci/**
37062306a36Sopenharmony_ci * ice_ena_vf_mappings - enable VF MSIX and queue mapping
37162306a36Sopenharmony_ci * @vf: pointer to the VF structure
37262306a36Sopenharmony_ci */
37362306a36Sopenharmony_cistatic void ice_ena_vf_mappings(struct ice_vf *vf)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	struct ice_vsi *vsi = ice_get_vf_vsi(vf);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if (WARN_ON(!vsi))
37862306a36Sopenharmony_ci		return;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	ice_ena_vf_msix_mappings(vf);
38162306a36Sopenharmony_ci	ice_ena_vf_q_mappings(vf, vsi->alloc_txq, vsi->alloc_rxq);
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci/**
38562306a36Sopenharmony_ci * ice_calc_vf_reg_idx - Calculate the VF's register index in the PF space
38662306a36Sopenharmony_ci * @vf: VF to calculate the register index for
38762306a36Sopenharmony_ci * @q_vector: a q_vector associated to the VF
38862306a36Sopenharmony_ci */
38962306a36Sopenharmony_ciint ice_calc_vf_reg_idx(struct ice_vf *vf, struct ice_q_vector *q_vector)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	struct ice_pf *pf;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	if (!vf || !q_vector)
39462306a36Sopenharmony_ci		return -EINVAL;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	pf = vf->pf;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* always add one to account for the OICR being the first MSIX */
39962306a36Sopenharmony_ci	return pf->sriov_base_vector + pf->vfs.num_msix_per * vf->vf_id +
40062306a36Sopenharmony_ci		q_vector->v_idx + 1;
40162306a36Sopenharmony_ci}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci/**
40462306a36Sopenharmony_ci * ice_sriov_set_msix_res - Set any used MSIX resources
40562306a36Sopenharmony_ci * @pf: pointer to PF structure
40662306a36Sopenharmony_ci * @num_msix_needed: number of MSIX vectors needed for all SR-IOV VFs
40762306a36Sopenharmony_ci *
40862306a36Sopenharmony_ci * This function allows SR-IOV resources to be taken from the end of the PF's
40962306a36Sopenharmony_ci * allowed HW MSIX vectors so that the irq_tracker will not be affected. We
41062306a36Sopenharmony_ci * just set the pf->sriov_base_vector and return success.
41162306a36Sopenharmony_ci *
41262306a36Sopenharmony_ci * If there are not enough resources available, return an error. This should
41362306a36Sopenharmony_ci * always be caught by ice_set_per_vf_res().
41462306a36Sopenharmony_ci *
41562306a36Sopenharmony_ci * Return 0 on success, and -EINVAL when there are not enough MSIX vectors
41662306a36Sopenharmony_ci * in the PF's space available for SR-IOV.
41762306a36Sopenharmony_ci */
41862306a36Sopenharmony_cistatic int ice_sriov_set_msix_res(struct ice_pf *pf, u16 num_msix_needed)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	u16 total_vectors = pf->hw.func_caps.common_cap.num_msix_vectors;
42162306a36Sopenharmony_ci	int vectors_used = ice_get_max_used_msix_vector(pf);
42262306a36Sopenharmony_ci	int sriov_base_vector;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	sriov_base_vector = total_vectors - num_msix_needed;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	/* make sure we only grab irq_tracker entries from the list end and
42762306a36Sopenharmony_ci	 * that we have enough available MSIX vectors
42862306a36Sopenharmony_ci	 */
42962306a36Sopenharmony_ci	if (sriov_base_vector < vectors_used)
43062306a36Sopenharmony_ci		return -EINVAL;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	pf->sriov_base_vector = sriov_base_vector;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	return 0;
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci/**
43862306a36Sopenharmony_ci * ice_set_per_vf_res - check if vectors and queues are available
43962306a36Sopenharmony_ci * @pf: pointer to the PF structure
44062306a36Sopenharmony_ci * @num_vfs: the number of SR-IOV VFs being configured
44162306a36Sopenharmony_ci *
44262306a36Sopenharmony_ci * First, determine HW interrupts from common pool. If we allocate fewer VFs, we
44362306a36Sopenharmony_ci * get more vectors and can enable more queues per VF. Note that this does not
44462306a36Sopenharmony_ci * grab any vectors from the SW pool already allocated. Also note, that all
44562306a36Sopenharmony_ci * vector counts include one for each VF's miscellaneous interrupt vector
44662306a36Sopenharmony_ci * (i.e. OICR).
44762306a36Sopenharmony_ci *
44862306a36Sopenharmony_ci * Minimum VFs - 2 vectors, 1 queue pair
44962306a36Sopenharmony_ci * Small VFs - 5 vectors, 4 queue pairs
45062306a36Sopenharmony_ci * Medium VFs - 17 vectors, 16 queue pairs
45162306a36Sopenharmony_ci *
45262306a36Sopenharmony_ci * Second, determine number of queue pairs per VF by starting with a pre-defined
45362306a36Sopenharmony_ci * maximum each VF supports. If this is not possible, then we adjust based on
45462306a36Sopenharmony_ci * queue pairs available on the device.
45562306a36Sopenharmony_ci *
45662306a36Sopenharmony_ci * Lastly, set queue and MSI-X VF variables tracked by the PF so it can be used
45762306a36Sopenharmony_ci * by each VF during VF initialization and reset.
45862306a36Sopenharmony_ci */
45962306a36Sopenharmony_cistatic int ice_set_per_vf_res(struct ice_pf *pf, u16 num_vfs)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	int vectors_used = ice_get_max_used_msix_vector(pf);
46262306a36Sopenharmony_ci	u16 num_msix_per_vf, num_txq, num_rxq, avail_qs;
46362306a36Sopenharmony_ci	int msix_avail_per_vf, msix_avail_for_sriov;
46462306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
46562306a36Sopenharmony_ci	int err;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	lockdep_assert_held(&pf->vfs.table_lock);
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	if (!num_vfs)
47062306a36Sopenharmony_ci		return -EINVAL;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/* determine MSI-X resources per VF */
47362306a36Sopenharmony_ci	msix_avail_for_sriov = pf->hw.func_caps.common_cap.num_msix_vectors -
47462306a36Sopenharmony_ci		vectors_used;
47562306a36Sopenharmony_ci	msix_avail_per_vf = msix_avail_for_sriov / num_vfs;
47662306a36Sopenharmony_ci	if (msix_avail_per_vf >= ICE_NUM_VF_MSIX_MED) {
47762306a36Sopenharmony_ci		num_msix_per_vf = ICE_NUM_VF_MSIX_MED;
47862306a36Sopenharmony_ci	} else if (msix_avail_per_vf >= ICE_NUM_VF_MSIX_SMALL) {
47962306a36Sopenharmony_ci		num_msix_per_vf = ICE_NUM_VF_MSIX_SMALL;
48062306a36Sopenharmony_ci	} else if (msix_avail_per_vf >= ICE_NUM_VF_MSIX_MULTIQ_MIN) {
48162306a36Sopenharmony_ci		num_msix_per_vf = ICE_NUM_VF_MSIX_MULTIQ_MIN;
48262306a36Sopenharmony_ci	} else if (msix_avail_per_vf >= ICE_MIN_INTR_PER_VF) {
48362306a36Sopenharmony_ci		num_msix_per_vf = ICE_MIN_INTR_PER_VF;
48462306a36Sopenharmony_ci	} else {
48562306a36Sopenharmony_ci		dev_err(dev, "Only %d MSI-X interrupts available for SR-IOV. Not enough to support minimum of %d MSI-X interrupts per VF for %d VFs\n",
48662306a36Sopenharmony_ci			msix_avail_for_sriov, ICE_MIN_INTR_PER_VF,
48762306a36Sopenharmony_ci			num_vfs);
48862306a36Sopenharmony_ci		return -ENOSPC;
48962306a36Sopenharmony_ci	}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	num_txq = min_t(u16, num_msix_per_vf - ICE_NONQ_VECS_VF,
49262306a36Sopenharmony_ci			ICE_MAX_RSS_QS_PER_VF);
49362306a36Sopenharmony_ci	avail_qs = ice_get_avail_txq_count(pf) / num_vfs;
49462306a36Sopenharmony_ci	if (!avail_qs)
49562306a36Sopenharmony_ci		num_txq = 0;
49662306a36Sopenharmony_ci	else if (num_txq > avail_qs)
49762306a36Sopenharmony_ci		num_txq = rounddown_pow_of_two(avail_qs);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	num_rxq = min_t(u16, num_msix_per_vf - ICE_NONQ_VECS_VF,
50062306a36Sopenharmony_ci			ICE_MAX_RSS_QS_PER_VF);
50162306a36Sopenharmony_ci	avail_qs = ice_get_avail_rxq_count(pf) / num_vfs;
50262306a36Sopenharmony_ci	if (!avail_qs)
50362306a36Sopenharmony_ci		num_rxq = 0;
50462306a36Sopenharmony_ci	else if (num_rxq > avail_qs)
50562306a36Sopenharmony_ci		num_rxq = rounddown_pow_of_two(avail_qs);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	if (num_txq < ICE_MIN_QS_PER_VF || num_rxq < ICE_MIN_QS_PER_VF) {
50862306a36Sopenharmony_ci		dev_err(dev, "Not enough queues to support minimum of %d queue pairs per VF for %d VFs\n",
50962306a36Sopenharmony_ci			ICE_MIN_QS_PER_VF, num_vfs);
51062306a36Sopenharmony_ci		return -ENOSPC;
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	err = ice_sriov_set_msix_res(pf, num_msix_per_vf * num_vfs);
51462306a36Sopenharmony_ci	if (err) {
51562306a36Sopenharmony_ci		dev_err(dev, "Unable to set MSI-X resources for %d VFs, err %d\n",
51662306a36Sopenharmony_ci			num_vfs, err);
51762306a36Sopenharmony_ci		return err;
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	/* only allow equal Tx/Rx queue count (i.e. queue pairs) */
52162306a36Sopenharmony_ci	pf->vfs.num_qps_per = min_t(int, num_txq, num_rxq);
52262306a36Sopenharmony_ci	pf->vfs.num_msix_per = num_msix_per_vf;
52362306a36Sopenharmony_ci	dev_info(dev, "Enabling %d VFs with %d vectors and %d queues per VF\n",
52462306a36Sopenharmony_ci		 num_vfs, pf->vfs.num_msix_per, pf->vfs.num_qps_per);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	return 0;
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci/**
53062306a36Sopenharmony_ci * ice_init_vf_vsi_res - initialize/setup VF VSI resources
53162306a36Sopenharmony_ci * @vf: VF to initialize/setup the VSI for
53262306a36Sopenharmony_ci *
53362306a36Sopenharmony_ci * This function creates a VSI for the VF, adds a VLAN 0 filter, and sets up the
53462306a36Sopenharmony_ci * VF VSI's broadcast filter and is only used during initial VF creation.
53562306a36Sopenharmony_ci */
53662306a36Sopenharmony_cistatic int ice_init_vf_vsi_res(struct ice_vf *vf)
53762306a36Sopenharmony_ci{
53862306a36Sopenharmony_ci	struct ice_pf *pf = vf->pf;
53962306a36Sopenharmony_ci	struct ice_vsi *vsi;
54062306a36Sopenharmony_ci	int err;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	vf->first_vector_idx = ice_calc_vf_first_vector_idx(pf, vf);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	vsi = ice_vf_vsi_setup(vf);
54562306a36Sopenharmony_ci	if (!vsi)
54662306a36Sopenharmony_ci		return -ENOMEM;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	err = ice_vf_init_host_cfg(vf, vsi);
54962306a36Sopenharmony_ci	if (err)
55062306a36Sopenharmony_ci		goto release_vsi;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	return 0;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_cirelease_vsi:
55562306a36Sopenharmony_ci	ice_vf_vsi_release(vf);
55662306a36Sopenharmony_ci	return err;
55762306a36Sopenharmony_ci}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci/**
56062306a36Sopenharmony_ci * ice_start_vfs - start VFs so they are ready to be used by SR-IOV
56162306a36Sopenharmony_ci * @pf: PF the VFs are associated with
56262306a36Sopenharmony_ci */
56362306a36Sopenharmony_cistatic int ice_start_vfs(struct ice_pf *pf)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
56662306a36Sopenharmony_ci	unsigned int bkt, it_cnt;
56762306a36Sopenharmony_ci	struct ice_vf *vf;
56862306a36Sopenharmony_ci	int retval;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	lockdep_assert_held(&pf->vfs.table_lock);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	it_cnt = 0;
57362306a36Sopenharmony_ci	ice_for_each_vf(pf, bkt, vf) {
57462306a36Sopenharmony_ci		vf->vf_ops->clear_reset_trigger(vf);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci		retval = ice_init_vf_vsi_res(vf);
57762306a36Sopenharmony_ci		if (retval) {
57862306a36Sopenharmony_ci			dev_err(ice_pf_to_dev(pf), "Failed to initialize VSI resources for VF %d, error %d\n",
57962306a36Sopenharmony_ci				vf->vf_id, retval);
58062306a36Sopenharmony_ci			goto teardown;
58162306a36Sopenharmony_ci		}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci		set_bit(ICE_VF_STATE_INIT, vf->vf_states);
58462306a36Sopenharmony_ci		ice_ena_vf_mappings(vf);
58562306a36Sopenharmony_ci		wr32(hw, VFGEN_RSTAT(vf->vf_id), VIRTCHNL_VFR_VFACTIVE);
58662306a36Sopenharmony_ci		it_cnt++;
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	ice_flush(hw);
59062306a36Sopenharmony_ci	return 0;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_citeardown:
59362306a36Sopenharmony_ci	ice_for_each_vf(pf, bkt, vf) {
59462306a36Sopenharmony_ci		if (it_cnt == 0)
59562306a36Sopenharmony_ci			break;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci		ice_dis_vf_mappings(vf);
59862306a36Sopenharmony_ci		ice_vf_vsi_release(vf);
59962306a36Sopenharmony_ci		it_cnt--;
60062306a36Sopenharmony_ci	}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	return retval;
60362306a36Sopenharmony_ci}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci/**
60662306a36Sopenharmony_ci * ice_sriov_free_vf - Free VF memory after all references are dropped
60762306a36Sopenharmony_ci * @vf: pointer to VF to free
60862306a36Sopenharmony_ci *
60962306a36Sopenharmony_ci * Called by ice_put_vf through ice_release_vf once the last reference to a VF
61062306a36Sopenharmony_ci * structure has been dropped.
61162306a36Sopenharmony_ci */
61262306a36Sopenharmony_cistatic void ice_sriov_free_vf(struct ice_vf *vf)
61362306a36Sopenharmony_ci{
61462306a36Sopenharmony_ci	mutex_destroy(&vf->cfg_lock);
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	kfree_rcu(vf, rcu);
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci/**
62062306a36Sopenharmony_ci * ice_sriov_clear_reset_state - clears VF Reset status register
62162306a36Sopenharmony_ci * @vf: the vf to configure
62262306a36Sopenharmony_ci */
62362306a36Sopenharmony_cistatic void ice_sriov_clear_reset_state(struct ice_vf *vf)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci	struct ice_hw *hw = &vf->pf->hw;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	/* Clear the reset status register so that VF immediately sees that
62862306a36Sopenharmony_ci	 * the device is resetting, even if hardware hasn't yet gotten around
62962306a36Sopenharmony_ci	 * to clearing VFGEN_RSTAT for us.
63062306a36Sopenharmony_ci	 */
63162306a36Sopenharmony_ci	wr32(hw, VFGEN_RSTAT(vf->vf_id), VIRTCHNL_VFR_INPROGRESS);
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci/**
63562306a36Sopenharmony_ci * ice_sriov_clear_mbx_register - clears SRIOV VF's mailbox registers
63662306a36Sopenharmony_ci * @vf: the vf to configure
63762306a36Sopenharmony_ci */
63862306a36Sopenharmony_cistatic void ice_sriov_clear_mbx_register(struct ice_vf *vf)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	struct ice_pf *pf = vf->pf;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	wr32(&pf->hw, VF_MBX_ARQLEN(vf->vf_id), 0);
64362306a36Sopenharmony_ci	wr32(&pf->hw, VF_MBX_ATQLEN(vf->vf_id), 0);
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci/**
64762306a36Sopenharmony_ci * ice_sriov_trigger_reset_register - trigger VF reset for SRIOV VF
64862306a36Sopenharmony_ci * @vf: pointer to VF structure
64962306a36Sopenharmony_ci * @is_vflr: true if reset occurred due to VFLR
65062306a36Sopenharmony_ci *
65162306a36Sopenharmony_ci * Trigger and cleanup after a VF reset for a SR-IOV VF.
65262306a36Sopenharmony_ci */
65362306a36Sopenharmony_cistatic void ice_sriov_trigger_reset_register(struct ice_vf *vf, bool is_vflr)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	struct ice_pf *pf = vf->pf;
65662306a36Sopenharmony_ci	u32 reg, reg_idx, bit_idx;
65762306a36Sopenharmony_ci	unsigned int vf_abs_id, i;
65862306a36Sopenharmony_ci	struct device *dev;
65962306a36Sopenharmony_ci	struct ice_hw *hw;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
66262306a36Sopenharmony_ci	hw = &pf->hw;
66362306a36Sopenharmony_ci	vf_abs_id = vf->vf_id + hw->func_caps.vf_base_id;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	/* In the case of a VFLR, HW has already reset the VF and we just need
66662306a36Sopenharmony_ci	 * to clean up. Otherwise we must first trigger the reset using the
66762306a36Sopenharmony_ci	 * VFRTRIG register.
66862306a36Sopenharmony_ci	 */
66962306a36Sopenharmony_ci	if (!is_vflr) {
67062306a36Sopenharmony_ci		reg = rd32(hw, VPGEN_VFRTRIG(vf->vf_id));
67162306a36Sopenharmony_ci		reg |= VPGEN_VFRTRIG_VFSWR_M;
67262306a36Sopenharmony_ci		wr32(hw, VPGEN_VFRTRIG(vf->vf_id), reg);
67362306a36Sopenharmony_ci	}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	/* clear the VFLR bit in GLGEN_VFLRSTAT */
67662306a36Sopenharmony_ci	reg_idx = (vf_abs_id) / 32;
67762306a36Sopenharmony_ci	bit_idx = (vf_abs_id) % 32;
67862306a36Sopenharmony_ci	wr32(hw, GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx));
67962306a36Sopenharmony_ci	ice_flush(hw);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	wr32(hw, PF_PCI_CIAA,
68262306a36Sopenharmony_ci	     VF_DEVICE_STATUS | (vf_abs_id << PF_PCI_CIAA_VF_NUM_S));
68362306a36Sopenharmony_ci	for (i = 0; i < ICE_PCI_CIAD_WAIT_COUNT; i++) {
68462306a36Sopenharmony_ci		reg = rd32(hw, PF_PCI_CIAD);
68562306a36Sopenharmony_ci		/* no transactions pending so stop polling */
68662306a36Sopenharmony_ci		if ((reg & VF_TRANS_PENDING_M) == 0)
68762306a36Sopenharmony_ci			break;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci		dev_err(dev, "VF %u PCI transactions stuck\n", vf->vf_id);
69062306a36Sopenharmony_ci		udelay(ICE_PCI_CIAD_WAIT_DELAY_US);
69162306a36Sopenharmony_ci	}
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci/**
69562306a36Sopenharmony_ci * ice_sriov_poll_reset_status - poll SRIOV VF reset status
69662306a36Sopenharmony_ci * @vf: pointer to VF structure
69762306a36Sopenharmony_ci *
69862306a36Sopenharmony_ci * Returns true when reset is successful, else returns false
69962306a36Sopenharmony_ci */
70062306a36Sopenharmony_cistatic bool ice_sriov_poll_reset_status(struct ice_vf *vf)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	struct ice_pf *pf = vf->pf;
70362306a36Sopenharmony_ci	unsigned int i;
70462306a36Sopenharmony_ci	u32 reg;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	for (i = 0; i < 10; i++) {
70762306a36Sopenharmony_ci		/* VF reset requires driver to first reset the VF and then
70862306a36Sopenharmony_ci		 * poll the status register to make sure that the reset
70962306a36Sopenharmony_ci		 * completed successfully.
71062306a36Sopenharmony_ci		 */
71162306a36Sopenharmony_ci		reg = rd32(&pf->hw, VPGEN_VFRSTAT(vf->vf_id));
71262306a36Sopenharmony_ci		if (reg & VPGEN_VFRSTAT_VFRD_M)
71362306a36Sopenharmony_ci			return true;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci		/* only sleep if the reset is not done */
71662306a36Sopenharmony_ci		usleep_range(10, 20);
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci	return false;
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci/**
72262306a36Sopenharmony_ci * ice_sriov_clear_reset_trigger - enable VF to access hardware
72362306a36Sopenharmony_ci * @vf: VF to enabled hardware access for
72462306a36Sopenharmony_ci */
72562306a36Sopenharmony_cistatic void ice_sriov_clear_reset_trigger(struct ice_vf *vf)
72662306a36Sopenharmony_ci{
72762306a36Sopenharmony_ci	struct ice_hw *hw = &vf->pf->hw;
72862306a36Sopenharmony_ci	u32 reg;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	reg = rd32(hw, VPGEN_VFRTRIG(vf->vf_id));
73162306a36Sopenharmony_ci	reg &= ~VPGEN_VFRTRIG_VFSWR_M;
73262306a36Sopenharmony_ci	wr32(hw, VPGEN_VFRTRIG(vf->vf_id), reg);
73362306a36Sopenharmony_ci	ice_flush(hw);
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci/**
73762306a36Sopenharmony_ci * ice_sriov_create_vsi - Create a new VSI for a VF
73862306a36Sopenharmony_ci * @vf: VF to create the VSI for
73962306a36Sopenharmony_ci *
74062306a36Sopenharmony_ci * This is called by ice_vf_recreate_vsi to create the new VSI after the old
74162306a36Sopenharmony_ci * VSI has been released.
74262306a36Sopenharmony_ci */
74362306a36Sopenharmony_cistatic int ice_sriov_create_vsi(struct ice_vf *vf)
74462306a36Sopenharmony_ci{
74562306a36Sopenharmony_ci	struct ice_vsi *vsi;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	vsi = ice_vf_vsi_setup(vf);
74862306a36Sopenharmony_ci	if (!vsi)
74962306a36Sopenharmony_ci		return -ENOMEM;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	return 0;
75262306a36Sopenharmony_ci}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci/**
75562306a36Sopenharmony_ci * ice_sriov_post_vsi_rebuild - tasks to do after the VF's VSI have been rebuilt
75662306a36Sopenharmony_ci * @vf: VF to perform tasks on
75762306a36Sopenharmony_ci */
75862306a36Sopenharmony_cistatic void ice_sriov_post_vsi_rebuild(struct ice_vf *vf)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	ice_ena_vf_mappings(vf);
76162306a36Sopenharmony_ci	wr32(&vf->pf->hw, VFGEN_RSTAT(vf->vf_id), VIRTCHNL_VFR_VFACTIVE);
76262306a36Sopenharmony_ci}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_cistatic const struct ice_vf_ops ice_sriov_vf_ops = {
76562306a36Sopenharmony_ci	.reset_type = ICE_VF_RESET,
76662306a36Sopenharmony_ci	.free = ice_sriov_free_vf,
76762306a36Sopenharmony_ci	.clear_reset_state = ice_sriov_clear_reset_state,
76862306a36Sopenharmony_ci	.clear_mbx_register = ice_sriov_clear_mbx_register,
76962306a36Sopenharmony_ci	.trigger_reset_register = ice_sriov_trigger_reset_register,
77062306a36Sopenharmony_ci	.poll_reset_status = ice_sriov_poll_reset_status,
77162306a36Sopenharmony_ci	.clear_reset_trigger = ice_sriov_clear_reset_trigger,
77262306a36Sopenharmony_ci	.irq_close = NULL,
77362306a36Sopenharmony_ci	.create_vsi = ice_sriov_create_vsi,
77462306a36Sopenharmony_ci	.post_vsi_rebuild = ice_sriov_post_vsi_rebuild,
77562306a36Sopenharmony_ci};
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci/**
77862306a36Sopenharmony_ci * ice_create_vf_entries - Allocate and insert VF entries
77962306a36Sopenharmony_ci * @pf: pointer to the PF structure
78062306a36Sopenharmony_ci * @num_vfs: the number of VFs to allocate
78162306a36Sopenharmony_ci *
78262306a36Sopenharmony_ci * Allocate new VF entries and insert them into the hash table. Set some
78362306a36Sopenharmony_ci * basic default fields for initializing the new VFs.
78462306a36Sopenharmony_ci *
78562306a36Sopenharmony_ci * After this function exits, the hash table will have num_vfs entries
78662306a36Sopenharmony_ci * inserted.
78762306a36Sopenharmony_ci *
78862306a36Sopenharmony_ci * Returns 0 on success or an integer error code on failure.
78962306a36Sopenharmony_ci */
79062306a36Sopenharmony_cistatic int ice_create_vf_entries(struct ice_pf *pf, u16 num_vfs)
79162306a36Sopenharmony_ci{
79262306a36Sopenharmony_ci	struct ice_vfs *vfs = &pf->vfs;
79362306a36Sopenharmony_ci	struct ice_vf *vf;
79462306a36Sopenharmony_ci	u16 vf_id;
79562306a36Sopenharmony_ci	int err;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	lockdep_assert_held(&vfs->table_lock);
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	for (vf_id = 0; vf_id < num_vfs; vf_id++) {
80062306a36Sopenharmony_ci		vf = kzalloc(sizeof(*vf), GFP_KERNEL);
80162306a36Sopenharmony_ci		if (!vf) {
80262306a36Sopenharmony_ci			err = -ENOMEM;
80362306a36Sopenharmony_ci			goto err_free_entries;
80462306a36Sopenharmony_ci		}
80562306a36Sopenharmony_ci		kref_init(&vf->refcnt);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci		vf->pf = pf;
80862306a36Sopenharmony_ci		vf->vf_id = vf_id;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci		/* set sriov vf ops for VFs created during SRIOV flow */
81162306a36Sopenharmony_ci		vf->vf_ops = &ice_sriov_vf_ops;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci		ice_initialize_vf_entry(vf);
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci		vf->vf_sw_id = pf->first_sw;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci		hash_add_rcu(vfs->table, &vf->entry, vf_id);
81862306a36Sopenharmony_ci	}
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	return 0;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cierr_free_entries:
82362306a36Sopenharmony_ci	ice_free_vf_entries(pf);
82462306a36Sopenharmony_ci	return err;
82562306a36Sopenharmony_ci}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci/**
82862306a36Sopenharmony_ci * ice_ena_vfs - enable VFs so they are ready to be used
82962306a36Sopenharmony_ci * @pf: pointer to the PF structure
83062306a36Sopenharmony_ci * @num_vfs: number of VFs to enable
83162306a36Sopenharmony_ci */
83262306a36Sopenharmony_cistatic int ice_ena_vfs(struct ice_pf *pf, u16 num_vfs)
83362306a36Sopenharmony_ci{
83462306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
83562306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
83662306a36Sopenharmony_ci	int ret;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	/* Disable global interrupt 0 so we don't try to handle the VFLR. */
83962306a36Sopenharmony_ci	wr32(hw, GLINT_DYN_CTL(pf->oicr_irq.index),
84062306a36Sopenharmony_ci	     ICE_ITR_NONE << GLINT_DYN_CTL_ITR_INDX_S);
84162306a36Sopenharmony_ci	set_bit(ICE_OICR_INTR_DIS, pf->state);
84262306a36Sopenharmony_ci	ice_flush(hw);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	ret = pci_enable_sriov(pf->pdev, num_vfs);
84562306a36Sopenharmony_ci	if (ret)
84662306a36Sopenharmony_ci		goto err_unroll_intr;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	mutex_lock(&pf->vfs.table_lock);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	ret = ice_set_per_vf_res(pf, num_vfs);
85162306a36Sopenharmony_ci	if (ret) {
85262306a36Sopenharmony_ci		dev_err(dev, "Not enough resources for %d VFs, err %d. Try with fewer number of VFs\n",
85362306a36Sopenharmony_ci			num_vfs, ret);
85462306a36Sopenharmony_ci		goto err_unroll_sriov;
85562306a36Sopenharmony_ci	}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	ret = ice_create_vf_entries(pf, num_vfs);
85862306a36Sopenharmony_ci	if (ret) {
85962306a36Sopenharmony_ci		dev_err(dev, "Failed to allocate VF entries for %d VFs\n",
86062306a36Sopenharmony_ci			num_vfs);
86162306a36Sopenharmony_ci		goto err_unroll_sriov;
86262306a36Sopenharmony_ci	}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	ret = ice_start_vfs(pf);
86562306a36Sopenharmony_ci	if (ret) {
86662306a36Sopenharmony_ci		dev_err(dev, "Failed to start %d VFs, err %d\n", num_vfs, ret);
86762306a36Sopenharmony_ci		ret = -EAGAIN;
86862306a36Sopenharmony_ci		goto err_unroll_vf_entries;
86962306a36Sopenharmony_ci	}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	clear_bit(ICE_VF_DIS, pf->state);
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	ret = ice_eswitch_configure(pf);
87462306a36Sopenharmony_ci	if (ret) {
87562306a36Sopenharmony_ci		dev_err(dev, "Failed to configure eswitch, err %d\n", ret);
87662306a36Sopenharmony_ci		goto err_unroll_sriov;
87762306a36Sopenharmony_ci	}
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci	/* rearm global interrupts */
88062306a36Sopenharmony_ci	if (test_and_clear_bit(ICE_OICR_INTR_DIS, pf->state))
88162306a36Sopenharmony_ci		ice_irq_dynamic_ena(hw, NULL, NULL);
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	mutex_unlock(&pf->vfs.table_lock);
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	return 0;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_cierr_unroll_vf_entries:
88862306a36Sopenharmony_ci	ice_free_vf_entries(pf);
88962306a36Sopenharmony_cierr_unroll_sriov:
89062306a36Sopenharmony_ci	mutex_unlock(&pf->vfs.table_lock);
89162306a36Sopenharmony_ci	pci_disable_sriov(pf->pdev);
89262306a36Sopenharmony_cierr_unroll_intr:
89362306a36Sopenharmony_ci	/* rearm interrupts here */
89462306a36Sopenharmony_ci	ice_irq_dynamic_ena(hw, NULL, NULL);
89562306a36Sopenharmony_ci	clear_bit(ICE_OICR_INTR_DIS, pf->state);
89662306a36Sopenharmony_ci	return ret;
89762306a36Sopenharmony_ci}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci/**
90062306a36Sopenharmony_ci * ice_pci_sriov_ena - Enable or change number of VFs
90162306a36Sopenharmony_ci * @pf: pointer to the PF structure
90262306a36Sopenharmony_ci * @num_vfs: number of VFs to allocate
90362306a36Sopenharmony_ci *
90462306a36Sopenharmony_ci * Returns 0 on success and negative on failure
90562306a36Sopenharmony_ci */
90662306a36Sopenharmony_cistatic int ice_pci_sriov_ena(struct ice_pf *pf, int num_vfs)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
90962306a36Sopenharmony_ci	int err;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	if (!num_vfs) {
91262306a36Sopenharmony_ci		ice_free_vfs(pf);
91362306a36Sopenharmony_ci		return 0;
91462306a36Sopenharmony_ci	}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	if (num_vfs > pf->vfs.num_supported) {
91762306a36Sopenharmony_ci		dev_err(dev, "Can't enable %d VFs, max VFs supported is %d\n",
91862306a36Sopenharmony_ci			num_vfs, pf->vfs.num_supported);
91962306a36Sopenharmony_ci		return -EOPNOTSUPP;
92062306a36Sopenharmony_ci	}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	dev_info(dev, "Enabling %d VFs\n", num_vfs);
92362306a36Sopenharmony_ci	err = ice_ena_vfs(pf, num_vfs);
92462306a36Sopenharmony_ci	if (err) {
92562306a36Sopenharmony_ci		dev_err(dev, "Failed to enable SR-IOV: %d\n", err);
92662306a36Sopenharmony_ci		return err;
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	set_bit(ICE_FLAG_SRIOV_ENA, pf->flags);
93062306a36Sopenharmony_ci	return 0;
93162306a36Sopenharmony_ci}
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci/**
93462306a36Sopenharmony_ci * ice_check_sriov_allowed - check if SR-IOV is allowed based on various checks
93562306a36Sopenharmony_ci * @pf: PF to enabled SR-IOV on
93662306a36Sopenharmony_ci */
93762306a36Sopenharmony_cistatic int ice_check_sriov_allowed(struct ice_pf *pf)
93862306a36Sopenharmony_ci{
93962306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	if (!test_bit(ICE_FLAG_SRIOV_CAPABLE, pf->flags)) {
94262306a36Sopenharmony_ci		dev_err(dev, "This device is not capable of SR-IOV\n");
94362306a36Sopenharmony_ci		return -EOPNOTSUPP;
94462306a36Sopenharmony_ci	}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	if (ice_is_safe_mode(pf)) {
94762306a36Sopenharmony_ci		dev_err(dev, "SR-IOV cannot be configured - Device is in Safe Mode\n");
94862306a36Sopenharmony_ci		return -EOPNOTSUPP;
94962306a36Sopenharmony_ci	}
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	if (!ice_pf_state_is_nominal(pf)) {
95262306a36Sopenharmony_ci		dev_err(dev, "Cannot enable SR-IOV, device not ready\n");
95362306a36Sopenharmony_ci		return -EBUSY;
95462306a36Sopenharmony_ci	}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	return 0;
95762306a36Sopenharmony_ci}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci/**
96062306a36Sopenharmony_ci * ice_sriov_configure - Enable or change number of VFs via sysfs
96162306a36Sopenharmony_ci * @pdev: pointer to a pci_dev structure
96262306a36Sopenharmony_ci * @num_vfs: number of VFs to allocate or 0 to free VFs
96362306a36Sopenharmony_ci *
96462306a36Sopenharmony_ci * This function is called when the user updates the number of VFs in sysfs. On
96562306a36Sopenharmony_ci * success return whatever num_vfs was set to by the caller. Return negative on
96662306a36Sopenharmony_ci * failure.
96762306a36Sopenharmony_ci */
96862306a36Sopenharmony_ciint ice_sriov_configure(struct pci_dev *pdev, int num_vfs)
96962306a36Sopenharmony_ci{
97062306a36Sopenharmony_ci	struct ice_pf *pf = pci_get_drvdata(pdev);
97162306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
97262306a36Sopenharmony_ci	int err;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	err = ice_check_sriov_allowed(pf);
97562306a36Sopenharmony_ci	if (err)
97662306a36Sopenharmony_ci		return err;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	if (!num_vfs) {
97962306a36Sopenharmony_ci		if (!pci_vfs_assigned(pdev)) {
98062306a36Sopenharmony_ci			ice_free_vfs(pf);
98162306a36Sopenharmony_ci			return 0;
98262306a36Sopenharmony_ci		}
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci		dev_err(dev, "can't free VFs because some are assigned to VMs.\n");
98562306a36Sopenharmony_ci		return -EBUSY;
98662306a36Sopenharmony_ci	}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	err = ice_pci_sriov_ena(pf, num_vfs);
98962306a36Sopenharmony_ci	if (err)
99062306a36Sopenharmony_ci		return err;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	return num_vfs;
99362306a36Sopenharmony_ci}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci/**
99662306a36Sopenharmony_ci * ice_process_vflr_event - Free VF resources via IRQ calls
99762306a36Sopenharmony_ci * @pf: pointer to the PF structure
99862306a36Sopenharmony_ci *
99962306a36Sopenharmony_ci * called from the VFLR IRQ handler to
100062306a36Sopenharmony_ci * free up VF resources and state variables
100162306a36Sopenharmony_ci */
100262306a36Sopenharmony_civoid ice_process_vflr_event(struct ice_pf *pf)
100362306a36Sopenharmony_ci{
100462306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
100562306a36Sopenharmony_ci	struct ice_vf *vf;
100662306a36Sopenharmony_ci	unsigned int bkt;
100762306a36Sopenharmony_ci	u32 reg;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	if (!test_and_clear_bit(ICE_VFLR_EVENT_PENDING, pf->state) ||
101062306a36Sopenharmony_ci	    !ice_has_vfs(pf))
101162306a36Sopenharmony_ci		return;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	mutex_lock(&pf->vfs.table_lock);
101462306a36Sopenharmony_ci	ice_for_each_vf(pf, bkt, vf) {
101562306a36Sopenharmony_ci		u32 reg_idx, bit_idx;
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci		reg_idx = (hw->func_caps.vf_base_id + vf->vf_id) / 32;
101862306a36Sopenharmony_ci		bit_idx = (hw->func_caps.vf_base_id + vf->vf_id) % 32;
101962306a36Sopenharmony_ci		/* read GLGEN_VFLRSTAT register to find out the flr VFs */
102062306a36Sopenharmony_ci		reg = rd32(hw, GLGEN_VFLRSTAT(reg_idx));
102162306a36Sopenharmony_ci		if (reg & BIT(bit_idx))
102262306a36Sopenharmony_ci			/* GLGEN_VFLRSTAT bit will be cleared in ice_reset_vf */
102362306a36Sopenharmony_ci			ice_reset_vf(vf, ICE_VF_RESET_VFLR | ICE_VF_RESET_LOCK);
102462306a36Sopenharmony_ci	}
102562306a36Sopenharmony_ci	mutex_unlock(&pf->vfs.table_lock);
102662306a36Sopenharmony_ci}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci/**
102962306a36Sopenharmony_ci * ice_get_vf_from_pfq - get the VF who owns the PF space queue passed in
103062306a36Sopenharmony_ci * @pf: PF used to index all VFs
103162306a36Sopenharmony_ci * @pfq: queue index relative to the PF's function space
103262306a36Sopenharmony_ci *
103362306a36Sopenharmony_ci * If no VF is found who owns the pfq then return NULL, otherwise return a
103462306a36Sopenharmony_ci * pointer to the VF who owns the pfq
103562306a36Sopenharmony_ci *
103662306a36Sopenharmony_ci * If this function returns non-NULL, it acquires a reference count of the VF
103762306a36Sopenharmony_ci * structure. The caller is responsible for calling ice_put_vf() to drop this
103862306a36Sopenharmony_ci * reference.
103962306a36Sopenharmony_ci */
104062306a36Sopenharmony_cistatic struct ice_vf *ice_get_vf_from_pfq(struct ice_pf *pf, u16 pfq)
104162306a36Sopenharmony_ci{
104262306a36Sopenharmony_ci	struct ice_vf *vf;
104362306a36Sopenharmony_ci	unsigned int bkt;
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	rcu_read_lock();
104662306a36Sopenharmony_ci	ice_for_each_vf_rcu(pf, bkt, vf) {
104762306a36Sopenharmony_ci		struct ice_vsi *vsi;
104862306a36Sopenharmony_ci		u16 rxq_idx;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci		vsi = ice_get_vf_vsi(vf);
105162306a36Sopenharmony_ci		if (!vsi)
105262306a36Sopenharmony_ci			continue;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci		ice_for_each_rxq(vsi, rxq_idx)
105562306a36Sopenharmony_ci			if (vsi->rxq_map[rxq_idx] == pfq) {
105662306a36Sopenharmony_ci				struct ice_vf *found;
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci				if (kref_get_unless_zero(&vf->refcnt))
105962306a36Sopenharmony_ci					found = vf;
106062306a36Sopenharmony_ci				else
106162306a36Sopenharmony_ci					found = NULL;
106262306a36Sopenharmony_ci				rcu_read_unlock();
106362306a36Sopenharmony_ci				return found;
106462306a36Sopenharmony_ci			}
106562306a36Sopenharmony_ci	}
106662306a36Sopenharmony_ci	rcu_read_unlock();
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci	return NULL;
106962306a36Sopenharmony_ci}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci/**
107262306a36Sopenharmony_ci * ice_globalq_to_pfq - convert from global queue index to PF space queue index
107362306a36Sopenharmony_ci * @pf: PF used for conversion
107462306a36Sopenharmony_ci * @globalq: global queue index used to convert to PF space queue index
107562306a36Sopenharmony_ci */
107662306a36Sopenharmony_cistatic u32 ice_globalq_to_pfq(struct ice_pf *pf, u32 globalq)
107762306a36Sopenharmony_ci{
107862306a36Sopenharmony_ci	return globalq - pf->hw.func_caps.common_cap.rxq_first_id;
107962306a36Sopenharmony_ci}
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci/**
108262306a36Sopenharmony_ci * ice_vf_lan_overflow_event - handle LAN overflow event for a VF
108362306a36Sopenharmony_ci * @pf: PF that the LAN overflow event happened on
108462306a36Sopenharmony_ci * @event: structure holding the event information for the LAN overflow event
108562306a36Sopenharmony_ci *
108662306a36Sopenharmony_ci * Determine if the LAN overflow event was caused by a VF queue. If it was not
108762306a36Sopenharmony_ci * caused by a VF, do nothing. If a VF caused this LAN overflow event trigger a
108862306a36Sopenharmony_ci * reset on the offending VF.
108962306a36Sopenharmony_ci */
109062306a36Sopenharmony_civoid
109162306a36Sopenharmony_ciice_vf_lan_overflow_event(struct ice_pf *pf, struct ice_rq_event_info *event)
109262306a36Sopenharmony_ci{
109362306a36Sopenharmony_ci	u32 gldcb_rtctq, queue;
109462306a36Sopenharmony_ci	struct ice_vf *vf;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	gldcb_rtctq = le32_to_cpu(event->desc.params.lan_overflow.prtdcb_ruptq);
109762306a36Sopenharmony_ci	dev_dbg(ice_pf_to_dev(pf), "GLDCB_RTCTQ: 0x%08x\n", gldcb_rtctq);
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	/* event returns device global Rx queue number */
110062306a36Sopenharmony_ci	queue = (gldcb_rtctq & GLDCB_RTCTQ_RXQNUM_M) >>
110162306a36Sopenharmony_ci		GLDCB_RTCTQ_RXQNUM_S;
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci	vf = ice_get_vf_from_pfq(pf, ice_globalq_to_pfq(pf, queue));
110462306a36Sopenharmony_ci	if (!vf)
110562306a36Sopenharmony_ci		return;
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	ice_reset_vf(vf, ICE_VF_RESET_NOTIFY | ICE_VF_RESET_LOCK);
110862306a36Sopenharmony_ci	ice_put_vf(vf);
110962306a36Sopenharmony_ci}
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci/**
111262306a36Sopenharmony_ci * ice_set_vf_spoofchk
111362306a36Sopenharmony_ci * @netdev: network interface device structure
111462306a36Sopenharmony_ci * @vf_id: VF identifier
111562306a36Sopenharmony_ci * @ena: flag to enable or disable feature
111662306a36Sopenharmony_ci *
111762306a36Sopenharmony_ci * Enable or disable VF spoof checking
111862306a36Sopenharmony_ci */
111962306a36Sopenharmony_ciint ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena)
112062306a36Sopenharmony_ci{
112162306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
112262306a36Sopenharmony_ci	struct ice_pf *pf = np->vsi->back;
112362306a36Sopenharmony_ci	struct ice_vsi *vf_vsi;
112462306a36Sopenharmony_ci	struct device *dev;
112562306a36Sopenharmony_ci	struct ice_vf *vf;
112662306a36Sopenharmony_ci	int ret;
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	vf = ice_get_vf_by_id(pf, vf_id);
113162306a36Sopenharmony_ci	if (!vf)
113262306a36Sopenharmony_ci		return -EINVAL;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	ret = ice_check_vf_ready_for_cfg(vf);
113562306a36Sopenharmony_ci	if (ret)
113662306a36Sopenharmony_ci		goto out_put_vf;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	vf_vsi = ice_get_vf_vsi(vf);
113962306a36Sopenharmony_ci	if (!vf_vsi) {
114062306a36Sopenharmony_ci		netdev_err(netdev, "VSI %d for VF %d is null\n",
114162306a36Sopenharmony_ci			   vf->lan_vsi_idx, vf->vf_id);
114262306a36Sopenharmony_ci		ret = -EINVAL;
114362306a36Sopenharmony_ci		goto out_put_vf;
114462306a36Sopenharmony_ci	}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	if (vf_vsi->type != ICE_VSI_VF) {
114762306a36Sopenharmony_ci		netdev_err(netdev, "Type %d of VSI %d for VF %d is no ICE_VSI_VF\n",
114862306a36Sopenharmony_ci			   vf_vsi->type, vf_vsi->vsi_num, vf->vf_id);
114962306a36Sopenharmony_ci		ret = -ENODEV;
115062306a36Sopenharmony_ci		goto out_put_vf;
115162306a36Sopenharmony_ci	}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	if (ena == vf->spoofchk) {
115462306a36Sopenharmony_ci		dev_dbg(dev, "VF spoofchk already %s\n", ena ? "ON" : "OFF");
115562306a36Sopenharmony_ci		ret = 0;
115662306a36Sopenharmony_ci		goto out_put_vf;
115762306a36Sopenharmony_ci	}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	ret = ice_vsi_apply_spoofchk(vf_vsi, ena);
116062306a36Sopenharmony_ci	if (ret)
116162306a36Sopenharmony_ci		dev_err(dev, "Failed to set spoofchk %s for VF %d VSI %d\n error %d\n",
116262306a36Sopenharmony_ci			ena ? "ON" : "OFF", vf->vf_id, vf_vsi->vsi_num, ret);
116362306a36Sopenharmony_ci	else
116462306a36Sopenharmony_ci		vf->spoofchk = ena;
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ciout_put_vf:
116762306a36Sopenharmony_ci	ice_put_vf(vf);
116862306a36Sopenharmony_ci	return ret;
116962306a36Sopenharmony_ci}
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci/**
117262306a36Sopenharmony_ci * ice_get_vf_cfg
117362306a36Sopenharmony_ci * @netdev: network interface device structure
117462306a36Sopenharmony_ci * @vf_id: VF identifier
117562306a36Sopenharmony_ci * @ivi: VF configuration structure
117662306a36Sopenharmony_ci *
117762306a36Sopenharmony_ci * return VF configuration
117862306a36Sopenharmony_ci */
117962306a36Sopenharmony_ciint
118062306a36Sopenharmony_ciice_get_vf_cfg(struct net_device *netdev, int vf_id, struct ifla_vf_info *ivi)
118162306a36Sopenharmony_ci{
118262306a36Sopenharmony_ci	struct ice_pf *pf = ice_netdev_to_pf(netdev);
118362306a36Sopenharmony_ci	struct ice_vf *vf;
118462306a36Sopenharmony_ci	int ret;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	vf = ice_get_vf_by_id(pf, vf_id);
118762306a36Sopenharmony_ci	if (!vf)
118862306a36Sopenharmony_ci		return -EINVAL;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	ret = ice_check_vf_ready_for_cfg(vf);
119162306a36Sopenharmony_ci	if (ret)
119262306a36Sopenharmony_ci		goto out_put_vf;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	ivi->vf = vf_id;
119562306a36Sopenharmony_ci	ether_addr_copy(ivi->mac, vf->hw_lan_addr);
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	/* VF configuration for VLAN and applicable QoS */
119862306a36Sopenharmony_ci	ivi->vlan = ice_vf_get_port_vlan_id(vf);
119962306a36Sopenharmony_ci	ivi->qos = ice_vf_get_port_vlan_prio(vf);
120062306a36Sopenharmony_ci	if (ice_vf_is_port_vlan_ena(vf))
120162306a36Sopenharmony_ci		ivi->vlan_proto = cpu_to_be16(ice_vf_get_port_vlan_tpid(vf));
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	ivi->trusted = vf->trusted;
120462306a36Sopenharmony_ci	ivi->spoofchk = vf->spoofchk;
120562306a36Sopenharmony_ci	if (!vf->link_forced)
120662306a36Sopenharmony_ci		ivi->linkstate = IFLA_VF_LINK_STATE_AUTO;
120762306a36Sopenharmony_ci	else if (vf->link_up)
120862306a36Sopenharmony_ci		ivi->linkstate = IFLA_VF_LINK_STATE_ENABLE;
120962306a36Sopenharmony_ci	else
121062306a36Sopenharmony_ci		ivi->linkstate = IFLA_VF_LINK_STATE_DISABLE;
121162306a36Sopenharmony_ci	ivi->max_tx_rate = vf->max_tx_rate;
121262306a36Sopenharmony_ci	ivi->min_tx_rate = vf->min_tx_rate;
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ciout_put_vf:
121562306a36Sopenharmony_ci	ice_put_vf(vf);
121662306a36Sopenharmony_ci	return ret;
121762306a36Sopenharmony_ci}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci/**
122062306a36Sopenharmony_ci * ice_set_vf_mac
122162306a36Sopenharmony_ci * @netdev: network interface device structure
122262306a36Sopenharmony_ci * @vf_id: VF identifier
122362306a36Sopenharmony_ci * @mac: MAC address
122462306a36Sopenharmony_ci *
122562306a36Sopenharmony_ci * program VF MAC address
122662306a36Sopenharmony_ci */
122762306a36Sopenharmony_ciint ice_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
122862306a36Sopenharmony_ci{
122962306a36Sopenharmony_ci	struct ice_pf *pf = ice_netdev_to_pf(netdev);
123062306a36Sopenharmony_ci	struct ice_vf *vf;
123162306a36Sopenharmony_ci	int ret;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	if (is_multicast_ether_addr(mac)) {
123462306a36Sopenharmony_ci		netdev_err(netdev, "%pM not a valid unicast address\n", mac);
123562306a36Sopenharmony_ci		return -EINVAL;
123662306a36Sopenharmony_ci	}
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	vf = ice_get_vf_by_id(pf, vf_id);
123962306a36Sopenharmony_ci	if (!vf)
124062306a36Sopenharmony_ci		return -EINVAL;
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	/* nothing left to do, unicast MAC already set */
124362306a36Sopenharmony_ci	if (ether_addr_equal(vf->dev_lan_addr, mac) &&
124462306a36Sopenharmony_ci	    ether_addr_equal(vf->hw_lan_addr, mac)) {
124562306a36Sopenharmony_ci		ret = 0;
124662306a36Sopenharmony_ci		goto out_put_vf;
124762306a36Sopenharmony_ci	}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	ret = ice_check_vf_ready_for_cfg(vf);
125062306a36Sopenharmony_ci	if (ret)
125162306a36Sopenharmony_ci		goto out_put_vf;
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci	mutex_lock(&vf->cfg_lock);
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	/* VF is notified of its new MAC via the PF's response to the
125662306a36Sopenharmony_ci	 * VIRTCHNL_OP_GET_VF_RESOURCES message after the VF has been reset
125762306a36Sopenharmony_ci	 */
125862306a36Sopenharmony_ci	ether_addr_copy(vf->dev_lan_addr, mac);
125962306a36Sopenharmony_ci	ether_addr_copy(vf->hw_lan_addr, mac);
126062306a36Sopenharmony_ci	if (is_zero_ether_addr(mac)) {
126162306a36Sopenharmony_ci		/* VF will send VIRTCHNL_OP_ADD_ETH_ADDR message with its MAC */
126262306a36Sopenharmony_ci		vf->pf_set_mac = false;
126362306a36Sopenharmony_ci		netdev_info(netdev, "Removing MAC on VF %d. VF driver will be reinitialized\n",
126462306a36Sopenharmony_ci			    vf->vf_id);
126562306a36Sopenharmony_ci	} else {
126662306a36Sopenharmony_ci		/* PF will add MAC rule for the VF */
126762306a36Sopenharmony_ci		vf->pf_set_mac = true;
126862306a36Sopenharmony_ci		netdev_info(netdev, "Setting MAC %pM on VF %d. VF driver will be reinitialized\n",
126962306a36Sopenharmony_ci			    mac, vf_id);
127062306a36Sopenharmony_ci	}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	ice_reset_vf(vf, ICE_VF_RESET_NOTIFY);
127362306a36Sopenharmony_ci	mutex_unlock(&vf->cfg_lock);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ciout_put_vf:
127662306a36Sopenharmony_ci	ice_put_vf(vf);
127762306a36Sopenharmony_ci	return ret;
127862306a36Sopenharmony_ci}
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci/**
128162306a36Sopenharmony_ci * ice_set_vf_trust
128262306a36Sopenharmony_ci * @netdev: network interface device structure
128362306a36Sopenharmony_ci * @vf_id: VF identifier
128462306a36Sopenharmony_ci * @trusted: Boolean value to enable/disable trusted VF
128562306a36Sopenharmony_ci *
128662306a36Sopenharmony_ci * Enable or disable a given VF as trusted
128762306a36Sopenharmony_ci */
128862306a36Sopenharmony_ciint ice_set_vf_trust(struct net_device *netdev, int vf_id, bool trusted)
128962306a36Sopenharmony_ci{
129062306a36Sopenharmony_ci	struct ice_pf *pf = ice_netdev_to_pf(netdev);
129162306a36Sopenharmony_ci	struct ice_vf *vf;
129262306a36Sopenharmony_ci	int ret;
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	vf = ice_get_vf_by_id(pf, vf_id);
129562306a36Sopenharmony_ci	if (!vf)
129662306a36Sopenharmony_ci		return -EINVAL;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	if (ice_is_eswitch_mode_switchdev(pf)) {
129962306a36Sopenharmony_ci		dev_info(ice_pf_to_dev(pf), "Trusted VF is forbidden in switchdev mode\n");
130062306a36Sopenharmony_ci		return -EOPNOTSUPP;
130162306a36Sopenharmony_ci	}
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	ret = ice_check_vf_ready_for_cfg(vf);
130462306a36Sopenharmony_ci	if (ret)
130562306a36Sopenharmony_ci		goto out_put_vf;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	/* Check if already trusted */
130862306a36Sopenharmony_ci	if (trusted == vf->trusted) {
130962306a36Sopenharmony_ci		ret = 0;
131062306a36Sopenharmony_ci		goto out_put_vf;
131162306a36Sopenharmony_ci	}
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	mutex_lock(&vf->cfg_lock);
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci	vf->trusted = trusted;
131662306a36Sopenharmony_ci	ice_reset_vf(vf, ICE_VF_RESET_NOTIFY);
131762306a36Sopenharmony_ci	dev_info(ice_pf_to_dev(pf), "VF %u is now %strusted\n",
131862306a36Sopenharmony_ci		 vf_id, trusted ? "" : "un");
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	mutex_unlock(&vf->cfg_lock);
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ciout_put_vf:
132362306a36Sopenharmony_ci	ice_put_vf(vf);
132462306a36Sopenharmony_ci	return ret;
132562306a36Sopenharmony_ci}
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci/**
132862306a36Sopenharmony_ci * ice_set_vf_link_state
132962306a36Sopenharmony_ci * @netdev: network interface device structure
133062306a36Sopenharmony_ci * @vf_id: VF identifier
133162306a36Sopenharmony_ci * @link_state: required link state
133262306a36Sopenharmony_ci *
133362306a36Sopenharmony_ci * Set VF's link state, irrespective of physical link state status
133462306a36Sopenharmony_ci */
133562306a36Sopenharmony_ciint ice_set_vf_link_state(struct net_device *netdev, int vf_id, int link_state)
133662306a36Sopenharmony_ci{
133762306a36Sopenharmony_ci	struct ice_pf *pf = ice_netdev_to_pf(netdev);
133862306a36Sopenharmony_ci	struct ice_vf *vf;
133962306a36Sopenharmony_ci	int ret;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	vf = ice_get_vf_by_id(pf, vf_id);
134262306a36Sopenharmony_ci	if (!vf)
134362306a36Sopenharmony_ci		return -EINVAL;
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci	ret = ice_check_vf_ready_for_cfg(vf);
134662306a36Sopenharmony_ci	if (ret)
134762306a36Sopenharmony_ci		goto out_put_vf;
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	switch (link_state) {
135062306a36Sopenharmony_ci	case IFLA_VF_LINK_STATE_AUTO:
135162306a36Sopenharmony_ci		vf->link_forced = false;
135262306a36Sopenharmony_ci		break;
135362306a36Sopenharmony_ci	case IFLA_VF_LINK_STATE_ENABLE:
135462306a36Sopenharmony_ci		vf->link_forced = true;
135562306a36Sopenharmony_ci		vf->link_up = true;
135662306a36Sopenharmony_ci		break;
135762306a36Sopenharmony_ci	case IFLA_VF_LINK_STATE_DISABLE:
135862306a36Sopenharmony_ci		vf->link_forced = true;
135962306a36Sopenharmony_ci		vf->link_up = false;
136062306a36Sopenharmony_ci		break;
136162306a36Sopenharmony_ci	default:
136262306a36Sopenharmony_ci		ret = -EINVAL;
136362306a36Sopenharmony_ci		goto out_put_vf;
136462306a36Sopenharmony_ci	}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	ice_vc_notify_vf_link_state(vf);
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ciout_put_vf:
136962306a36Sopenharmony_ci	ice_put_vf(vf);
137062306a36Sopenharmony_ci	return ret;
137162306a36Sopenharmony_ci}
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci/**
137462306a36Sopenharmony_ci * ice_calc_all_vfs_min_tx_rate - calculate cumulative min Tx rate on all VFs
137562306a36Sopenharmony_ci * @pf: PF associated with VFs
137662306a36Sopenharmony_ci */
137762306a36Sopenharmony_cistatic int ice_calc_all_vfs_min_tx_rate(struct ice_pf *pf)
137862306a36Sopenharmony_ci{
137962306a36Sopenharmony_ci	struct ice_vf *vf;
138062306a36Sopenharmony_ci	unsigned int bkt;
138162306a36Sopenharmony_ci	int rate = 0;
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	rcu_read_lock();
138462306a36Sopenharmony_ci	ice_for_each_vf_rcu(pf, bkt, vf)
138562306a36Sopenharmony_ci		rate += vf->min_tx_rate;
138662306a36Sopenharmony_ci	rcu_read_unlock();
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	return rate;
138962306a36Sopenharmony_ci}
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci/**
139262306a36Sopenharmony_ci * ice_min_tx_rate_oversubscribed - check if min Tx rate causes oversubscription
139362306a36Sopenharmony_ci * @vf: VF trying to configure min_tx_rate
139462306a36Sopenharmony_ci * @min_tx_rate: min Tx rate in Mbps
139562306a36Sopenharmony_ci *
139662306a36Sopenharmony_ci * Check if the min_tx_rate being passed in will cause oversubscription of total
139762306a36Sopenharmony_ci * min_tx_rate based on the current link speed and all other VFs configured
139862306a36Sopenharmony_ci * min_tx_rate
139962306a36Sopenharmony_ci *
140062306a36Sopenharmony_ci * Return true if the passed min_tx_rate would cause oversubscription, else
140162306a36Sopenharmony_ci * return false
140262306a36Sopenharmony_ci */
140362306a36Sopenharmony_cistatic bool
140462306a36Sopenharmony_ciice_min_tx_rate_oversubscribed(struct ice_vf *vf, int min_tx_rate)
140562306a36Sopenharmony_ci{
140662306a36Sopenharmony_ci	struct ice_vsi *vsi = ice_get_vf_vsi(vf);
140762306a36Sopenharmony_ci	int all_vfs_min_tx_rate;
140862306a36Sopenharmony_ci	int link_speed_mbps;
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	if (WARN_ON(!vsi))
141162306a36Sopenharmony_ci		return false;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	link_speed_mbps = ice_get_link_speed_mbps(vsi);
141462306a36Sopenharmony_ci	all_vfs_min_tx_rate = ice_calc_all_vfs_min_tx_rate(vf->pf);
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	/* this VF's previous rate is being overwritten */
141762306a36Sopenharmony_ci	all_vfs_min_tx_rate -= vf->min_tx_rate;
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci	if (all_vfs_min_tx_rate + min_tx_rate > link_speed_mbps) {
142062306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(vf->pf), "min_tx_rate of %d Mbps on VF %u would cause oversubscription of %d Mbps based on the current link speed %d Mbps\n",
142162306a36Sopenharmony_ci			min_tx_rate, vf->vf_id,
142262306a36Sopenharmony_ci			all_vfs_min_tx_rate + min_tx_rate - link_speed_mbps,
142362306a36Sopenharmony_ci			link_speed_mbps);
142462306a36Sopenharmony_ci		return true;
142562306a36Sopenharmony_ci	}
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	return false;
142862306a36Sopenharmony_ci}
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci/**
143162306a36Sopenharmony_ci * ice_set_vf_bw - set min/max VF bandwidth
143262306a36Sopenharmony_ci * @netdev: network interface device structure
143362306a36Sopenharmony_ci * @vf_id: VF identifier
143462306a36Sopenharmony_ci * @min_tx_rate: Minimum Tx rate in Mbps
143562306a36Sopenharmony_ci * @max_tx_rate: Maximum Tx rate in Mbps
143662306a36Sopenharmony_ci */
143762306a36Sopenharmony_ciint
143862306a36Sopenharmony_ciice_set_vf_bw(struct net_device *netdev, int vf_id, int min_tx_rate,
143962306a36Sopenharmony_ci	      int max_tx_rate)
144062306a36Sopenharmony_ci{
144162306a36Sopenharmony_ci	struct ice_pf *pf = ice_netdev_to_pf(netdev);
144262306a36Sopenharmony_ci	struct ice_vsi *vsi;
144362306a36Sopenharmony_ci	struct device *dev;
144462306a36Sopenharmony_ci	struct ice_vf *vf;
144562306a36Sopenharmony_ci	int ret;
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	vf = ice_get_vf_by_id(pf, vf_id);
145062306a36Sopenharmony_ci	if (!vf)
145162306a36Sopenharmony_ci		return -EINVAL;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	ret = ice_check_vf_ready_for_cfg(vf);
145462306a36Sopenharmony_ci	if (ret)
145562306a36Sopenharmony_ci		goto out_put_vf;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	vsi = ice_get_vf_vsi(vf);
145862306a36Sopenharmony_ci	if (!vsi) {
145962306a36Sopenharmony_ci		ret = -EINVAL;
146062306a36Sopenharmony_ci		goto out_put_vf;
146162306a36Sopenharmony_ci	}
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	if (min_tx_rate && ice_is_dcb_active(pf)) {
146462306a36Sopenharmony_ci		dev_err(dev, "DCB on PF is currently enabled. VF min Tx rate limiting not allowed on this PF.\n");
146562306a36Sopenharmony_ci		ret = -EOPNOTSUPP;
146662306a36Sopenharmony_ci		goto out_put_vf;
146762306a36Sopenharmony_ci	}
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	if (ice_min_tx_rate_oversubscribed(vf, min_tx_rate)) {
147062306a36Sopenharmony_ci		ret = -EINVAL;
147162306a36Sopenharmony_ci		goto out_put_vf;
147262306a36Sopenharmony_ci	}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	if (vf->min_tx_rate != (unsigned int)min_tx_rate) {
147562306a36Sopenharmony_ci		ret = ice_set_min_bw_limit(vsi, (u64)min_tx_rate * 1000);
147662306a36Sopenharmony_ci		if (ret) {
147762306a36Sopenharmony_ci			dev_err(dev, "Unable to set min-tx-rate for VF %d\n",
147862306a36Sopenharmony_ci				vf->vf_id);
147962306a36Sopenharmony_ci			goto out_put_vf;
148062306a36Sopenharmony_ci		}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci		vf->min_tx_rate = min_tx_rate;
148362306a36Sopenharmony_ci	}
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	if (vf->max_tx_rate != (unsigned int)max_tx_rate) {
148662306a36Sopenharmony_ci		ret = ice_set_max_bw_limit(vsi, (u64)max_tx_rate * 1000);
148762306a36Sopenharmony_ci		if (ret) {
148862306a36Sopenharmony_ci			dev_err(dev, "Unable to set max-tx-rate for VF %d\n",
148962306a36Sopenharmony_ci				vf->vf_id);
149062306a36Sopenharmony_ci			goto out_put_vf;
149162306a36Sopenharmony_ci		}
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci		vf->max_tx_rate = max_tx_rate;
149462306a36Sopenharmony_ci	}
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ciout_put_vf:
149762306a36Sopenharmony_ci	ice_put_vf(vf);
149862306a36Sopenharmony_ci	return ret;
149962306a36Sopenharmony_ci}
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci/**
150262306a36Sopenharmony_ci * ice_get_vf_stats - populate some stats for the VF
150362306a36Sopenharmony_ci * @netdev: the netdev of the PF
150462306a36Sopenharmony_ci * @vf_id: the host OS identifier (0-255)
150562306a36Sopenharmony_ci * @vf_stats: pointer to the OS memory to be initialized
150662306a36Sopenharmony_ci */
150762306a36Sopenharmony_ciint ice_get_vf_stats(struct net_device *netdev, int vf_id,
150862306a36Sopenharmony_ci		     struct ifla_vf_stats *vf_stats)
150962306a36Sopenharmony_ci{
151062306a36Sopenharmony_ci	struct ice_pf *pf = ice_netdev_to_pf(netdev);
151162306a36Sopenharmony_ci	struct ice_eth_stats *stats;
151262306a36Sopenharmony_ci	struct ice_vsi *vsi;
151362306a36Sopenharmony_ci	struct ice_vf *vf;
151462306a36Sopenharmony_ci	int ret;
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	vf = ice_get_vf_by_id(pf, vf_id);
151762306a36Sopenharmony_ci	if (!vf)
151862306a36Sopenharmony_ci		return -EINVAL;
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	ret = ice_check_vf_ready_for_cfg(vf);
152162306a36Sopenharmony_ci	if (ret)
152262306a36Sopenharmony_ci		goto out_put_vf;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	vsi = ice_get_vf_vsi(vf);
152562306a36Sopenharmony_ci	if (!vsi) {
152662306a36Sopenharmony_ci		ret = -EINVAL;
152762306a36Sopenharmony_ci		goto out_put_vf;
152862306a36Sopenharmony_ci	}
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	ice_update_eth_stats(vsi);
153162306a36Sopenharmony_ci	stats = &vsi->eth_stats;
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	memset(vf_stats, 0, sizeof(*vf_stats));
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci	vf_stats->rx_packets = stats->rx_unicast + stats->rx_broadcast +
153662306a36Sopenharmony_ci		stats->rx_multicast;
153762306a36Sopenharmony_ci	vf_stats->tx_packets = stats->tx_unicast + stats->tx_broadcast +
153862306a36Sopenharmony_ci		stats->tx_multicast;
153962306a36Sopenharmony_ci	vf_stats->rx_bytes   = stats->rx_bytes;
154062306a36Sopenharmony_ci	vf_stats->tx_bytes   = stats->tx_bytes;
154162306a36Sopenharmony_ci	vf_stats->broadcast  = stats->rx_broadcast;
154262306a36Sopenharmony_ci	vf_stats->multicast  = stats->rx_multicast;
154362306a36Sopenharmony_ci	vf_stats->rx_dropped = stats->rx_discards;
154462306a36Sopenharmony_ci	vf_stats->tx_dropped = stats->tx_discards;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ciout_put_vf:
154762306a36Sopenharmony_ci	ice_put_vf(vf);
154862306a36Sopenharmony_ci	return ret;
154962306a36Sopenharmony_ci}
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci/**
155262306a36Sopenharmony_ci * ice_is_supported_port_vlan_proto - make sure the vlan_proto is supported
155362306a36Sopenharmony_ci * @hw: hardware structure used to check the VLAN mode
155462306a36Sopenharmony_ci * @vlan_proto: VLAN TPID being checked
155562306a36Sopenharmony_ci *
155662306a36Sopenharmony_ci * If the device is configured in Double VLAN Mode (DVM), then both ETH_P_8021Q
155762306a36Sopenharmony_ci * and ETH_P_8021AD are supported. If the device is configured in Single VLAN
155862306a36Sopenharmony_ci * Mode (SVM), then only ETH_P_8021Q is supported.
155962306a36Sopenharmony_ci */
156062306a36Sopenharmony_cistatic bool
156162306a36Sopenharmony_ciice_is_supported_port_vlan_proto(struct ice_hw *hw, u16 vlan_proto)
156262306a36Sopenharmony_ci{
156362306a36Sopenharmony_ci	bool is_supported = false;
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	switch (vlan_proto) {
156662306a36Sopenharmony_ci	case ETH_P_8021Q:
156762306a36Sopenharmony_ci		is_supported = true;
156862306a36Sopenharmony_ci		break;
156962306a36Sopenharmony_ci	case ETH_P_8021AD:
157062306a36Sopenharmony_ci		if (ice_is_dvm_ena(hw))
157162306a36Sopenharmony_ci			is_supported = true;
157262306a36Sopenharmony_ci		break;
157362306a36Sopenharmony_ci	}
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	return is_supported;
157662306a36Sopenharmony_ci}
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci/**
157962306a36Sopenharmony_ci * ice_set_vf_port_vlan
158062306a36Sopenharmony_ci * @netdev: network interface device structure
158162306a36Sopenharmony_ci * @vf_id: VF identifier
158262306a36Sopenharmony_ci * @vlan_id: VLAN ID being set
158362306a36Sopenharmony_ci * @qos: priority setting
158462306a36Sopenharmony_ci * @vlan_proto: VLAN protocol
158562306a36Sopenharmony_ci *
158662306a36Sopenharmony_ci * program VF Port VLAN ID and/or QoS
158762306a36Sopenharmony_ci */
158862306a36Sopenharmony_ciint
158962306a36Sopenharmony_ciice_set_vf_port_vlan(struct net_device *netdev, int vf_id, u16 vlan_id, u8 qos,
159062306a36Sopenharmony_ci		     __be16 vlan_proto)
159162306a36Sopenharmony_ci{
159262306a36Sopenharmony_ci	struct ice_pf *pf = ice_netdev_to_pf(netdev);
159362306a36Sopenharmony_ci	u16 local_vlan_proto = ntohs(vlan_proto);
159462306a36Sopenharmony_ci	struct device *dev;
159562306a36Sopenharmony_ci	struct ice_vf *vf;
159662306a36Sopenharmony_ci	int ret;
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	if (vlan_id >= VLAN_N_VID || qos > 7) {
160162306a36Sopenharmony_ci		dev_err(dev, "Invalid Port VLAN parameters for VF %d, ID %d, QoS %d\n",
160262306a36Sopenharmony_ci			vf_id, vlan_id, qos);
160362306a36Sopenharmony_ci		return -EINVAL;
160462306a36Sopenharmony_ci	}
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	if (!ice_is_supported_port_vlan_proto(&pf->hw, local_vlan_proto)) {
160762306a36Sopenharmony_ci		dev_err(dev, "VF VLAN protocol 0x%04x is not supported\n",
160862306a36Sopenharmony_ci			local_vlan_proto);
160962306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
161062306a36Sopenharmony_ci	}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	vf = ice_get_vf_by_id(pf, vf_id);
161362306a36Sopenharmony_ci	if (!vf)
161462306a36Sopenharmony_ci		return -EINVAL;
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	ret = ice_check_vf_ready_for_cfg(vf);
161762306a36Sopenharmony_ci	if (ret)
161862306a36Sopenharmony_ci		goto out_put_vf;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	if (ice_vf_get_port_vlan_prio(vf) == qos &&
162162306a36Sopenharmony_ci	    ice_vf_get_port_vlan_tpid(vf) == local_vlan_proto &&
162262306a36Sopenharmony_ci	    ice_vf_get_port_vlan_id(vf) == vlan_id) {
162362306a36Sopenharmony_ci		/* duplicate request, so just return success */
162462306a36Sopenharmony_ci		dev_dbg(dev, "Duplicate port VLAN %u, QoS %u, TPID 0x%04x request\n",
162562306a36Sopenharmony_ci			vlan_id, qos, local_vlan_proto);
162662306a36Sopenharmony_ci		ret = 0;
162762306a36Sopenharmony_ci		goto out_put_vf;
162862306a36Sopenharmony_ci	}
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci	mutex_lock(&vf->cfg_lock);
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	vf->port_vlan_info = ICE_VLAN(local_vlan_proto, vlan_id, qos);
163362306a36Sopenharmony_ci	if (ice_vf_is_port_vlan_ena(vf))
163462306a36Sopenharmony_ci		dev_info(dev, "Setting VLAN %u, QoS %u, TPID 0x%04x on VF %d\n",
163562306a36Sopenharmony_ci			 vlan_id, qos, local_vlan_proto, vf_id);
163662306a36Sopenharmony_ci	else
163762306a36Sopenharmony_ci		dev_info(dev, "Clearing port VLAN on VF %d\n", vf_id);
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	ice_reset_vf(vf, ICE_VF_RESET_NOTIFY);
164062306a36Sopenharmony_ci	mutex_unlock(&vf->cfg_lock);
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ciout_put_vf:
164362306a36Sopenharmony_ci	ice_put_vf(vf);
164462306a36Sopenharmony_ci	return ret;
164562306a36Sopenharmony_ci}
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci/**
164862306a36Sopenharmony_ci * ice_print_vf_rx_mdd_event - print VF Rx malicious driver detect event
164962306a36Sopenharmony_ci * @vf: pointer to the VF structure
165062306a36Sopenharmony_ci */
165162306a36Sopenharmony_civoid ice_print_vf_rx_mdd_event(struct ice_vf *vf)
165262306a36Sopenharmony_ci{
165362306a36Sopenharmony_ci	struct ice_pf *pf = vf->pf;
165462306a36Sopenharmony_ci	struct device *dev;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	dev_info(dev, "%d Rx Malicious Driver Detection events detected on PF %d VF %d MAC %pM. mdd-auto-reset-vfs=%s\n",
165962306a36Sopenharmony_ci		 vf->mdd_rx_events.count, pf->hw.pf_id, vf->vf_id,
166062306a36Sopenharmony_ci		 vf->dev_lan_addr,
166162306a36Sopenharmony_ci		 test_bit(ICE_FLAG_MDD_AUTO_RESET_VF, pf->flags)
166262306a36Sopenharmony_ci			  ? "on" : "off");
166362306a36Sopenharmony_ci}
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci/**
166662306a36Sopenharmony_ci * ice_print_vfs_mdd_events - print VFs malicious driver detect event
166762306a36Sopenharmony_ci * @pf: pointer to the PF structure
166862306a36Sopenharmony_ci *
166962306a36Sopenharmony_ci * Called from ice_handle_mdd_event to rate limit and print VFs MDD events.
167062306a36Sopenharmony_ci */
167162306a36Sopenharmony_civoid ice_print_vfs_mdd_events(struct ice_pf *pf)
167262306a36Sopenharmony_ci{
167362306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
167462306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
167562306a36Sopenharmony_ci	struct ice_vf *vf;
167662306a36Sopenharmony_ci	unsigned int bkt;
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	/* check that there are pending MDD events to print */
167962306a36Sopenharmony_ci	if (!test_and_clear_bit(ICE_MDD_VF_PRINT_PENDING, pf->state))
168062306a36Sopenharmony_ci		return;
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	/* VF MDD event logs are rate limited to one second intervals */
168362306a36Sopenharmony_ci	if (time_is_after_jiffies(pf->vfs.last_printed_mdd_jiffies + HZ * 1))
168462306a36Sopenharmony_ci		return;
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	pf->vfs.last_printed_mdd_jiffies = jiffies;
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	mutex_lock(&pf->vfs.table_lock);
168962306a36Sopenharmony_ci	ice_for_each_vf(pf, bkt, vf) {
169062306a36Sopenharmony_ci		/* only print Rx MDD event message if there are new events */
169162306a36Sopenharmony_ci		if (vf->mdd_rx_events.count != vf->mdd_rx_events.last_printed) {
169262306a36Sopenharmony_ci			vf->mdd_rx_events.last_printed =
169362306a36Sopenharmony_ci							vf->mdd_rx_events.count;
169462306a36Sopenharmony_ci			ice_print_vf_rx_mdd_event(vf);
169562306a36Sopenharmony_ci		}
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci		/* only print Tx MDD event message if there are new events */
169862306a36Sopenharmony_ci		if (vf->mdd_tx_events.count != vf->mdd_tx_events.last_printed) {
169962306a36Sopenharmony_ci			vf->mdd_tx_events.last_printed =
170062306a36Sopenharmony_ci							vf->mdd_tx_events.count;
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci			dev_info(dev, "%d Tx Malicious Driver Detection events detected on PF %d VF %d MAC %pM.\n",
170362306a36Sopenharmony_ci				 vf->mdd_tx_events.count, hw->pf_id, vf->vf_id,
170462306a36Sopenharmony_ci				 vf->dev_lan_addr);
170562306a36Sopenharmony_ci		}
170662306a36Sopenharmony_ci	}
170762306a36Sopenharmony_ci	mutex_unlock(&pf->vfs.table_lock);
170862306a36Sopenharmony_ci}
170962306a36Sopenharmony_ci
171062306a36Sopenharmony_ci/**
171162306a36Sopenharmony_ci * ice_restore_all_vfs_msi_state - restore VF MSI state after PF FLR
171262306a36Sopenharmony_ci * @pdev: pointer to a pci_dev structure
171362306a36Sopenharmony_ci *
171462306a36Sopenharmony_ci * Called when recovering from a PF FLR to restore interrupt capability to
171562306a36Sopenharmony_ci * the VFs.
171662306a36Sopenharmony_ci */
171762306a36Sopenharmony_civoid ice_restore_all_vfs_msi_state(struct pci_dev *pdev)
171862306a36Sopenharmony_ci{
171962306a36Sopenharmony_ci	u16 vf_id;
172062306a36Sopenharmony_ci	int pos;
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	if (!pci_num_vf(pdev))
172362306a36Sopenharmony_ci		return;
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
172662306a36Sopenharmony_ci	if (pos) {
172762306a36Sopenharmony_ci		struct pci_dev *vfdev;
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci		pci_read_config_word(pdev, pos + PCI_SRIOV_VF_DID,
173062306a36Sopenharmony_ci				     &vf_id);
173162306a36Sopenharmony_ci		vfdev = pci_get_device(pdev->vendor, vf_id, NULL);
173262306a36Sopenharmony_ci		while (vfdev) {
173362306a36Sopenharmony_ci			if (vfdev->is_virtfn && vfdev->physfn == pdev)
173462306a36Sopenharmony_ci				pci_restore_msi_state(vfdev);
173562306a36Sopenharmony_ci			vfdev = pci_get_device(pdev->vendor, vf_id,
173662306a36Sopenharmony_ci					       vfdev);
173762306a36Sopenharmony_ci		}
173862306a36Sopenharmony_ci	}
173962306a36Sopenharmony_ci}
1740