18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright(c) 2013 - 2019 Intel Corporation. */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include "fm10k.h"
58c2ecf20Sopenharmony_ci#include "fm10k_vf.h"
68c2ecf20Sopenharmony_ci#include "fm10k_pf.h"
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_cistatic s32 fm10k_iov_msg_error(struct fm10k_hw *hw, u32 **results,
98c2ecf20Sopenharmony_ci			       struct fm10k_mbx_info *mbx)
108c2ecf20Sopenharmony_ci{
118c2ecf20Sopenharmony_ci	struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx;
128c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = hw->back;
138c2ecf20Sopenharmony_ci	struct pci_dev *pdev = interface->pdev;
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci	dev_err(&pdev->dev, "Unknown message ID %u on VF %d\n",
168c2ecf20Sopenharmony_ci		**results & FM10K_TLV_ID_MASK, vf_info->vf_idx);
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	return fm10k_tlv_msg_error(hw, results, mbx);
198c2ecf20Sopenharmony_ci}
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/**
228c2ecf20Sopenharmony_ci *  fm10k_iov_msg_queue_mac_vlan - Message handler for MAC/VLAN request from VF
238c2ecf20Sopenharmony_ci *  @hw: Pointer to hardware structure
248c2ecf20Sopenharmony_ci *  @results: Pointer array to message, results[0] is pointer to message
258c2ecf20Sopenharmony_ci *  @mbx: Pointer to mailbox information structure
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci *  This function is a custom handler for MAC/VLAN requests from the VF. The
288c2ecf20Sopenharmony_ci *  assumption is that it is acceptable to directly hand off the message from
298c2ecf20Sopenharmony_ci *  the VF to the PF's switch manager. However, we use a MAC/VLAN message
308c2ecf20Sopenharmony_ci *  queue to avoid overloading the mailbox when a large number of requests
318c2ecf20Sopenharmony_ci *  come in.
328c2ecf20Sopenharmony_ci **/
338c2ecf20Sopenharmony_cistatic s32 fm10k_iov_msg_queue_mac_vlan(struct fm10k_hw *hw, u32 **results,
348c2ecf20Sopenharmony_ci					struct fm10k_mbx_info *mbx)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx;
378c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = hw->back;
388c2ecf20Sopenharmony_ci	u8 mac[ETH_ALEN];
398c2ecf20Sopenharmony_ci	u32 *result;
408c2ecf20Sopenharmony_ci	int err = 0;
418c2ecf20Sopenharmony_ci	bool set;
428c2ecf20Sopenharmony_ci	u16 vlan;
438c2ecf20Sopenharmony_ci	u32 vid;
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	/* we shouldn't be updating rules on a disabled interface */
468c2ecf20Sopenharmony_ci	if (!FM10K_VF_FLAG_ENABLED(vf_info))
478c2ecf20Sopenharmony_ci		err = FM10K_ERR_PARAM;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	if (!err && !!results[FM10K_MAC_VLAN_MSG_VLAN]) {
508c2ecf20Sopenharmony_ci		result = results[FM10K_MAC_VLAN_MSG_VLAN];
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci		/* record VLAN id requested */
538c2ecf20Sopenharmony_ci		err = fm10k_tlv_attr_get_u32(result, &vid);
548c2ecf20Sopenharmony_ci		if (err)
558c2ecf20Sopenharmony_ci			return err;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci		set = !(vid & FM10K_VLAN_CLEAR);
588c2ecf20Sopenharmony_ci		vid &= ~FM10K_VLAN_CLEAR;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci		/* if the length field has been set, this is a multi-bit
618c2ecf20Sopenharmony_ci		 * update request. For multi-bit requests, simply disallow
628c2ecf20Sopenharmony_ci		 * them when the pf_vid has been set. In this case, the PF
638c2ecf20Sopenharmony_ci		 * should have already cleared the VLAN_TABLE, and if we
648c2ecf20Sopenharmony_ci		 * allowed them, it could allow a rogue VF to receive traffic
658c2ecf20Sopenharmony_ci		 * on a VLAN it was not assigned. In the single-bit case, we
668c2ecf20Sopenharmony_ci		 * need to modify requests for VLAN 0 to use the default PF or
678c2ecf20Sopenharmony_ci		 * SW vid when assigned.
688c2ecf20Sopenharmony_ci		 */
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci		if (vid >> 16) {
718c2ecf20Sopenharmony_ci			/* prevent multi-bit requests when PF has
728c2ecf20Sopenharmony_ci			 * administratively set the VLAN for this VF
738c2ecf20Sopenharmony_ci			 */
748c2ecf20Sopenharmony_ci			if (vf_info->pf_vid)
758c2ecf20Sopenharmony_ci				return FM10K_ERR_PARAM;
768c2ecf20Sopenharmony_ci		} else {
778c2ecf20Sopenharmony_ci			err = fm10k_iov_select_vid(vf_info, (u16)vid);
788c2ecf20Sopenharmony_ci			if (err < 0)
798c2ecf20Sopenharmony_ci				return err;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci			vid = err;
828c2ecf20Sopenharmony_ci		}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci		/* update VSI info for VF in regards to VLAN table */
858c2ecf20Sopenharmony_ci		err = hw->mac.ops.update_vlan(hw, vid, vf_info->vsi, set);
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	if (!err && !!results[FM10K_MAC_VLAN_MSG_MAC]) {
898c2ecf20Sopenharmony_ci		result = results[FM10K_MAC_VLAN_MSG_MAC];
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci		/* record unicast MAC address requested */
928c2ecf20Sopenharmony_ci		err = fm10k_tlv_attr_get_mac_vlan(result, mac, &vlan);
938c2ecf20Sopenharmony_ci		if (err)
948c2ecf20Sopenharmony_ci			return err;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci		/* block attempts to set MAC for a locked device */
978c2ecf20Sopenharmony_ci		if (is_valid_ether_addr(vf_info->mac) &&
988c2ecf20Sopenharmony_ci		    !ether_addr_equal(mac, vf_info->mac))
998c2ecf20Sopenharmony_ci			return FM10K_ERR_PARAM;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci		set = !(vlan & FM10K_VLAN_CLEAR);
1028c2ecf20Sopenharmony_ci		vlan &= ~FM10K_VLAN_CLEAR;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci		err = fm10k_iov_select_vid(vf_info, vlan);
1058c2ecf20Sopenharmony_ci		if (err < 0)
1068c2ecf20Sopenharmony_ci			return err;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci		vlan = (u16)err;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci		/* Add this request to the MAC/VLAN queue */
1118c2ecf20Sopenharmony_ci		err = fm10k_queue_mac_request(interface, vf_info->glort,
1128c2ecf20Sopenharmony_ci					      mac, vlan, set);
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	if (!err && !!results[FM10K_MAC_VLAN_MSG_MULTICAST]) {
1168c2ecf20Sopenharmony_ci		result = results[FM10K_MAC_VLAN_MSG_MULTICAST];
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		/* record multicast MAC address requested */
1198c2ecf20Sopenharmony_ci		err = fm10k_tlv_attr_get_mac_vlan(result, mac, &vlan);
1208c2ecf20Sopenharmony_ci		if (err)
1218c2ecf20Sopenharmony_ci			return err;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci		/* verify that the VF is allowed to request multicast */
1248c2ecf20Sopenharmony_ci		if (!(vf_info->vf_flags & FM10K_VF_FLAG_MULTI_ENABLED))
1258c2ecf20Sopenharmony_ci			return FM10K_ERR_PARAM;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci		set = !(vlan & FM10K_VLAN_CLEAR);
1288c2ecf20Sopenharmony_ci		vlan &= ~FM10K_VLAN_CLEAR;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci		err = fm10k_iov_select_vid(vf_info, vlan);
1318c2ecf20Sopenharmony_ci		if (err < 0)
1328c2ecf20Sopenharmony_ci			return err;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci		vlan = (u16)err;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci		/* Add this request to the MAC/VLAN queue */
1378c2ecf20Sopenharmony_ci		err = fm10k_queue_mac_request(interface, vf_info->glort,
1388c2ecf20Sopenharmony_ci					      mac, vlan, set);
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	return err;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic const struct fm10k_msg_data iov_mbx_data[] = {
1458c2ecf20Sopenharmony_ci	FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test),
1468c2ecf20Sopenharmony_ci	FM10K_VF_MSG_MSIX_HANDLER(fm10k_iov_msg_msix_pf),
1478c2ecf20Sopenharmony_ci	FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_iov_msg_queue_mac_vlan),
1488c2ecf20Sopenharmony_ci	FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_iov_msg_lport_state_pf),
1498c2ecf20Sopenharmony_ci	FM10K_TLV_MSG_ERROR_HANDLER(fm10k_iov_msg_error),
1508c2ecf20Sopenharmony_ci};
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cis32 fm10k_iov_event(struct fm10k_intfc *interface)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
1558c2ecf20Sopenharmony_ci	struct fm10k_iov_data *iov_data;
1568c2ecf20Sopenharmony_ci	s64 vflre;
1578c2ecf20Sopenharmony_ci	int i;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/* if there is no iov_data then there is no mailbox to process */
1608c2ecf20Sopenharmony_ci	if (!READ_ONCE(interface->iov_data))
1618c2ecf20Sopenharmony_ci		return 0;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	rcu_read_lock();
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	iov_data = interface->iov_data;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	/* check again now that we are in the RCU block */
1688c2ecf20Sopenharmony_ci	if (!iov_data)
1698c2ecf20Sopenharmony_ci		goto read_unlock;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (!(fm10k_read_reg(hw, FM10K_EICR) & FM10K_EICR_VFLR))
1728c2ecf20Sopenharmony_ci		goto read_unlock;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	/* read VFLRE to determine if any VFs have been reset */
1758c2ecf20Sopenharmony_ci	vflre = fm10k_read_reg(hw, FM10K_PFVFLRE(1));
1768c2ecf20Sopenharmony_ci	vflre <<= 32;
1778c2ecf20Sopenharmony_ci	vflre |= fm10k_read_reg(hw, FM10K_PFVFLRE(0));
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	i = iov_data->num_vfs;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	for (vflre <<= 64 - i; vflre && i--; vflre += vflre) {
1828c2ecf20Sopenharmony_ci		struct fm10k_vf_info *vf_info = &iov_data->vf_info[i];
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci		if (vflre >= 0)
1858c2ecf20Sopenharmony_ci			continue;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci		hw->iov.ops.reset_resources(hw, vf_info);
1888c2ecf20Sopenharmony_ci		vf_info->mbx.ops.connect(hw, &vf_info->mbx);
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ciread_unlock:
1928c2ecf20Sopenharmony_ci	rcu_read_unlock();
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	return 0;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cis32 fm10k_iov_mbx(struct fm10k_intfc *interface)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
2008c2ecf20Sopenharmony_ci	struct fm10k_iov_data *iov_data;
2018c2ecf20Sopenharmony_ci	int i;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	/* if there is no iov_data then there is no mailbox to process */
2048c2ecf20Sopenharmony_ci	if (!READ_ONCE(interface->iov_data))
2058c2ecf20Sopenharmony_ci		return 0;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	rcu_read_lock();
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	iov_data = interface->iov_data;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/* check again now that we are in the RCU block */
2128c2ecf20Sopenharmony_ci	if (!iov_data)
2138c2ecf20Sopenharmony_ci		goto read_unlock;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	/* lock the mailbox for transmit and receive */
2168c2ecf20Sopenharmony_ci	fm10k_mbx_lock(interface);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	/* Most VF messages sent to the PF cause the PF to respond by
2198c2ecf20Sopenharmony_ci	 * requesting from the SM mailbox. This means that too many VF
2208c2ecf20Sopenharmony_ci	 * messages processed at once could cause a mailbox timeout on the PF.
2218c2ecf20Sopenharmony_ci	 * To prevent this, store a pointer to the next VF mbx to process. Use
2228c2ecf20Sopenharmony_ci	 * that as the start of the loop so that we don't starve whichever VF
2238c2ecf20Sopenharmony_ci	 * got ignored on the previous run.
2248c2ecf20Sopenharmony_ci	 */
2258c2ecf20Sopenharmony_ciprocess_mbx:
2268c2ecf20Sopenharmony_ci	for (i = iov_data->next_vf_mbx ? : iov_data->num_vfs; i--;) {
2278c2ecf20Sopenharmony_ci		struct fm10k_vf_info *vf_info = &iov_data->vf_info[i];
2288c2ecf20Sopenharmony_ci		struct fm10k_mbx_info *mbx = &vf_info->mbx;
2298c2ecf20Sopenharmony_ci		u16 glort = vf_info->glort;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci		/* process the SM mailbox first to drain outgoing messages */
2328c2ecf20Sopenharmony_ci		hw->mbx.ops.process(hw, &hw->mbx);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci		/* verify port mapping is valid, if not reset port */
2358c2ecf20Sopenharmony_ci		if (vf_info->vf_flags && !fm10k_glort_valid_pf(hw, glort)) {
2368c2ecf20Sopenharmony_ci			hw->iov.ops.reset_lport(hw, vf_info);
2378c2ecf20Sopenharmony_ci			fm10k_clear_macvlan_queue(interface, glort, false);
2388c2ecf20Sopenharmony_ci		}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci		/* reset VFs that have mailbox timed out */
2418c2ecf20Sopenharmony_ci		if (!mbx->timeout) {
2428c2ecf20Sopenharmony_ci			hw->iov.ops.reset_resources(hw, vf_info);
2438c2ecf20Sopenharmony_ci			mbx->ops.connect(hw, mbx);
2448c2ecf20Sopenharmony_ci		}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci		/* guarantee we have free space in the SM mailbox */
2478c2ecf20Sopenharmony_ci		if (hw->mbx.state == FM10K_STATE_OPEN &&
2488c2ecf20Sopenharmony_ci		    !hw->mbx.ops.tx_ready(&hw->mbx, FM10K_VFMBX_MSG_MTU)) {
2498c2ecf20Sopenharmony_ci			/* keep track of how many times this occurs */
2508c2ecf20Sopenharmony_ci			interface->hw_sm_mbx_full++;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci			/* make sure we try again momentarily */
2538c2ecf20Sopenharmony_ci			fm10k_service_event_schedule(interface);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci			break;
2568c2ecf20Sopenharmony_ci		}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci		/* cleanup mailbox and process received messages */
2598c2ecf20Sopenharmony_ci		mbx->ops.process(hw, mbx);
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	/* if we stopped processing mailboxes early, update next_vf_mbx.
2638c2ecf20Sopenharmony_ci	 * Otherwise, reset next_vf_mbx, and restart loop so that we process
2648c2ecf20Sopenharmony_ci	 * the remaining mailboxes we skipped at the start.
2658c2ecf20Sopenharmony_ci	 */
2668c2ecf20Sopenharmony_ci	if (i >= 0) {
2678c2ecf20Sopenharmony_ci		iov_data->next_vf_mbx = i + 1;
2688c2ecf20Sopenharmony_ci	} else if (iov_data->next_vf_mbx) {
2698c2ecf20Sopenharmony_ci		iov_data->next_vf_mbx = 0;
2708c2ecf20Sopenharmony_ci		goto process_mbx;
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	/* free the lock */
2748c2ecf20Sopenharmony_ci	fm10k_mbx_unlock(interface);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ciread_unlock:
2778c2ecf20Sopenharmony_ci	rcu_read_unlock();
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	return 0;
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_civoid fm10k_iov_suspend(struct pci_dev *pdev)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = pci_get_drvdata(pdev);
2858c2ecf20Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
2868c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
2878c2ecf20Sopenharmony_ci	int num_vfs, i;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	/* pull out num_vfs from iov_data */
2908c2ecf20Sopenharmony_ci	num_vfs = iov_data ? iov_data->num_vfs : 0;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/* shut down queue mapping for VFs */
2938c2ecf20Sopenharmony_ci	fm10k_write_reg(hw, FM10K_DGLORTMAP(fm10k_dglort_vf_rss),
2948c2ecf20Sopenharmony_ci			FM10K_DGLORTMAP_NONE);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	/* Stop any active VFs and reset their resources */
2978c2ecf20Sopenharmony_ci	for (i = 0; i < num_vfs; i++) {
2988c2ecf20Sopenharmony_ci		struct fm10k_vf_info *vf_info = &iov_data->vf_info[i];
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci		hw->iov.ops.reset_resources(hw, vf_info);
3018c2ecf20Sopenharmony_ci		hw->iov.ops.reset_lport(hw, vf_info);
3028c2ecf20Sopenharmony_ci		fm10k_clear_macvlan_queue(interface, vf_info->glort, false);
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic void fm10k_mask_aer_comp_abort(struct pci_dev *pdev)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	u32 err_mask;
3098c2ecf20Sopenharmony_ci	int pos;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
3128c2ecf20Sopenharmony_ci	if (!pos)
3138c2ecf20Sopenharmony_ci		return;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	/* Mask the completion abort bit in the ERR_UNCOR_MASK register,
3168c2ecf20Sopenharmony_ci	 * preventing the device from reporting these errors to the upstream
3178c2ecf20Sopenharmony_ci	 * PCIe root device. This avoids bringing down platforms which upgrade
3188c2ecf20Sopenharmony_ci	 * non-fatal completer aborts into machine check exceptions. Completer
3198c2ecf20Sopenharmony_ci	 * aborts can occur whenever a VF reads a queue it doesn't own.
3208c2ecf20Sopenharmony_ci	 */
3218c2ecf20Sopenharmony_ci	pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_MASK, &err_mask);
3228c2ecf20Sopenharmony_ci	err_mask |= PCI_ERR_UNC_COMP_ABORT;
3238c2ecf20Sopenharmony_ci	pci_write_config_dword(pdev, pos + PCI_ERR_UNCOR_MASK, err_mask);
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ciint fm10k_iov_resume(struct pci_dev *pdev)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = pci_get_drvdata(pdev);
3298c2ecf20Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
3308c2ecf20Sopenharmony_ci	struct fm10k_dglort_cfg dglort = { 0 };
3318c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
3328c2ecf20Sopenharmony_ci	int num_vfs, i;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	/* pull out num_vfs from iov_data */
3358c2ecf20Sopenharmony_ci	num_vfs = iov_data ? iov_data->num_vfs : 0;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	/* return error if iov_data is not already populated */
3388c2ecf20Sopenharmony_ci	if (!iov_data)
3398c2ecf20Sopenharmony_ci		return -ENOMEM;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	/* Lower severity of completer abort error reporting as
3428c2ecf20Sopenharmony_ci	 * the VFs can trigger this any time they read a queue
3438c2ecf20Sopenharmony_ci	 * that they don't own.
3448c2ecf20Sopenharmony_ci	 */
3458c2ecf20Sopenharmony_ci	fm10k_mask_aer_comp_abort(pdev);
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	/* allocate hardware resources for the VFs */
3488c2ecf20Sopenharmony_ci	hw->iov.ops.assign_resources(hw, num_vfs, num_vfs);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	/* configure DGLORT mapping for RSS */
3518c2ecf20Sopenharmony_ci	dglort.glort = hw->mac.dglort_map & FM10K_DGLORTMAP_NONE;
3528c2ecf20Sopenharmony_ci	dglort.idx = fm10k_dglort_vf_rss;
3538c2ecf20Sopenharmony_ci	dglort.inner_rss = 1;
3548c2ecf20Sopenharmony_ci	dglort.rss_l = fls(fm10k_queues_per_pool(hw) - 1);
3558c2ecf20Sopenharmony_ci	dglort.queue_b = fm10k_vf_queue_index(hw, 0);
3568c2ecf20Sopenharmony_ci	dglort.vsi_l = fls(hw->iov.total_vfs - 1);
3578c2ecf20Sopenharmony_ci	dglort.vsi_b = 1;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	hw->mac.ops.configure_dglort_map(hw, &dglort);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	/* assign resources to the device */
3628c2ecf20Sopenharmony_ci	for (i = 0; i < num_vfs; i++) {
3638c2ecf20Sopenharmony_ci		struct fm10k_vf_info *vf_info = &iov_data->vf_info[i];
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci		/* allocate all but the last GLORT to the VFs */
3668c2ecf20Sopenharmony_ci		if (i == (~hw->mac.dglort_map >> FM10K_DGLORTMAP_MASK_SHIFT))
3678c2ecf20Sopenharmony_ci			break;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci		/* assign GLORT to VF, and restrict it to multicast */
3708c2ecf20Sopenharmony_ci		hw->iov.ops.set_lport(hw, vf_info, i,
3718c2ecf20Sopenharmony_ci				      FM10K_VF_FLAG_MULTI_CAPABLE);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci		/* mailbox is disconnected so we don't send a message */
3748c2ecf20Sopenharmony_ci		hw->iov.ops.assign_default_mac_vlan(hw, vf_info);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci		/* now we are ready so we can connect */
3778c2ecf20Sopenharmony_ci		vf_info->mbx.ops.connect(hw, &vf_info->mbx);
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	return 0;
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cis32 fm10k_iov_update_pvid(struct fm10k_intfc *interface, u16 glort, u16 pvid)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
3868c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
3878c2ecf20Sopenharmony_ci	struct fm10k_vf_info *vf_info;
3888c2ecf20Sopenharmony_ci	u16 vf_idx = (glort - hw->mac.dglort_map) & FM10K_DGLORTMAP_NONE;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	/* no IOV support, not our message to process */
3918c2ecf20Sopenharmony_ci	if (!iov_data)
3928c2ecf20Sopenharmony_ci		return FM10K_ERR_PARAM;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	/* glort outside our range, not our message to process */
3958c2ecf20Sopenharmony_ci	if (vf_idx >= iov_data->num_vfs)
3968c2ecf20Sopenharmony_ci		return FM10K_ERR_PARAM;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	/* determine if an update has occurred and if so notify the VF */
3998c2ecf20Sopenharmony_ci	vf_info = &iov_data->vf_info[vf_idx];
4008c2ecf20Sopenharmony_ci	if (vf_info->sw_vid != pvid) {
4018c2ecf20Sopenharmony_ci		vf_info->sw_vid = pvid;
4028c2ecf20Sopenharmony_ci		hw->iov.ops.assign_default_mac_vlan(hw, vf_info);
4038c2ecf20Sopenharmony_ci	}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	return 0;
4068c2ecf20Sopenharmony_ci}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_cistatic void fm10k_iov_free_data(struct pci_dev *pdev)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = pci_get_drvdata(pdev);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	if (!interface->iov_data)
4138c2ecf20Sopenharmony_ci		return;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	/* reclaim hardware resources */
4168c2ecf20Sopenharmony_ci	fm10k_iov_suspend(pdev);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	/* drop iov_data from interface */
4198c2ecf20Sopenharmony_ci	kfree_rcu(interface->iov_data, rcu);
4208c2ecf20Sopenharmony_ci	interface->iov_data = NULL;
4218c2ecf20Sopenharmony_ci}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_cistatic s32 fm10k_iov_alloc_data(struct pci_dev *pdev, int num_vfs)
4248c2ecf20Sopenharmony_ci{
4258c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = pci_get_drvdata(pdev);
4268c2ecf20Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
4278c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
4288c2ecf20Sopenharmony_ci	size_t size;
4298c2ecf20Sopenharmony_ci	int i;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	/* return error if iov_data is already populated */
4328c2ecf20Sopenharmony_ci	if (iov_data)
4338c2ecf20Sopenharmony_ci		return -EBUSY;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	/* The PF should always be able to assign resources */
4368c2ecf20Sopenharmony_ci	if (!hw->iov.ops.assign_resources)
4378c2ecf20Sopenharmony_ci		return -ENODEV;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	/* nothing to do if no VFs are requested */
4408c2ecf20Sopenharmony_ci	if (!num_vfs)
4418c2ecf20Sopenharmony_ci		return 0;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	/* allocate memory for VF storage */
4448c2ecf20Sopenharmony_ci	size = offsetof(struct fm10k_iov_data, vf_info[num_vfs]);
4458c2ecf20Sopenharmony_ci	iov_data = kzalloc(size, GFP_KERNEL);
4468c2ecf20Sopenharmony_ci	if (!iov_data)
4478c2ecf20Sopenharmony_ci		return -ENOMEM;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	/* record number of VFs */
4508c2ecf20Sopenharmony_ci	iov_data->num_vfs = num_vfs;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	/* loop through vf_info structures initializing each entry */
4538c2ecf20Sopenharmony_ci	for (i = 0; i < num_vfs; i++) {
4548c2ecf20Sopenharmony_ci		struct fm10k_vf_info *vf_info = &iov_data->vf_info[i];
4558c2ecf20Sopenharmony_ci		int err;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci		/* Record VF VSI value */
4588c2ecf20Sopenharmony_ci		vf_info->vsi = i + 1;
4598c2ecf20Sopenharmony_ci		vf_info->vf_idx = i;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci		/* initialize mailbox memory */
4628c2ecf20Sopenharmony_ci		err = fm10k_pfvf_mbx_init(hw, &vf_info->mbx, iov_mbx_data, i);
4638c2ecf20Sopenharmony_ci		if (err) {
4648c2ecf20Sopenharmony_ci			dev_err(&pdev->dev,
4658c2ecf20Sopenharmony_ci				"Unable to initialize SR-IOV mailbox\n");
4668c2ecf20Sopenharmony_ci			kfree(iov_data);
4678c2ecf20Sopenharmony_ci			return err;
4688c2ecf20Sopenharmony_ci		}
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	/* assign iov_data to interface */
4728c2ecf20Sopenharmony_ci	interface->iov_data = iov_data;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	/* allocate hardware resources for the VFs */
4758c2ecf20Sopenharmony_ci	fm10k_iov_resume(pdev);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	return 0;
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_civoid fm10k_iov_disable(struct pci_dev *pdev)
4818c2ecf20Sopenharmony_ci{
4828c2ecf20Sopenharmony_ci	if (pci_num_vf(pdev) && pci_vfs_assigned(pdev))
4838c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
4848c2ecf20Sopenharmony_ci			"Cannot disable SR-IOV while VFs are assigned\n");
4858c2ecf20Sopenharmony_ci	else
4868c2ecf20Sopenharmony_ci		pci_disable_sriov(pdev);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	fm10k_iov_free_data(pdev);
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ciint fm10k_iov_configure(struct pci_dev *pdev, int num_vfs)
4928c2ecf20Sopenharmony_ci{
4938c2ecf20Sopenharmony_ci	int current_vfs = pci_num_vf(pdev);
4948c2ecf20Sopenharmony_ci	int err = 0;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	if (current_vfs && pci_vfs_assigned(pdev)) {
4978c2ecf20Sopenharmony_ci		dev_err(&pdev->dev,
4988c2ecf20Sopenharmony_ci			"Cannot modify SR-IOV while VFs are assigned\n");
4998c2ecf20Sopenharmony_ci		num_vfs = current_vfs;
5008c2ecf20Sopenharmony_ci	} else {
5018c2ecf20Sopenharmony_ci		pci_disable_sriov(pdev);
5028c2ecf20Sopenharmony_ci		fm10k_iov_free_data(pdev);
5038c2ecf20Sopenharmony_ci	}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	/* allocate resources for the VFs */
5068c2ecf20Sopenharmony_ci	err = fm10k_iov_alloc_data(pdev, num_vfs);
5078c2ecf20Sopenharmony_ci	if (err)
5088c2ecf20Sopenharmony_ci		return err;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	/* allocate VFs if not already allocated */
5118c2ecf20Sopenharmony_ci	if (num_vfs && num_vfs != current_vfs) {
5128c2ecf20Sopenharmony_ci		err = pci_enable_sriov(pdev, num_vfs);
5138c2ecf20Sopenharmony_ci		if (err) {
5148c2ecf20Sopenharmony_ci			dev_err(&pdev->dev,
5158c2ecf20Sopenharmony_ci				"Enable PCI SR-IOV failed: %d\n", err);
5168c2ecf20Sopenharmony_ci			return err;
5178c2ecf20Sopenharmony_ci		}
5188c2ecf20Sopenharmony_ci	}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	return num_vfs;
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci/**
5248c2ecf20Sopenharmony_ci * fm10k_iov_update_stats - Update stats for all VFs
5258c2ecf20Sopenharmony_ci * @interface: device private structure
5268c2ecf20Sopenharmony_ci *
5278c2ecf20Sopenharmony_ci * Updates the VF statistics for all enabled VFs. Expects to be called by
5288c2ecf20Sopenharmony_ci * fm10k_update_stats and assumes that locking via the __FM10K_UPDATING_STATS
5298c2ecf20Sopenharmony_ci * bit is already handled.
5308c2ecf20Sopenharmony_ci */
5318c2ecf20Sopenharmony_civoid fm10k_iov_update_stats(struct fm10k_intfc *interface)
5328c2ecf20Sopenharmony_ci{
5338c2ecf20Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
5348c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
5358c2ecf20Sopenharmony_ci	int i;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	if (!iov_data)
5388c2ecf20Sopenharmony_ci		return;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	for (i = 0; i < iov_data->num_vfs; i++)
5418c2ecf20Sopenharmony_ci		hw->iov.ops.update_stats(hw, iov_data->vf_info[i].stats, i);
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_cistatic inline void fm10k_reset_vf_info(struct fm10k_intfc *interface,
5458c2ecf20Sopenharmony_ci				       struct fm10k_vf_info *vf_info)
5468c2ecf20Sopenharmony_ci{
5478c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	/* assigning the MAC address will send a mailbox message */
5508c2ecf20Sopenharmony_ci	fm10k_mbx_lock(interface);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	/* disable LPORT for this VF which clears switch rules */
5538c2ecf20Sopenharmony_ci	hw->iov.ops.reset_lport(hw, vf_info);
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	fm10k_clear_macvlan_queue(interface, vf_info->glort, false);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	/* assign new MAC+VLAN for this VF */
5588c2ecf20Sopenharmony_ci	hw->iov.ops.assign_default_mac_vlan(hw, vf_info);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	/* re-enable the LPORT for this VF */
5618c2ecf20Sopenharmony_ci	hw->iov.ops.set_lport(hw, vf_info, vf_info->vf_idx,
5628c2ecf20Sopenharmony_ci			      FM10K_VF_FLAG_MULTI_CAPABLE);
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	fm10k_mbx_unlock(interface);
5658c2ecf20Sopenharmony_ci}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ciint fm10k_ndo_set_vf_mac(struct net_device *netdev, int vf_idx, u8 *mac)
5688c2ecf20Sopenharmony_ci{
5698c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = netdev_priv(netdev);
5708c2ecf20Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
5718c2ecf20Sopenharmony_ci	struct fm10k_vf_info *vf_info;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	/* verify SR-IOV is active and that vf idx is valid */
5748c2ecf20Sopenharmony_ci	if (!iov_data || vf_idx >= iov_data->num_vfs)
5758c2ecf20Sopenharmony_ci		return -EINVAL;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	/* verify MAC addr is valid */
5788c2ecf20Sopenharmony_ci	if (!is_zero_ether_addr(mac) && !is_valid_ether_addr(mac))
5798c2ecf20Sopenharmony_ci		return -EINVAL;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	/* record new MAC address */
5828c2ecf20Sopenharmony_ci	vf_info = &iov_data->vf_info[vf_idx];
5838c2ecf20Sopenharmony_ci	ether_addr_copy(vf_info->mac, mac);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	fm10k_reset_vf_info(interface, vf_info);
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	return 0;
5888c2ecf20Sopenharmony_ci}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ciint fm10k_ndo_set_vf_vlan(struct net_device *netdev, int vf_idx, u16 vid,
5918c2ecf20Sopenharmony_ci			  u8 qos, __be16 vlan_proto)
5928c2ecf20Sopenharmony_ci{
5938c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = netdev_priv(netdev);
5948c2ecf20Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
5958c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
5968c2ecf20Sopenharmony_ci	struct fm10k_vf_info *vf_info;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	/* verify SR-IOV is active and that vf idx is valid */
5998c2ecf20Sopenharmony_ci	if (!iov_data || vf_idx >= iov_data->num_vfs)
6008c2ecf20Sopenharmony_ci		return -EINVAL;
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	/* QOS is unsupported and VLAN IDs accepted range 0-4094 */
6038c2ecf20Sopenharmony_ci	if (qos || (vid > (VLAN_VID_MASK - 1)))
6048c2ecf20Sopenharmony_ci		return -EINVAL;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	/* VF VLAN Protocol part to default is unsupported */
6078c2ecf20Sopenharmony_ci	if (vlan_proto != htons(ETH_P_8021Q))
6088c2ecf20Sopenharmony_ci		return -EPROTONOSUPPORT;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	vf_info = &iov_data->vf_info[vf_idx];
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	/* exit if there is nothing to do */
6138c2ecf20Sopenharmony_ci	if (vf_info->pf_vid == vid)
6148c2ecf20Sopenharmony_ci		return 0;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	/* record default VLAN ID for VF */
6178c2ecf20Sopenharmony_ci	vf_info->pf_vid = vid;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	/* Clear the VLAN table for the VF */
6208c2ecf20Sopenharmony_ci	hw->mac.ops.update_vlan(hw, FM10K_VLAN_ALL, vf_info->vsi, false);
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	fm10k_reset_vf_info(interface, vf_info);
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	return 0;
6258c2ecf20Sopenharmony_ci}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ciint fm10k_ndo_set_vf_bw(struct net_device *netdev, int vf_idx,
6288c2ecf20Sopenharmony_ci			int __always_unused min_rate, int max_rate)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = netdev_priv(netdev);
6318c2ecf20Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
6328c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	/* verify SR-IOV is active and that vf idx is valid */
6358c2ecf20Sopenharmony_ci	if (!iov_data || vf_idx >= iov_data->num_vfs)
6368c2ecf20Sopenharmony_ci		return -EINVAL;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	/* rate limit cannot be less than 10Mbs or greater than link speed */
6398c2ecf20Sopenharmony_ci	if (max_rate &&
6408c2ecf20Sopenharmony_ci	    (max_rate < FM10K_VF_TC_MIN || max_rate > FM10K_VF_TC_MAX))
6418c2ecf20Sopenharmony_ci		return -EINVAL;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	/* store values */
6448c2ecf20Sopenharmony_ci	iov_data->vf_info[vf_idx].rate = max_rate;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	/* update hardware configuration */
6478c2ecf20Sopenharmony_ci	hw->iov.ops.configure_tc(hw, vf_idx, max_rate);
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	return 0;
6508c2ecf20Sopenharmony_ci}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ciint fm10k_ndo_get_vf_config(struct net_device *netdev,
6538c2ecf20Sopenharmony_ci			    int vf_idx, struct ifla_vf_info *ivi)
6548c2ecf20Sopenharmony_ci{
6558c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = netdev_priv(netdev);
6568c2ecf20Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
6578c2ecf20Sopenharmony_ci	struct fm10k_vf_info *vf_info;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	/* verify SR-IOV is active and that vf idx is valid */
6608c2ecf20Sopenharmony_ci	if (!iov_data || vf_idx >= iov_data->num_vfs)
6618c2ecf20Sopenharmony_ci		return -EINVAL;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	vf_info = &iov_data->vf_info[vf_idx];
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	ivi->vf = vf_idx;
6668c2ecf20Sopenharmony_ci	ivi->max_tx_rate = vf_info->rate;
6678c2ecf20Sopenharmony_ci	ivi->min_tx_rate = 0;
6688c2ecf20Sopenharmony_ci	ether_addr_copy(ivi->mac, vf_info->mac);
6698c2ecf20Sopenharmony_ci	ivi->vlan = vf_info->pf_vid;
6708c2ecf20Sopenharmony_ci	ivi->qos = 0;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	return 0;
6738c2ecf20Sopenharmony_ci}
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ciint fm10k_ndo_get_vf_stats(struct net_device *netdev,
6768c2ecf20Sopenharmony_ci			   int vf_idx, struct ifla_vf_stats *stats)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	struct fm10k_intfc *interface = netdev_priv(netdev);
6798c2ecf20Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
6808c2ecf20Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
6818c2ecf20Sopenharmony_ci	struct fm10k_hw_stats_q *hw_stats;
6828c2ecf20Sopenharmony_ci	u32 idx, qpp;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	/* verify SR-IOV is active and that vf idx is valid */
6858c2ecf20Sopenharmony_ci	if (!iov_data || vf_idx >= iov_data->num_vfs)
6868c2ecf20Sopenharmony_ci		return -EINVAL;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	qpp = fm10k_queues_per_pool(hw);
6898c2ecf20Sopenharmony_ci	hw_stats = iov_data->vf_info[vf_idx].stats;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	for (idx = 0; idx < qpp; idx++) {
6928c2ecf20Sopenharmony_ci		stats->rx_packets += hw_stats[idx].rx_packets.count;
6938c2ecf20Sopenharmony_ci		stats->tx_packets += hw_stats[idx].tx_packets.count;
6948c2ecf20Sopenharmony_ci		stats->rx_bytes += hw_stats[idx].rx_bytes.count;
6958c2ecf20Sopenharmony_ci		stats->tx_bytes += hw_stats[idx].tx_bytes.count;
6968c2ecf20Sopenharmony_ci		stats->rx_dropped += hw_stats[idx].rx_drops.count;
6978c2ecf20Sopenharmony_ci	}
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	return 0;
7008c2ecf20Sopenharmony_ci}
701