162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright(c) 2013 - 2019 Intel Corporation. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include "fm10k.h"
562306a36Sopenharmony_ci#include "fm10k_vf.h"
662306a36Sopenharmony_ci#include "fm10k_pf.h"
762306a36Sopenharmony_ci
862306a36Sopenharmony_cistatic s32 fm10k_iov_msg_error(struct fm10k_hw *hw, u32 **results,
962306a36Sopenharmony_ci			       struct fm10k_mbx_info *mbx)
1062306a36Sopenharmony_ci{
1162306a36Sopenharmony_ci	struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx;
1262306a36Sopenharmony_ci	struct fm10k_intfc *interface = hw->back;
1362306a36Sopenharmony_ci	struct pci_dev *pdev = interface->pdev;
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci	dev_err(&pdev->dev, "Unknown message ID %u on VF %d\n",
1662306a36Sopenharmony_ci		**results & FM10K_TLV_ID_MASK, vf_info->vf_idx);
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci	return fm10k_tlv_msg_error(hw, results, mbx);
1962306a36Sopenharmony_ci}
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/**
2262306a36Sopenharmony_ci *  fm10k_iov_msg_queue_mac_vlan - Message handler for MAC/VLAN request from VF
2362306a36Sopenharmony_ci *  @hw: Pointer to hardware structure
2462306a36Sopenharmony_ci *  @results: Pointer array to message, results[0] is pointer to message
2562306a36Sopenharmony_ci *  @mbx: Pointer to mailbox information structure
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci *  This function is a custom handler for MAC/VLAN requests from the VF. The
2862306a36Sopenharmony_ci *  assumption is that it is acceptable to directly hand off the message from
2962306a36Sopenharmony_ci *  the VF to the PF's switch manager. However, we use a MAC/VLAN message
3062306a36Sopenharmony_ci *  queue to avoid overloading the mailbox when a large number of requests
3162306a36Sopenharmony_ci *  come in.
3262306a36Sopenharmony_ci **/
3362306a36Sopenharmony_cistatic s32 fm10k_iov_msg_queue_mac_vlan(struct fm10k_hw *hw, u32 **results,
3462306a36Sopenharmony_ci					struct fm10k_mbx_info *mbx)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx;
3762306a36Sopenharmony_ci	struct fm10k_intfc *interface = hw->back;
3862306a36Sopenharmony_ci	u8 mac[ETH_ALEN];
3962306a36Sopenharmony_ci	u32 *result;
4062306a36Sopenharmony_ci	int err = 0;
4162306a36Sopenharmony_ci	bool set;
4262306a36Sopenharmony_ci	u16 vlan;
4362306a36Sopenharmony_ci	u32 vid;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/* we shouldn't be updating rules on a disabled interface */
4662306a36Sopenharmony_ci	if (!FM10K_VF_FLAG_ENABLED(vf_info))
4762306a36Sopenharmony_ci		err = FM10K_ERR_PARAM;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	if (!err && !!results[FM10K_MAC_VLAN_MSG_VLAN]) {
5062306a36Sopenharmony_ci		result = results[FM10K_MAC_VLAN_MSG_VLAN];
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci		/* record VLAN id requested */
5362306a36Sopenharmony_ci		err = fm10k_tlv_attr_get_u32(result, &vid);
5462306a36Sopenharmony_ci		if (err)
5562306a36Sopenharmony_ci			return err;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci		set = !(vid & FM10K_VLAN_CLEAR);
5862306a36Sopenharmony_ci		vid &= ~FM10K_VLAN_CLEAR;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci		/* if the length field has been set, this is a multi-bit
6162306a36Sopenharmony_ci		 * update request. For multi-bit requests, simply disallow
6262306a36Sopenharmony_ci		 * them when the pf_vid has been set. In this case, the PF
6362306a36Sopenharmony_ci		 * should have already cleared the VLAN_TABLE, and if we
6462306a36Sopenharmony_ci		 * allowed them, it could allow a rogue VF to receive traffic
6562306a36Sopenharmony_ci		 * on a VLAN it was not assigned. In the single-bit case, we
6662306a36Sopenharmony_ci		 * need to modify requests for VLAN 0 to use the default PF or
6762306a36Sopenharmony_ci		 * SW vid when assigned.
6862306a36Sopenharmony_ci		 */
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci		if (vid >> 16) {
7162306a36Sopenharmony_ci			/* prevent multi-bit requests when PF has
7262306a36Sopenharmony_ci			 * administratively set the VLAN for this VF
7362306a36Sopenharmony_ci			 */
7462306a36Sopenharmony_ci			if (vf_info->pf_vid)
7562306a36Sopenharmony_ci				return FM10K_ERR_PARAM;
7662306a36Sopenharmony_ci		} else {
7762306a36Sopenharmony_ci			err = fm10k_iov_select_vid(vf_info, (u16)vid);
7862306a36Sopenharmony_ci			if (err < 0)
7962306a36Sopenharmony_ci				return err;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci			vid = err;
8262306a36Sopenharmony_ci		}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci		/* update VSI info for VF in regards to VLAN table */
8562306a36Sopenharmony_ci		err = hw->mac.ops.update_vlan(hw, vid, vf_info->vsi, set);
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if (!err && !!results[FM10K_MAC_VLAN_MSG_MAC]) {
8962306a36Sopenharmony_ci		result = results[FM10K_MAC_VLAN_MSG_MAC];
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci		/* record unicast MAC address requested */
9262306a36Sopenharmony_ci		err = fm10k_tlv_attr_get_mac_vlan(result, mac, &vlan);
9362306a36Sopenharmony_ci		if (err)
9462306a36Sopenharmony_ci			return err;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci		/* block attempts to set MAC for a locked device */
9762306a36Sopenharmony_ci		if (is_valid_ether_addr(vf_info->mac) &&
9862306a36Sopenharmony_ci		    !ether_addr_equal(mac, vf_info->mac))
9962306a36Sopenharmony_ci			return FM10K_ERR_PARAM;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci		set = !(vlan & FM10K_VLAN_CLEAR);
10262306a36Sopenharmony_ci		vlan &= ~FM10K_VLAN_CLEAR;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci		err = fm10k_iov_select_vid(vf_info, vlan);
10562306a36Sopenharmony_ci		if (err < 0)
10662306a36Sopenharmony_ci			return err;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci		vlan = (u16)err;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci		/* Add this request to the MAC/VLAN queue */
11162306a36Sopenharmony_ci		err = fm10k_queue_mac_request(interface, vf_info->glort,
11262306a36Sopenharmony_ci					      mac, vlan, set);
11362306a36Sopenharmony_ci	}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	if (!err && !!results[FM10K_MAC_VLAN_MSG_MULTICAST]) {
11662306a36Sopenharmony_ci		result = results[FM10K_MAC_VLAN_MSG_MULTICAST];
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci		/* record multicast MAC address requested */
11962306a36Sopenharmony_ci		err = fm10k_tlv_attr_get_mac_vlan(result, mac, &vlan);
12062306a36Sopenharmony_ci		if (err)
12162306a36Sopenharmony_ci			return err;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci		/* verify that the VF is allowed to request multicast */
12462306a36Sopenharmony_ci		if (!(vf_info->vf_flags & FM10K_VF_FLAG_MULTI_ENABLED))
12562306a36Sopenharmony_ci			return FM10K_ERR_PARAM;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci		set = !(vlan & FM10K_VLAN_CLEAR);
12862306a36Sopenharmony_ci		vlan &= ~FM10K_VLAN_CLEAR;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		err = fm10k_iov_select_vid(vf_info, vlan);
13162306a36Sopenharmony_ci		if (err < 0)
13262306a36Sopenharmony_ci			return err;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci		vlan = (u16)err;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci		/* Add this request to the MAC/VLAN queue */
13762306a36Sopenharmony_ci		err = fm10k_queue_mac_request(interface, vf_info->glort,
13862306a36Sopenharmony_ci					      mac, vlan, set);
13962306a36Sopenharmony_ci	}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	return err;
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic const struct fm10k_msg_data iov_mbx_data[] = {
14562306a36Sopenharmony_ci	FM10K_TLV_MSG_TEST_HANDLER(fm10k_tlv_msg_test),
14662306a36Sopenharmony_ci	FM10K_VF_MSG_MSIX_HANDLER(fm10k_iov_msg_msix_pf),
14762306a36Sopenharmony_ci	FM10K_VF_MSG_MAC_VLAN_HANDLER(fm10k_iov_msg_queue_mac_vlan),
14862306a36Sopenharmony_ci	FM10K_VF_MSG_LPORT_STATE_HANDLER(fm10k_iov_msg_lport_state_pf),
14962306a36Sopenharmony_ci	FM10K_TLV_MSG_ERROR_HANDLER(fm10k_iov_msg_error),
15062306a36Sopenharmony_ci};
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cis32 fm10k_iov_event(struct fm10k_intfc *interface)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
15562306a36Sopenharmony_ci	struct fm10k_iov_data *iov_data;
15662306a36Sopenharmony_ci	s64 vflre;
15762306a36Sopenharmony_ci	int i;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	/* if there is no iov_data then there is no mailbox to process */
16062306a36Sopenharmony_ci	if (!READ_ONCE(interface->iov_data))
16162306a36Sopenharmony_ci		return 0;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	rcu_read_lock();
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	iov_data = interface->iov_data;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* check again now that we are in the RCU block */
16862306a36Sopenharmony_ci	if (!iov_data)
16962306a36Sopenharmony_ci		goto read_unlock;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	if (!(fm10k_read_reg(hw, FM10K_EICR) & FM10K_EICR_VFLR))
17262306a36Sopenharmony_ci		goto read_unlock;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	/* read VFLRE to determine if any VFs have been reset */
17562306a36Sopenharmony_ci	vflre = fm10k_read_reg(hw, FM10K_PFVFLRE(1));
17662306a36Sopenharmony_ci	vflre <<= 32;
17762306a36Sopenharmony_ci	vflre |= fm10k_read_reg(hw, FM10K_PFVFLRE(0));
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	i = iov_data->num_vfs;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	for (vflre <<= 64 - i; vflre && i--; vflre += vflre) {
18262306a36Sopenharmony_ci		struct fm10k_vf_info *vf_info = &iov_data->vf_info[i];
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci		if (vflre >= 0)
18562306a36Sopenharmony_ci			continue;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci		hw->iov.ops.reset_resources(hw, vf_info);
18862306a36Sopenharmony_ci		vf_info->mbx.ops.connect(hw, &vf_info->mbx);
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ciread_unlock:
19262306a36Sopenharmony_ci	rcu_read_unlock();
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	return 0;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cis32 fm10k_iov_mbx(struct fm10k_intfc *interface)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
20062306a36Sopenharmony_ci	struct fm10k_iov_data *iov_data;
20162306a36Sopenharmony_ci	int i;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	/* if there is no iov_data then there is no mailbox to process */
20462306a36Sopenharmony_ci	if (!READ_ONCE(interface->iov_data))
20562306a36Sopenharmony_ci		return 0;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	rcu_read_lock();
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	iov_data = interface->iov_data;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	/* check again now that we are in the RCU block */
21262306a36Sopenharmony_ci	if (!iov_data)
21362306a36Sopenharmony_ci		goto read_unlock;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	/* lock the mailbox for transmit and receive */
21662306a36Sopenharmony_ci	fm10k_mbx_lock(interface);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	/* Most VF messages sent to the PF cause the PF to respond by
21962306a36Sopenharmony_ci	 * requesting from the SM mailbox. This means that too many VF
22062306a36Sopenharmony_ci	 * messages processed at once could cause a mailbox timeout on the PF.
22162306a36Sopenharmony_ci	 * To prevent this, store a pointer to the next VF mbx to process. Use
22262306a36Sopenharmony_ci	 * that as the start of the loop so that we don't starve whichever VF
22362306a36Sopenharmony_ci	 * got ignored on the previous run.
22462306a36Sopenharmony_ci	 */
22562306a36Sopenharmony_ciprocess_mbx:
22662306a36Sopenharmony_ci	for (i = iov_data->next_vf_mbx ? : iov_data->num_vfs; i--;) {
22762306a36Sopenharmony_ci		struct fm10k_vf_info *vf_info = &iov_data->vf_info[i];
22862306a36Sopenharmony_ci		struct fm10k_mbx_info *mbx = &vf_info->mbx;
22962306a36Sopenharmony_ci		u16 glort = vf_info->glort;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci		/* process the SM mailbox first to drain outgoing messages */
23262306a36Sopenharmony_ci		hw->mbx.ops.process(hw, &hw->mbx);
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci		/* verify port mapping is valid, if not reset port */
23562306a36Sopenharmony_ci		if (vf_info->vf_flags && !fm10k_glort_valid_pf(hw, glort)) {
23662306a36Sopenharmony_ci			hw->iov.ops.reset_lport(hw, vf_info);
23762306a36Sopenharmony_ci			fm10k_clear_macvlan_queue(interface, glort, false);
23862306a36Sopenharmony_ci		}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci		/* reset VFs that have mailbox timed out */
24162306a36Sopenharmony_ci		if (!mbx->timeout) {
24262306a36Sopenharmony_ci			hw->iov.ops.reset_resources(hw, vf_info);
24362306a36Sopenharmony_ci			mbx->ops.connect(hw, mbx);
24462306a36Sopenharmony_ci		}
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci		/* guarantee we have free space in the SM mailbox */
24762306a36Sopenharmony_ci		if (hw->mbx.state == FM10K_STATE_OPEN &&
24862306a36Sopenharmony_ci		    !hw->mbx.ops.tx_ready(&hw->mbx, FM10K_VFMBX_MSG_MTU)) {
24962306a36Sopenharmony_ci			/* keep track of how many times this occurs */
25062306a36Sopenharmony_ci			interface->hw_sm_mbx_full++;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci			/* make sure we try again momentarily */
25362306a36Sopenharmony_ci			fm10k_service_event_schedule(interface);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci			break;
25662306a36Sopenharmony_ci		}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		/* cleanup mailbox and process received messages */
25962306a36Sopenharmony_ci		mbx->ops.process(hw, mbx);
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	/* if we stopped processing mailboxes early, update next_vf_mbx.
26362306a36Sopenharmony_ci	 * Otherwise, reset next_vf_mbx, and restart loop so that we process
26462306a36Sopenharmony_ci	 * the remaining mailboxes we skipped at the start.
26562306a36Sopenharmony_ci	 */
26662306a36Sopenharmony_ci	if (i >= 0) {
26762306a36Sopenharmony_ci		iov_data->next_vf_mbx = i + 1;
26862306a36Sopenharmony_ci	} else if (iov_data->next_vf_mbx) {
26962306a36Sopenharmony_ci		iov_data->next_vf_mbx = 0;
27062306a36Sopenharmony_ci		goto process_mbx;
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	/* free the lock */
27462306a36Sopenharmony_ci	fm10k_mbx_unlock(interface);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ciread_unlock:
27762306a36Sopenharmony_ci	rcu_read_unlock();
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	return 0;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_civoid fm10k_iov_suspend(struct pci_dev *pdev)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	struct fm10k_intfc *interface = pci_get_drvdata(pdev);
28562306a36Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
28662306a36Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
28762306a36Sopenharmony_ci	int num_vfs, i;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	/* pull out num_vfs from iov_data */
29062306a36Sopenharmony_ci	num_vfs = iov_data ? iov_data->num_vfs : 0;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	/* shut down queue mapping for VFs */
29362306a36Sopenharmony_ci	fm10k_write_reg(hw, FM10K_DGLORTMAP(fm10k_dglort_vf_rss),
29462306a36Sopenharmony_ci			FM10K_DGLORTMAP_NONE);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	/* Stop any active VFs and reset their resources */
29762306a36Sopenharmony_ci	for (i = 0; i < num_vfs; i++) {
29862306a36Sopenharmony_ci		struct fm10k_vf_info *vf_info = &iov_data->vf_info[i];
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci		hw->iov.ops.reset_resources(hw, vf_info);
30162306a36Sopenharmony_ci		hw->iov.ops.reset_lport(hw, vf_info);
30262306a36Sopenharmony_ci		fm10k_clear_macvlan_queue(interface, vf_info->glort, false);
30362306a36Sopenharmony_ci	}
30462306a36Sopenharmony_ci}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic void fm10k_mask_aer_comp_abort(struct pci_dev *pdev)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	u32 err_mask;
30962306a36Sopenharmony_ci	int pos;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
31262306a36Sopenharmony_ci	if (!pos)
31362306a36Sopenharmony_ci		return;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	/* Mask the completion abort bit in the ERR_UNCOR_MASK register,
31662306a36Sopenharmony_ci	 * preventing the device from reporting these errors to the upstream
31762306a36Sopenharmony_ci	 * PCIe root device. This avoids bringing down platforms which upgrade
31862306a36Sopenharmony_ci	 * non-fatal completer aborts into machine check exceptions. Completer
31962306a36Sopenharmony_ci	 * aborts can occur whenever a VF reads a queue it doesn't own.
32062306a36Sopenharmony_ci	 */
32162306a36Sopenharmony_ci	pci_read_config_dword(pdev, pos + PCI_ERR_UNCOR_MASK, &err_mask);
32262306a36Sopenharmony_ci	err_mask |= PCI_ERR_UNC_COMP_ABORT;
32362306a36Sopenharmony_ci	pci_write_config_dword(pdev, pos + PCI_ERR_UNCOR_MASK, err_mask);
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ciint fm10k_iov_resume(struct pci_dev *pdev)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	struct fm10k_intfc *interface = pci_get_drvdata(pdev);
32962306a36Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
33062306a36Sopenharmony_ci	struct fm10k_dglort_cfg dglort = { 0 };
33162306a36Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
33262306a36Sopenharmony_ci	int num_vfs, i;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	/* pull out num_vfs from iov_data */
33562306a36Sopenharmony_ci	num_vfs = iov_data ? iov_data->num_vfs : 0;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	/* return error if iov_data is not already populated */
33862306a36Sopenharmony_ci	if (!iov_data)
33962306a36Sopenharmony_ci		return -ENOMEM;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	/* Lower severity of completer abort error reporting as
34262306a36Sopenharmony_ci	 * the VFs can trigger this any time they read a queue
34362306a36Sopenharmony_ci	 * that they don't own.
34462306a36Sopenharmony_ci	 */
34562306a36Sopenharmony_ci	fm10k_mask_aer_comp_abort(pdev);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	/* allocate hardware resources for the VFs */
34862306a36Sopenharmony_ci	hw->iov.ops.assign_resources(hw, num_vfs, num_vfs);
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	/* configure DGLORT mapping for RSS */
35162306a36Sopenharmony_ci	dglort.glort = hw->mac.dglort_map & FM10K_DGLORTMAP_NONE;
35262306a36Sopenharmony_ci	dglort.idx = fm10k_dglort_vf_rss;
35362306a36Sopenharmony_ci	dglort.inner_rss = 1;
35462306a36Sopenharmony_ci	dglort.rss_l = fls(fm10k_queues_per_pool(hw) - 1);
35562306a36Sopenharmony_ci	dglort.queue_b = fm10k_vf_queue_index(hw, 0);
35662306a36Sopenharmony_ci	dglort.vsi_l = fls(hw->iov.total_vfs - 1);
35762306a36Sopenharmony_ci	dglort.vsi_b = 1;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	hw->mac.ops.configure_dglort_map(hw, &dglort);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	/* assign resources to the device */
36262306a36Sopenharmony_ci	for (i = 0; i < num_vfs; i++) {
36362306a36Sopenharmony_ci		struct fm10k_vf_info *vf_info = &iov_data->vf_info[i];
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci		/* allocate all but the last GLORT to the VFs */
36662306a36Sopenharmony_ci		if (i == (~hw->mac.dglort_map >> FM10K_DGLORTMAP_MASK_SHIFT))
36762306a36Sopenharmony_ci			break;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci		/* assign GLORT to VF, and restrict it to multicast */
37062306a36Sopenharmony_ci		hw->iov.ops.set_lport(hw, vf_info, i,
37162306a36Sopenharmony_ci				      FM10K_VF_FLAG_MULTI_CAPABLE);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci		/* mailbox is disconnected so we don't send a message */
37462306a36Sopenharmony_ci		hw->iov.ops.assign_default_mac_vlan(hw, vf_info);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci		/* now we are ready so we can connect */
37762306a36Sopenharmony_ci		vf_info->mbx.ops.connect(hw, &vf_info->mbx);
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	return 0;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_cis32 fm10k_iov_update_pvid(struct fm10k_intfc *interface, u16 glort, u16 pvid)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
38662306a36Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
38762306a36Sopenharmony_ci	struct fm10k_vf_info *vf_info;
38862306a36Sopenharmony_ci	u16 vf_idx = (glort - hw->mac.dglort_map) & FM10K_DGLORTMAP_NONE;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	/* no IOV support, not our message to process */
39162306a36Sopenharmony_ci	if (!iov_data)
39262306a36Sopenharmony_ci		return FM10K_ERR_PARAM;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	/* glort outside our range, not our message to process */
39562306a36Sopenharmony_ci	if (vf_idx >= iov_data->num_vfs)
39662306a36Sopenharmony_ci		return FM10K_ERR_PARAM;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* determine if an update has occurred and if so notify the VF */
39962306a36Sopenharmony_ci	vf_info = &iov_data->vf_info[vf_idx];
40062306a36Sopenharmony_ci	if (vf_info->sw_vid != pvid) {
40162306a36Sopenharmony_ci		vf_info->sw_vid = pvid;
40262306a36Sopenharmony_ci		hw->iov.ops.assign_default_mac_vlan(hw, vf_info);
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	return 0;
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_cistatic void fm10k_iov_free_data(struct pci_dev *pdev)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	struct fm10k_intfc *interface = pci_get_drvdata(pdev);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	if (!interface->iov_data)
41362306a36Sopenharmony_ci		return;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	/* reclaim hardware resources */
41662306a36Sopenharmony_ci	fm10k_iov_suspend(pdev);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	/* drop iov_data from interface */
41962306a36Sopenharmony_ci	kfree_rcu(interface->iov_data, rcu);
42062306a36Sopenharmony_ci	interface->iov_data = NULL;
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_cistatic s32 fm10k_iov_alloc_data(struct pci_dev *pdev, int num_vfs)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	struct fm10k_intfc *interface = pci_get_drvdata(pdev);
42662306a36Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
42762306a36Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
42862306a36Sopenharmony_ci	size_t size;
42962306a36Sopenharmony_ci	int i;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	/* return error if iov_data is already populated */
43262306a36Sopenharmony_ci	if (iov_data)
43362306a36Sopenharmony_ci		return -EBUSY;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	/* The PF should always be able to assign resources */
43662306a36Sopenharmony_ci	if (!hw->iov.ops.assign_resources)
43762306a36Sopenharmony_ci		return -ENODEV;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	/* nothing to do if no VFs are requested */
44062306a36Sopenharmony_ci	if (!num_vfs)
44162306a36Sopenharmony_ci		return 0;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	/* allocate memory for VF storage */
44462306a36Sopenharmony_ci	size = offsetof(struct fm10k_iov_data, vf_info[num_vfs]);
44562306a36Sopenharmony_ci	iov_data = kzalloc(size, GFP_KERNEL);
44662306a36Sopenharmony_ci	if (!iov_data)
44762306a36Sopenharmony_ci		return -ENOMEM;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	/* record number of VFs */
45062306a36Sopenharmony_ci	iov_data->num_vfs = num_vfs;
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	/* loop through vf_info structures initializing each entry */
45362306a36Sopenharmony_ci	for (i = 0; i < num_vfs; i++) {
45462306a36Sopenharmony_ci		struct fm10k_vf_info *vf_info = &iov_data->vf_info[i];
45562306a36Sopenharmony_ci		int err;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci		/* Record VF VSI value */
45862306a36Sopenharmony_ci		vf_info->vsi = i + 1;
45962306a36Sopenharmony_ci		vf_info->vf_idx = i;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci		/* initialize mailbox memory */
46262306a36Sopenharmony_ci		err = fm10k_pfvf_mbx_init(hw, &vf_info->mbx, iov_mbx_data, i);
46362306a36Sopenharmony_ci		if (err) {
46462306a36Sopenharmony_ci			dev_err(&pdev->dev,
46562306a36Sopenharmony_ci				"Unable to initialize SR-IOV mailbox\n");
46662306a36Sopenharmony_ci			kfree(iov_data);
46762306a36Sopenharmony_ci			return err;
46862306a36Sopenharmony_ci		}
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/* assign iov_data to interface */
47262306a36Sopenharmony_ci	interface->iov_data = iov_data;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	/* allocate hardware resources for the VFs */
47562306a36Sopenharmony_ci	fm10k_iov_resume(pdev);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	return 0;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_civoid fm10k_iov_disable(struct pci_dev *pdev)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	if (pci_num_vf(pdev) && pci_vfs_assigned(pdev))
48362306a36Sopenharmony_ci		dev_err(&pdev->dev,
48462306a36Sopenharmony_ci			"Cannot disable SR-IOV while VFs are assigned\n");
48562306a36Sopenharmony_ci	else
48662306a36Sopenharmony_ci		pci_disable_sriov(pdev);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	fm10k_iov_free_data(pdev);
48962306a36Sopenharmony_ci}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ciint fm10k_iov_configure(struct pci_dev *pdev, int num_vfs)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	int current_vfs = pci_num_vf(pdev);
49462306a36Sopenharmony_ci	int err = 0;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	if (current_vfs && pci_vfs_assigned(pdev)) {
49762306a36Sopenharmony_ci		dev_err(&pdev->dev,
49862306a36Sopenharmony_ci			"Cannot modify SR-IOV while VFs are assigned\n");
49962306a36Sopenharmony_ci		num_vfs = current_vfs;
50062306a36Sopenharmony_ci	} else {
50162306a36Sopenharmony_ci		pci_disable_sriov(pdev);
50262306a36Sopenharmony_ci		fm10k_iov_free_data(pdev);
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	/* allocate resources for the VFs */
50662306a36Sopenharmony_ci	err = fm10k_iov_alloc_data(pdev, num_vfs);
50762306a36Sopenharmony_ci	if (err)
50862306a36Sopenharmony_ci		return err;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci	/* allocate VFs if not already allocated */
51162306a36Sopenharmony_ci	if (num_vfs && num_vfs != current_vfs) {
51262306a36Sopenharmony_ci		err = pci_enable_sriov(pdev, num_vfs);
51362306a36Sopenharmony_ci		if (err) {
51462306a36Sopenharmony_ci			dev_err(&pdev->dev,
51562306a36Sopenharmony_ci				"Enable PCI SR-IOV failed: %d\n", err);
51662306a36Sopenharmony_ci			return err;
51762306a36Sopenharmony_ci		}
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	return num_vfs;
52162306a36Sopenharmony_ci}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci/**
52462306a36Sopenharmony_ci * fm10k_iov_update_stats - Update stats for all VFs
52562306a36Sopenharmony_ci * @interface: device private structure
52662306a36Sopenharmony_ci *
52762306a36Sopenharmony_ci * Updates the VF statistics for all enabled VFs. Expects to be called by
52862306a36Sopenharmony_ci * fm10k_update_stats and assumes that locking via the __FM10K_UPDATING_STATS
52962306a36Sopenharmony_ci * bit is already handled.
53062306a36Sopenharmony_ci */
53162306a36Sopenharmony_civoid fm10k_iov_update_stats(struct fm10k_intfc *interface)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
53462306a36Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
53562306a36Sopenharmony_ci	int i;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	if (!iov_data)
53862306a36Sopenharmony_ci		return;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	for (i = 0; i < iov_data->num_vfs; i++)
54162306a36Sopenharmony_ci		hw->iov.ops.update_stats(hw, iov_data->vf_info[i].stats, i);
54262306a36Sopenharmony_ci}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_cistatic inline void fm10k_reset_vf_info(struct fm10k_intfc *interface,
54562306a36Sopenharmony_ci				       struct fm10k_vf_info *vf_info)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	/* assigning the MAC address will send a mailbox message */
55062306a36Sopenharmony_ci	fm10k_mbx_lock(interface);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	/* disable LPORT for this VF which clears switch rules */
55362306a36Sopenharmony_ci	hw->iov.ops.reset_lport(hw, vf_info);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	fm10k_clear_macvlan_queue(interface, vf_info->glort, false);
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	/* assign new MAC+VLAN for this VF */
55862306a36Sopenharmony_ci	hw->iov.ops.assign_default_mac_vlan(hw, vf_info);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	/* re-enable the LPORT for this VF */
56162306a36Sopenharmony_ci	hw->iov.ops.set_lport(hw, vf_info, vf_info->vf_idx,
56262306a36Sopenharmony_ci			      FM10K_VF_FLAG_MULTI_CAPABLE);
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	fm10k_mbx_unlock(interface);
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ciint fm10k_ndo_set_vf_mac(struct net_device *netdev, int vf_idx, u8 *mac)
56862306a36Sopenharmony_ci{
56962306a36Sopenharmony_ci	struct fm10k_intfc *interface = netdev_priv(netdev);
57062306a36Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
57162306a36Sopenharmony_ci	struct fm10k_vf_info *vf_info;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	/* verify SR-IOV is active and that vf idx is valid */
57462306a36Sopenharmony_ci	if (!iov_data || vf_idx >= iov_data->num_vfs)
57562306a36Sopenharmony_ci		return -EINVAL;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	/* verify MAC addr is valid */
57862306a36Sopenharmony_ci	if (!is_zero_ether_addr(mac) && !is_valid_ether_addr(mac))
57962306a36Sopenharmony_ci		return -EINVAL;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	/* record new MAC address */
58262306a36Sopenharmony_ci	vf_info = &iov_data->vf_info[vf_idx];
58362306a36Sopenharmony_ci	ether_addr_copy(vf_info->mac, mac);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	fm10k_reset_vf_info(interface, vf_info);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	return 0;
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ciint fm10k_ndo_set_vf_vlan(struct net_device *netdev, int vf_idx, u16 vid,
59162306a36Sopenharmony_ci			  u8 qos, __be16 vlan_proto)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	struct fm10k_intfc *interface = netdev_priv(netdev);
59462306a36Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
59562306a36Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
59662306a36Sopenharmony_ci	struct fm10k_vf_info *vf_info;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	/* verify SR-IOV is active and that vf idx is valid */
59962306a36Sopenharmony_ci	if (!iov_data || vf_idx >= iov_data->num_vfs)
60062306a36Sopenharmony_ci		return -EINVAL;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	/* QOS is unsupported and VLAN IDs accepted range 0-4094 */
60362306a36Sopenharmony_ci	if (qos || (vid > (VLAN_VID_MASK - 1)))
60462306a36Sopenharmony_ci		return -EINVAL;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	/* VF VLAN Protocol part to default is unsupported */
60762306a36Sopenharmony_ci	if (vlan_proto != htons(ETH_P_8021Q))
60862306a36Sopenharmony_ci		return -EPROTONOSUPPORT;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	vf_info = &iov_data->vf_info[vf_idx];
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	/* exit if there is nothing to do */
61362306a36Sopenharmony_ci	if (vf_info->pf_vid == vid)
61462306a36Sopenharmony_ci		return 0;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	/* record default VLAN ID for VF */
61762306a36Sopenharmony_ci	vf_info->pf_vid = vid;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	/* Clear the VLAN table for the VF */
62062306a36Sopenharmony_ci	hw->mac.ops.update_vlan(hw, FM10K_VLAN_ALL, vf_info->vsi, false);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	fm10k_reset_vf_info(interface, vf_info);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	return 0;
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ciint fm10k_ndo_set_vf_bw(struct net_device *netdev, int vf_idx,
62862306a36Sopenharmony_ci			int __always_unused min_rate, int max_rate)
62962306a36Sopenharmony_ci{
63062306a36Sopenharmony_ci	struct fm10k_intfc *interface = netdev_priv(netdev);
63162306a36Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
63262306a36Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	/* verify SR-IOV is active and that vf idx is valid */
63562306a36Sopenharmony_ci	if (!iov_data || vf_idx >= iov_data->num_vfs)
63662306a36Sopenharmony_ci		return -EINVAL;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	/* rate limit cannot be less than 10Mbs or greater than link speed */
63962306a36Sopenharmony_ci	if (max_rate &&
64062306a36Sopenharmony_ci	    (max_rate < FM10K_VF_TC_MIN || max_rate > FM10K_VF_TC_MAX))
64162306a36Sopenharmony_ci		return -EINVAL;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	/* store values */
64462306a36Sopenharmony_ci	iov_data->vf_info[vf_idx].rate = max_rate;
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	/* update hardware configuration */
64762306a36Sopenharmony_ci	hw->iov.ops.configure_tc(hw, vf_idx, max_rate);
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	return 0;
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ciint fm10k_ndo_get_vf_config(struct net_device *netdev,
65362306a36Sopenharmony_ci			    int vf_idx, struct ifla_vf_info *ivi)
65462306a36Sopenharmony_ci{
65562306a36Sopenharmony_ci	struct fm10k_intfc *interface = netdev_priv(netdev);
65662306a36Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
65762306a36Sopenharmony_ci	struct fm10k_vf_info *vf_info;
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	/* verify SR-IOV is active and that vf idx is valid */
66062306a36Sopenharmony_ci	if (!iov_data || vf_idx >= iov_data->num_vfs)
66162306a36Sopenharmony_ci		return -EINVAL;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	vf_info = &iov_data->vf_info[vf_idx];
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	ivi->vf = vf_idx;
66662306a36Sopenharmony_ci	ivi->max_tx_rate = vf_info->rate;
66762306a36Sopenharmony_ci	ivi->min_tx_rate = 0;
66862306a36Sopenharmony_ci	ether_addr_copy(ivi->mac, vf_info->mac);
66962306a36Sopenharmony_ci	ivi->vlan = vf_info->pf_vid;
67062306a36Sopenharmony_ci	ivi->qos = 0;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	return 0;
67362306a36Sopenharmony_ci}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ciint fm10k_ndo_get_vf_stats(struct net_device *netdev,
67662306a36Sopenharmony_ci			   int vf_idx, struct ifla_vf_stats *stats)
67762306a36Sopenharmony_ci{
67862306a36Sopenharmony_ci	struct fm10k_intfc *interface = netdev_priv(netdev);
67962306a36Sopenharmony_ci	struct fm10k_iov_data *iov_data = interface->iov_data;
68062306a36Sopenharmony_ci	struct fm10k_hw *hw = &interface->hw;
68162306a36Sopenharmony_ci	struct fm10k_hw_stats_q *hw_stats;
68262306a36Sopenharmony_ci	u32 idx, qpp;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/* verify SR-IOV is active and that vf idx is valid */
68562306a36Sopenharmony_ci	if (!iov_data || vf_idx >= iov_data->num_vfs)
68662306a36Sopenharmony_ci		return -EINVAL;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	qpp = fm10k_queues_per_pool(hw);
68962306a36Sopenharmony_ci	hw_stats = iov_data->vf_info[vf_idx].stats;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	for (idx = 0; idx < qpp; idx++) {
69262306a36Sopenharmony_ci		stats->rx_packets += hw_stats[idx].rx_packets.count;
69362306a36Sopenharmony_ci		stats->tx_packets += hw_stats[idx].tx_packets.count;
69462306a36Sopenharmony_ci		stats->rx_bytes += hw_stats[idx].rx_bytes.count;
69562306a36Sopenharmony_ci		stats->tx_bytes += hw_stats[idx].tx_bytes.count;
69662306a36Sopenharmony_ci		stats->rx_dropped += hw_stats[idx].rx_drops.count;
69762306a36Sopenharmony_ci	}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	return 0;
70062306a36Sopenharmony_ci}
701