162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) 2018, Intel Corporation. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci/* Intel(R) Ethernet Connection E800 Series Linux Driver */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <generated/utsrelease.h>
962306a36Sopenharmony_ci#include <linux/crash_dump.h>
1062306a36Sopenharmony_ci#include "ice.h"
1162306a36Sopenharmony_ci#include "ice_base.h"
1262306a36Sopenharmony_ci#include "ice_lib.h"
1362306a36Sopenharmony_ci#include "ice_fltr.h"
1462306a36Sopenharmony_ci#include "ice_dcb_lib.h"
1562306a36Sopenharmony_ci#include "ice_dcb_nl.h"
1662306a36Sopenharmony_ci#include "ice_devlink.h"
1762306a36Sopenharmony_ci/* Including ice_trace.h with CREATE_TRACE_POINTS defined will generate the
1862306a36Sopenharmony_ci * ice tracepoint functions. This must be done exactly once across the
1962306a36Sopenharmony_ci * ice driver.
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ci#define CREATE_TRACE_POINTS
2262306a36Sopenharmony_ci#include "ice_trace.h"
2362306a36Sopenharmony_ci#include "ice_eswitch.h"
2462306a36Sopenharmony_ci#include "ice_tc_lib.h"
2562306a36Sopenharmony_ci#include "ice_vsi_vlan_ops.h"
2662306a36Sopenharmony_ci#include <net/xdp_sock_drv.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define DRV_SUMMARY	"Intel(R) Ethernet Connection E800 Series Linux Driver"
2962306a36Sopenharmony_cistatic const char ice_driver_string[] = DRV_SUMMARY;
3062306a36Sopenharmony_cistatic const char ice_copyright[] = "Copyright (c) 2018, Intel Corporation.";
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/* DDP Package file located in firmware search paths (e.g. /lib/firmware/) */
3362306a36Sopenharmony_ci#define ICE_DDP_PKG_PATH	"intel/ice/ddp/"
3462306a36Sopenharmony_ci#define ICE_DDP_PKG_FILE	ICE_DDP_PKG_PATH "ice.pkg"
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ciMODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
3762306a36Sopenharmony_ciMODULE_DESCRIPTION(DRV_SUMMARY);
3862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
3962306a36Sopenharmony_ciMODULE_FIRMWARE(ICE_DDP_PKG_FILE);
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic int debug = -1;
4262306a36Sopenharmony_cimodule_param(debug, int, 0644);
4362306a36Sopenharmony_ci#ifndef CONFIG_DYNAMIC_DEBUG
4462306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "netif level (0=none,...,16=all), hw debug_mask (0x8XXXXXXX)");
4562306a36Sopenharmony_ci#else
4662306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)");
4762306a36Sopenharmony_ci#endif /* !CONFIG_DYNAMIC_DEBUG */
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ciDEFINE_STATIC_KEY_FALSE(ice_xdp_locking_key);
5062306a36Sopenharmony_ciEXPORT_SYMBOL(ice_xdp_locking_key);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/**
5362306a36Sopenharmony_ci * ice_hw_to_dev - Get device pointer from the hardware structure
5462306a36Sopenharmony_ci * @hw: pointer to the device HW structure
5562306a36Sopenharmony_ci *
5662306a36Sopenharmony_ci * Used to access the device pointer from compilation units which can't easily
5762306a36Sopenharmony_ci * include the definition of struct ice_pf without leading to circular header
5862306a36Sopenharmony_ci * dependencies.
5962306a36Sopenharmony_ci */
6062306a36Sopenharmony_cistruct device *ice_hw_to_dev(struct ice_hw *hw)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	struct ice_pf *pf = container_of(hw, struct ice_pf, hw);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	return &pf->pdev->dev;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic struct workqueue_struct *ice_wq;
6862306a36Sopenharmony_cistruct workqueue_struct *ice_lag_wq;
6962306a36Sopenharmony_cistatic const struct net_device_ops ice_netdev_safe_mode_ops;
7062306a36Sopenharmony_cistatic const struct net_device_ops ice_netdev_ops;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic void ice_vsi_release_all(struct ice_pf *pf);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic int ice_rebuild_channels(struct ice_pf *pf);
7762306a36Sopenharmony_cistatic void ice_remove_q_channels(struct ice_vsi *vsi, bool rem_adv_fltr);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic int
8062306a36Sopenharmony_ciice_indr_setup_tc_cb(struct net_device *netdev, struct Qdisc *sch,
8162306a36Sopenharmony_ci		     void *cb_priv, enum tc_setup_type type, void *type_data,
8262306a36Sopenharmony_ci		     void *data,
8362306a36Sopenharmony_ci		     void (*cleanup)(struct flow_block_cb *block_cb));
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cibool netif_is_ice(const struct net_device *dev)
8662306a36Sopenharmony_ci{
8762306a36Sopenharmony_ci	return dev && (dev->netdev_ops == &ice_netdev_ops);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/**
9162306a36Sopenharmony_ci * ice_get_tx_pending - returns number of Tx descriptors not processed
9262306a36Sopenharmony_ci * @ring: the ring of descriptors
9362306a36Sopenharmony_ci */
9462306a36Sopenharmony_cistatic u16 ice_get_tx_pending(struct ice_tx_ring *ring)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	u16 head, tail;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	head = ring->next_to_clean;
9962306a36Sopenharmony_ci	tail = ring->next_to_use;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (head != tail)
10262306a36Sopenharmony_ci		return (head < tail) ?
10362306a36Sopenharmony_ci			tail - head : (tail + ring->count - head);
10462306a36Sopenharmony_ci	return 0;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci/**
10862306a36Sopenharmony_ci * ice_check_for_hang_subtask - check for and recover hung queues
10962306a36Sopenharmony_ci * @pf: pointer to PF struct
11062306a36Sopenharmony_ci */
11162306a36Sopenharmony_cistatic void ice_check_for_hang_subtask(struct ice_pf *pf)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	struct ice_vsi *vsi = NULL;
11462306a36Sopenharmony_ci	struct ice_hw *hw;
11562306a36Sopenharmony_ci	unsigned int i;
11662306a36Sopenharmony_ci	int packets;
11762306a36Sopenharmony_ci	u32 v;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	ice_for_each_vsi(pf, v)
12062306a36Sopenharmony_ci		if (pf->vsi[v] && pf->vsi[v]->type == ICE_VSI_PF) {
12162306a36Sopenharmony_ci			vsi = pf->vsi[v];
12262306a36Sopenharmony_ci			break;
12362306a36Sopenharmony_ci		}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	if (!vsi || test_bit(ICE_VSI_DOWN, vsi->state))
12662306a36Sopenharmony_ci		return;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	if (!(vsi->netdev && netif_carrier_ok(vsi->netdev)))
12962306a36Sopenharmony_ci		return;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	hw = &vsi->back->hw;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	ice_for_each_txq(vsi, i) {
13462306a36Sopenharmony_ci		struct ice_tx_ring *tx_ring = vsi->tx_rings[i];
13562306a36Sopenharmony_ci		struct ice_ring_stats *ring_stats;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci		if (!tx_ring)
13862306a36Sopenharmony_ci			continue;
13962306a36Sopenharmony_ci		if (ice_ring_ch_enabled(tx_ring))
14062306a36Sopenharmony_ci			continue;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci		ring_stats = tx_ring->ring_stats;
14362306a36Sopenharmony_ci		if (!ring_stats)
14462306a36Sopenharmony_ci			continue;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci		if (tx_ring->desc) {
14762306a36Sopenharmony_ci			/* If packet counter has not changed the queue is
14862306a36Sopenharmony_ci			 * likely stalled, so force an interrupt for this
14962306a36Sopenharmony_ci			 * queue.
15062306a36Sopenharmony_ci			 *
15162306a36Sopenharmony_ci			 * prev_pkt would be negative if there was no
15262306a36Sopenharmony_ci			 * pending work.
15362306a36Sopenharmony_ci			 */
15462306a36Sopenharmony_ci			packets = ring_stats->stats.pkts & INT_MAX;
15562306a36Sopenharmony_ci			if (ring_stats->tx_stats.prev_pkt == packets) {
15662306a36Sopenharmony_ci				/* Trigger sw interrupt to revive the queue */
15762306a36Sopenharmony_ci				ice_trigger_sw_intr(hw, tx_ring->q_vector);
15862306a36Sopenharmony_ci				continue;
15962306a36Sopenharmony_ci			}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci			/* Memory barrier between read of packet count and call
16262306a36Sopenharmony_ci			 * to ice_get_tx_pending()
16362306a36Sopenharmony_ci			 */
16462306a36Sopenharmony_ci			smp_rmb();
16562306a36Sopenharmony_ci			ring_stats->tx_stats.prev_pkt =
16662306a36Sopenharmony_ci			    ice_get_tx_pending(tx_ring) ? packets : -1;
16762306a36Sopenharmony_ci		}
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci/**
17262306a36Sopenharmony_ci * ice_init_mac_fltr - Set initial MAC filters
17362306a36Sopenharmony_ci * @pf: board private structure
17462306a36Sopenharmony_ci *
17562306a36Sopenharmony_ci * Set initial set of MAC filters for PF VSI; configure filters for permanent
17662306a36Sopenharmony_ci * address and broadcast address. If an error is encountered, netdevice will be
17762306a36Sopenharmony_ci * unregistered.
17862306a36Sopenharmony_ci */
17962306a36Sopenharmony_cistatic int ice_init_mac_fltr(struct ice_pf *pf)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	struct ice_vsi *vsi;
18262306a36Sopenharmony_ci	u8 *perm_addr;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	vsi = ice_get_main_vsi(pf);
18562306a36Sopenharmony_ci	if (!vsi)
18662306a36Sopenharmony_ci		return -EINVAL;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	perm_addr = vsi->port_info->mac.perm_addr;
18962306a36Sopenharmony_ci	return ice_fltr_add_mac_and_broadcast(vsi, perm_addr, ICE_FWD_TO_VSI);
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci/**
19362306a36Sopenharmony_ci * ice_add_mac_to_sync_list - creates list of MAC addresses to be synced
19462306a36Sopenharmony_ci * @netdev: the net device on which the sync is happening
19562306a36Sopenharmony_ci * @addr: MAC address to sync
19662306a36Sopenharmony_ci *
19762306a36Sopenharmony_ci * This is a callback function which is called by the in kernel device sync
19862306a36Sopenharmony_ci * functions (like __dev_uc_sync, __dev_mc_sync, etc). This function only
19962306a36Sopenharmony_ci * populates the tmp_sync_list, which is later used by ice_add_mac to add the
20062306a36Sopenharmony_ci * MAC filters from the hardware.
20162306a36Sopenharmony_ci */
20262306a36Sopenharmony_cistatic int ice_add_mac_to_sync_list(struct net_device *netdev, const u8 *addr)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
20562306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	if (ice_fltr_add_mac_to_list(vsi, &vsi->tmp_sync_list, addr,
20862306a36Sopenharmony_ci				     ICE_FWD_TO_VSI))
20962306a36Sopenharmony_ci		return -EINVAL;
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	return 0;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci/**
21562306a36Sopenharmony_ci * ice_add_mac_to_unsync_list - creates list of MAC addresses to be unsynced
21662306a36Sopenharmony_ci * @netdev: the net device on which the unsync is happening
21762306a36Sopenharmony_ci * @addr: MAC address to unsync
21862306a36Sopenharmony_ci *
21962306a36Sopenharmony_ci * This is a callback function which is called by the in kernel device unsync
22062306a36Sopenharmony_ci * functions (like __dev_uc_unsync, __dev_mc_unsync, etc). This function only
22162306a36Sopenharmony_ci * populates the tmp_unsync_list, which is later used by ice_remove_mac to
22262306a36Sopenharmony_ci * delete the MAC filters from the hardware.
22362306a36Sopenharmony_ci */
22462306a36Sopenharmony_cistatic int ice_add_mac_to_unsync_list(struct net_device *netdev, const u8 *addr)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
22762306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	/* Under some circumstances, we might receive a request to delete our
23062306a36Sopenharmony_ci	 * own device address from our uc list. Because we store the device
23162306a36Sopenharmony_ci	 * address in the VSI's MAC filter list, we need to ignore such
23262306a36Sopenharmony_ci	 * requests and not delete our device address from this list.
23362306a36Sopenharmony_ci	 */
23462306a36Sopenharmony_ci	if (ether_addr_equal(addr, netdev->dev_addr))
23562306a36Sopenharmony_ci		return 0;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	if (ice_fltr_add_mac_to_list(vsi, &vsi->tmp_unsync_list, addr,
23862306a36Sopenharmony_ci				     ICE_FWD_TO_VSI))
23962306a36Sopenharmony_ci		return -EINVAL;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	return 0;
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci/**
24562306a36Sopenharmony_ci * ice_vsi_fltr_changed - check if filter state changed
24662306a36Sopenharmony_ci * @vsi: VSI to be checked
24762306a36Sopenharmony_ci *
24862306a36Sopenharmony_ci * returns true if filter state has changed, false otherwise.
24962306a36Sopenharmony_ci */
25062306a36Sopenharmony_cistatic bool ice_vsi_fltr_changed(struct ice_vsi *vsi)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	return test_bit(ICE_VSI_UMAC_FLTR_CHANGED, vsi->state) ||
25362306a36Sopenharmony_ci	       test_bit(ICE_VSI_MMAC_FLTR_CHANGED, vsi->state);
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci/**
25762306a36Sopenharmony_ci * ice_set_promisc - Enable promiscuous mode for a given PF
25862306a36Sopenharmony_ci * @vsi: the VSI being configured
25962306a36Sopenharmony_ci * @promisc_m: mask of promiscuous config bits
26062306a36Sopenharmony_ci *
26162306a36Sopenharmony_ci */
26262306a36Sopenharmony_cistatic int ice_set_promisc(struct ice_vsi *vsi, u8 promisc_m)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	int status;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	if (vsi->type != ICE_VSI_PF)
26762306a36Sopenharmony_ci		return 0;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	if (ice_vsi_has_non_zero_vlans(vsi)) {
27062306a36Sopenharmony_ci		promisc_m |= (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX);
27162306a36Sopenharmony_ci		status = ice_fltr_set_vlan_vsi_promisc(&vsi->back->hw, vsi,
27262306a36Sopenharmony_ci						       promisc_m);
27362306a36Sopenharmony_ci	} else {
27462306a36Sopenharmony_ci		status = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx,
27562306a36Sopenharmony_ci						  promisc_m, 0);
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci	if (status && status != -EEXIST)
27862306a36Sopenharmony_ci		return status;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	netdev_dbg(vsi->netdev, "set promisc filter bits for VSI %i: 0x%x\n",
28162306a36Sopenharmony_ci		   vsi->vsi_num, promisc_m);
28262306a36Sopenharmony_ci	return 0;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci/**
28662306a36Sopenharmony_ci * ice_clear_promisc - Disable promiscuous mode for a given PF
28762306a36Sopenharmony_ci * @vsi: the VSI being configured
28862306a36Sopenharmony_ci * @promisc_m: mask of promiscuous config bits
28962306a36Sopenharmony_ci *
29062306a36Sopenharmony_ci */
29162306a36Sopenharmony_cistatic int ice_clear_promisc(struct ice_vsi *vsi, u8 promisc_m)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	int status;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (vsi->type != ICE_VSI_PF)
29662306a36Sopenharmony_ci		return 0;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	if (ice_vsi_has_non_zero_vlans(vsi)) {
29962306a36Sopenharmony_ci		promisc_m |= (ICE_PROMISC_VLAN_RX | ICE_PROMISC_VLAN_TX);
30062306a36Sopenharmony_ci		status = ice_fltr_clear_vlan_vsi_promisc(&vsi->back->hw, vsi,
30162306a36Sopenharmony_ci							 promisc_m);
30262306a36Sopenharmony_ci	} else {
30362306a36Sopenharmony_ci		status = ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx,
30462306a36Sopenharmony_ci						    promisc_m, 0);
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	netdev_dbg(vsi->netdev, "clear promisc filter bits for VSI %i: 0x%x\n",
30862306a36Sopenharmony_ci		   vsi->vsi_num, promisc_m);
30962306a36Sopenharmony_ci	return status;
31062306a36Sopenharmony_ci}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci/**
31362306a36Sopenharmony_ci * ice_vsi_sync_fltr - Update the VSI filter list to the HW
31462306a36Sopenharmony_ci * @vsi: ptr to the VSI
31562306a36Sopenharmony_ci *
31662306a36Sopenharmony_ci * Push any outstanding VSI filter changes through the AdminQ.
31762306a36Sopenharmony_ci */
31862306a36Sopenharmony_cistatic int ice_vsi_sync_fltr(struct ice_vsi *vsi)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	struct ice_vsi_vlan_ops *vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
32162306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(vsi->back);
32262306a36Sopenharmony_ci	struct net_device *netdev = vsi->netdev;
32362306a36Sopenharmony_ci	bool promisc_forced_on = false;
32462306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
32562306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
32662306a36Sopenharmony_ci	u32 changed_flags = 0;
32762306a36Sopenharmony_ci	int err;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	if (!vsi->netdev)
33062306a36Sopenharmony_ci		return -EINVAL;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	while (test_and_set_bit(ICE_CFG_BUSY, vsi->state))
33362306a36Sopenharmony_ci		usleep_range(1000, 2000);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	changed_flags = vsi->current_netdev_flags ^ vsi->netdev->flags;
33662306a36Sopenharmony_ci	vsi->current_netdev_flags = vsi->netdev->flags;
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	INIT_LIST_HEAD(&vsi->tmp_sync_list);
33962306a36Sopenharmony_ci	INIT_LIST_HEAD(&vsi->tmp_unsync_list);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	if (ice_vsi_fltr_changed(vsi)) {
34262306a36Sopenharmony_ci		clear_bit(ICE_VSI_UMAC_FLTR_CHANGED, vsi->state);
34362306a36Sopenharmony_ci		clear_bit(ICE_VSI_MMAC_FLTR_CHANGED, vsi->state);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci		/* grab the netdev's addr_list_lock */
34662306a36Sopenharmony_ci		netif_addr_lock_bh(netdev);
34762306a36Sopenharmony_ci		__dev_uc_sync(netdev, ice_add_mac_to_sync_list,
34862306a36Sopenharmony_ci			      ice_add_mac_to_unsync_list);
34962306a36Sopenharmony_ci		__dev_mc_sync(netdev, ice_add_mac_to_sync_list,
35062306a36Sopenharmony_ci			      ice_add_mac_to_unsync_list);
35162306a36Sopenharmony_ci		/* our temp lists are populated. release lock */
35262306a36Sopenharmony_ci		netif_addr_unlock_bh(netdev);
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	/* Remove MAC addresses in the unsync list */
35662306a36Sopenharmony_ci	err = ice_fltr_remove_mac_list(vsi, &vsi->tmp_unsync_list);
35762306a36Sopenharmony_ci	ice_fltr_free_list(dev, &vsi->tmp_unsync_list);
35862306a36Sopenharmony_ci	if (err) {
35962306a36Sopenharmony_ci		netdev_err(netdev, "Failed to delete MAC filters\n");
36062306a36Sopenharmony_ci		/* if we failed because of alloc failures, just bail */
36162306a36Sopenharmony_ci		if (err == -ENOMEM)
36262306a36Sopenharmony_ci			goto out;
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	/* Add MAC addresses in the sync list */
36662306a36Sopenharmony_ci	err = ice_fltr_add_mac_list(vsi, &vsi->tmp_sync_list);
36762306a36Sopenharmony_ci	ice_fltr_free_list(dev, &vsi->tmp_sync_list);
36862306a36Sopenharmony_ci	/* If filter is added successfully or already exists, do not go into
36962306a36Sopenharmony_ci	 * 'if' condition and report it as error. Instead continue processing
37062306a36Sopenharmony_ci	 * rest of the function.
37162306a36Sopenharmony_ci	 */
37262306a36Sopenharmony_ci	if (err && err != -EEXIST) {
37362306a36Sopenharmony_ci		netdev_err(netdev, "Failed to add MAC filters\n");
37462306a36Sopenharmony_ci		/* If there is no more space for new umac filters, VSI
37562306a36Sopenharmony_ci		 * should go into promiscuous mode. There should be some
37662306a36Sopenharmony_ci		 * space reserved for promiscuous filters.
37762306a36Sopenharmony_ci		 */
37862306a36Sopenharmony_ci		if (hw->adminq.sq_last_status == ICE_AQ_RC_ENOSPC &&
37962306a36Sopenharmony_ci		    !test_and_set_bit(ICE_FLTR_OVERFLOW_PROMISC,
38062306a36Sopenharmony_ci				      vsi->state)) {
38162306a36Sopenharmony_ci			promisc_forced_on = true;
38262306a36Sopenharmony_ci			netdev_warn(netdev, "Reached MAC filter limit, forcing promisc mode on VSI %d\n",
38362306a36Sopenharmony_ci				    vsi->vsi_num);
38462306a36Sopenharmony_ci		} else {
38562306a36Sopenharmony_ci			goto out;
38662306a36Sopenharmony_ci		}
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci	err = 0;
38962306a36Sopenharmony_ci	/* check for changes in promiscuous modes */
39062306a36Sopenharmony_ci	if (changed_flags & IFF_ALLMULTI) {
39162306a36Sopenharmony_ci		if (vsi->current_netdev_flags & IFF_ALLMULTI) {
39262306a36Sopenharmony_ci			err = ice_set_promisc(vsi, ICE_MCAST_PROMISC_BITS);
39362306a36Sopenharmony_ci			if (err) {
39462306a36Sopenharmony_ci				vsi->current_netdev_flags &= ~IFF_ALLMULTI;
39562306a36Sopenharmony_ci				goto out_promisc;
39662306a36Sopenharmony_ci			}
39762306a36Sopenharmony_ci		} else {
39862306a36Sopenharmony_ci			/* !(vsi->current_netdev_flags & IFF_ALLMULTI) */
39962306a36Sopenharmony_ci			err = ice_clear_promisc(vsi, ICE_MCAST_PROMISC_BITS);
40062306a36Sopenharmony_ci			if (err) {
40162306a36Sopenharmony_ci				vsi->current_netdev_flags |= IFF_ALLMULTI;
40262306a36Sopenharmony_ci				goto out_promisc;
40362306a36Sopenharmony_ci			}
40462306a36Sopenharmony_ci		}
40562306a36Sopenharmony_ci	}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	if (((changed_flags & IFF_PROMISC) || promisc_forced_on) ||
40862306a36Sopenharmony_ci	    test_bit(ICE_VSI_PROMISC_CHANGED, vsi->state)) {
40962306a36Sopenharmony_ci		clear_bit(ICE_VSI_PROMISC_CHANGED, vsi->state);
41062306a36Sopenharmony_ci		if (vsi->current_netdev_flags & IFF_PROMISC) {
41162306a36Sopenharmony_ci			/* Apply Rx filter rule to get traffic from wire */
41262306a36Sopenharmony_ci			if (!ice_is_dflt_vsi_in_use(vsi->port_info)) {
41362306a36Sopenharmony_ci				err = ice_set_dflt_vsi(vsi);
41462306a36Sopenharmony_ci				if (err && err != -EEXIST) {
41562306a36Sopenharmony_ci					netdev_err(netdev, "Error %d setting default VSI %i Rx rule\n",
41662306a36Sopenharmony_ci						   err, vsi->vsi_num);
41762306a36Sopenharmony_ci					vsi->current_netdev_flags &=
41862306a36Sopenharmony_ci						~IFF_PROMISC;
41962306a36Sopenharmony_ci					goto out_promisc;
42062306a36Sopenharmony_ci				}
42162306a36Sopenharmony_ci				err = 0;
42262306a36Sopenharmony_ci				vlan_ops->dis_rx_filtering(vsi);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci				/* promiscuous mode implies allmulticast so
42562306a36Sopenharmony_ci				 * that VSIs that are in promiscuous mode are
42662306a36Sopenharmony_ci				 * subscribed to multicast packets coming to
42762306a36Sopenharmony_ci				 * the port
42862306a36Sopenharmony_ci				 */
42962306a36Sopenharmony_ci				err = ice_set_promisc(vsi,
43062306a36Sopenharmony_ci						      ICE_MCAST_PROMISC_BITS);
43162306a36Sopenharmony_ci				if (err)
43262306a36Sopenharmony_ci					goto out_promisc;
43362306a36Sopenharmony_ci			}
43462306a36Sopenharmony_ci		} else {
43562306a36Sopenharmony_ci			/* Clear Rx filter to remove traffic from wire */
43662306a36Sopenharmony_ci			if (ice_is_vsi_dflt_vsi(vsi)) {
43762306a36Sopenharmony_ci				err = ice_clear_dflt_vsi(vsi);
43862306a36Sopenharmony_ci				if (err) {
43962306a36Sopenharmony_ci					netdev_err(netdev, "Error %d clearing default VSI %i Rx rule\n",
44062306a36Sopenharmony_ci						   err, vsi->vsi_num);
44162306a36Sopenharmony_ci					vsi->current_netdev_flags |=
44262306a36Sopenharmony_ci						IFF_PROMISC;
44362306a36Sopenharmony_ci					goto out_promisc;
44462306a36Sopenharmony_ci				}
44562306a36Sopenharmony_ci				if (vsi->netdev->features &
44662306a36Sopenharmony_ci				    NETIF_F_HW_VLAN_CTAG_FILTER)
44762306a36Sopenharmony_ci					vlan_ops->ena_rx_filtering(vsi);
44862306a36Sopenharmony_ci			}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci			/* disable allmulti here, but only if allmulti is not
45162306a36Sopenharmony_ci			 * still enabled for the netdev
45262306a36Sopenharmony_ci			 */
45362306a36Sopenharmony_ci			if (!(vsi->current_netdev_flags & IFF_ALLMULTI)) {
45462306a36Sopenharmony_ci				err = ice_clear_promisc(vsi,
45562306a36Sopenharmony_ci							ICE_MCAST_PROMISC_BITS);
45662306a36Sopenharmony_ci				if (err) {
45762306a36Sopenharmony_ci					netdev_err(netdev, "Error %d clearing multicast promiscuous on VSI %i\n",
45862306a36Sopenharmony_ci						   err, vsi->vsi_num);
45962306a36Sopenharmony_ci				}
46062306a36Sopenharmony_ci			}
46162306a36Sopenharmony_ci		}
46262306a36Sopenharmony_ci	}
46362306a36Sopenharmony_ci	goto exit;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ciout_promisc:
46662306a36Sopenharmony_ci	set_bit(ICE_VSI_PROMISC_CHANGED, vsi->state);
46762306a36Sopenharmony_ci	goto exit;
46862306a36Sopenharmony_ciout:
46962306a36Sopenharmony_ci	/* if something went wrong then set the changed flag so we try again */
47062306a36Sopenharmony_ci	set_bit(ICE_VSI_UMAC_FLTR_CHANGED, vsi->state);
47162306a36Sopenharmony_ci	set_bit(ICE_VSI_MMAC_FLTR_CHANGED, vsi->state);
47262306a36Sopenharmony_ciexit:
47362306a36Sopenharmony_ci	clear_bit(ICE_CFG_BUSY, vsi->state);
47462306a36Sopenharmony_ci	return err;
47562306a36Sopenharmony_ci}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci/**
47862306a36Sopenharmony_ci * ice_sync_fltr_subtask - Sync the VSI filter list with HW
47962306a36Sopenharmony_ci * @pf: board private structure
48062306a36Sopenharmony_ci */
48162306a36Sopenharmony_cistatic void ice_sync_fltr_subtask(struct ice_pf *pf)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	int v;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	if (!pf || !(test_bit(ICE_FLAG_FLTR_SYNC, pf->flags)))
48662306a36Sopenharmony_ci		return;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	clear_bit(ICE_FLAG_FLTR_SYNC, pf->flags);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	ice_for_each_vsi(pf, v)
49162306a36Sopenharmony_ci		if (pf->vsi[v] && ice_vsi_fltr_changed(pf->vsi[v]) &&
49262306a36Sopenharmony_ci		    ice_vsi_sync_fltr(pf->vsi[v])) {
49362306a36Sopenharmony_ci			/* come back and try again later */
49462306a36Sopenharmony_ci			set_bit(ICE_FLAG_FLTR_SYNC, pf->flags);
49562306a36Sopenharmony_ci			break;
49662306a36Sopenharmony_ci		}
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci/**
50062306a36Sopenharmony_ci * ice_pf_dis_all_vsi - Pause all VSIs on a PF
50162306a36Sopenharmony_ci * @pf: the PF
50262306a36Sopenharmony_ci * @locked: is the rtnl_lock already held
50362306a36Sopenharmony_ci */
50462306a36Sopenharmony_cistatic void ice_pf_dis_all_vsi(struct ice_pf *pf, bool locked)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	int node;
50762306a36Sopenharmony_ci	int v;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	ice_for_each_vsi(pf, v)
51062306a36Sopenharmony_ci		if (pf->vsi[v])
51162306a36Sopenharmony_ci			ice_dis_vsi(pf->vsi[v], locked);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	for (node = 0; node < ICE_MAX_PF_AGG_NODES; node++)
51462306a36Sopenharmony_ci		pf->pf_agg_node[node].num_vsis = 0;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	for (node = 0; node < ICE_MAX_VF_AGG_NODES; node++)
51762306a36Sopenharmony_ci		pf->vf_agg_node[node].num_vsis = 0;
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci/**
52162306a36Sopenharmony_ci * ice_clear_sw_switch_recipes - clear switch recipes
52262306a36Sopenharmony_ci * @pf: board private structure
52362306a36Sopenharmony_ci *
52462306a36Sopenharmony_ci * Mark switch recipes as not created in sw structures. There are cases where
52562306a36Sopenharmony_ci * rules (especially advanced rules) need to be restored, either re-read from
52662306a36Sopenharmony_ci * hardware or added again. For example after the reset. 'recp_created' flag
52762306a36Sopenharmony_ci * prevents from doing that and need to be cleared upfront.
52862306a36Sopenharmony_ci */
52962306a36Sopenharmony_cistatic void ice_clear_sw_switch_recipes(struct ice_pf *pf)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	struct ice_sw_recipe *recp;
53262306a36Sopenharmony_ci	u8 i;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	recp = pf->hw.switch_info->recp_list;
53562306a36Sopenharmony_ci	for (i = 0; i < ICE_MAX_NUM_RECIPES; i++)
53662306a36Sopenharmony_ci		recp[i].recp_created = false;
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci/**
54062306a36Sopenharmony_ci * ice_prepare_for_reset - prep for reset
54162306a36Sopenharmony_ci * @pf: board private structure
54262306a36Sopenharmony_ci * @reset_type: reset type requested
54362306a36Sopenharmony_ci *
54462306a36Sopenharmony_ci * Inform or close all dependent features in prep for reset.
54562306a36Sopenharmony_ci */
54662306a36Sopenharmony_cistatic void
54762306a36Sopenharmony_ciice_prepare_for_reset(struct ice_pf *pf, enum ice_reset_req reset_type)
54862306a36Sopenharmony_ci{
54962306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
55062306a36Sopenharmony_ci	struct ice_vsi *vsi;
55162306a36Sopenharmony_ci	struct ice_vf *vf;
55262306a36Sopenharmony_ci	unsigned int bkt;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	dev_dbg(ice_pf_to_dev(pf), "reset_type=%d\n", reset_type);
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	/* already prepared for reset */
55762306a36Sopenharmony_ci	if (test_bit(ICE_PREPARED_FOR_RESET, pf->state))
55862306a36Sopenharmony_ci		return;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	ice_unplug_aux_dev(pf);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	/* Notify VFs of impending reset */
56362306a36Sopenharmony_ci	if (ice_check_sq_alive(hw, &hw->mailboxq))
56462306a36Sopenharmony_ci		ice_vc_notify_reset(pf);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	/* Disable VFs until reset is completed */
56762306a36Sopenharmony_ci	mutex_lock(&pf->vfs.table_lock);
56862306a36Sopenharmony_ci	ice_for_each_vf(pf, bkt, vf)
56962306a36Sopenharmony_ci		ice_set_vf_state_dis(vf);
57062306a36Sopenharmony_ci	mutex_unlock(&pf->vfs.table_lock);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	if (ice_is_eswitch_mode_switchdev(pf)) {
57362306a36Sopenharmony_ci		if (reset_type != ICE_RESET_PFR)
57462306a36Sopenharmony_ci			ice_clear_sw_switch_recipes(pf);
57562306a36Sopenharmony_ci	}
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	/* release ADQ specific HW and SW resources */
57862306a36Sopenharmony_ci	vsi = ice_get_main_vsi(pf);
57962306a36Sopenharmony_ci	if (!vsi)
58062306a36Sopenharmony_ci		goto skip;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	/* to be on safe side, reset orig_rss_size so that normal flow
58362306a36Sopenharmony_ci	 * of deciding rss_size can take precedence
58462306a36Sopenharmony_ci	 */
58562306a36Sopenharmony_ci	vsi->orig_rss_size = 0;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_TC_MQPRIO, pf->flags)) {
58862306a36Sopenharmony_ci		if (reset_type == ICE_RESET_PFR) {
58962306a36Sopenharmony_ci			vsi->old_ena_tc = vsi->all_enatc;
59062306a36Sopenharmony_ci			vsi->old_numtc = vsi->all_numtc;
59162306a36Sopenharmony_ci		} else {
59262306a36Sopenharmony_ci			ice_remove_q_channels(vsi, true);
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci			/* for other reset type, do not support channel rebuild
59562306a36Sopenharmony_ci			 * hence reset needed info
59662306a36Sopenharmony_ci			 */
59762306a36Sopenharmony_ci			vsi->old_ena_tc = 0;
59862306a36Sopenharmony_ci			vsi->all_enatc = 0;
59962306a36Sopenharmony_ci			vsi->old_numtc = 0;
60062306a36Sopenharmony_ci			vsi->all_numtc = 0;
60162306a36Sopenharmony_ci			vsi->req_txq = 0;
60262306a36Sopenharmony_ci			vsi->req_rxq = 0;
60362306a36Sopenharmony_ci			clear_bit(ICE_FLAG_TC_MQPRIO, pf->flags);
60462306a36Sopenharmony_ci			memset(&vsi->mqprio_qopt, 0, sizeof(vsi->mqprio_qopt));
60562306a36Sopenharmony_ci		}
60662306a36Sopenharmony_ci	}
60762306a36Sopenharmony_ciskip:
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/* clear SW filtering DB */
61062306a36Sopenharmony_ci	ice_clear_hw_tbls(hw);
61162306a36Sopenharmony_ci	/* disable the VSIs and their queues that are not already DOWN */
61262306a36Sopenharmony_ci	ice_pf_dis_all_vsi(pf, false);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags))
61562306a36Sopenharmony_ci		ice_ptp_prepare_for_reset(pf);
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	if (ice_is_feature_supported(pf, ICE_F_GNSS))
61862306a36Sopenharmony_ci		ice_gnss_exit(pf);
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	if (hw->port_info)
62162306a36Sopenharmony_ci		ice_sched_clear_port(hw->port_info);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	ice_shutdown_all_ctrlq(hw);
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci	set_bit(ICE_PREPARED_FOR_RESET, pf->state);
62662306a36Sopenharmony_ci}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci/**
62962306a36Sopenharmony_ci * ice_do_reset - Initiate one of many types of resets
63062306a36Sopenharmony_ci * @pf: board private structure
63162306a36Sopenharmony_ci * @reset_type: reset type requested before this function was called.
63262306a36Sopenharmony_ci */
63362306a36Sopenharmony_cistatic void ice_do_reset(struct ice_pf *pf, enum ice_reset_req reset_type)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
63662306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	dev_dbg(dev, "reset_type 0x%x requested\n", reset_type);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	if (pf->lag && pf->lag->bonded && reset_type == ICE_RESET_PFR) {
64162306a36Sopenharmony_ci		dev_dbg(dev, "PFR on a bonded interface, promoting to CORER\n");
64262306a36Sopenharmony_ci		reset_type = ICE_RESET_CORER;
64362306a36Sopenharmony_ci	}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	ice_prepare_for_reset(pf, reset_type);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	/* trigger the reset */
64862306a36Sopenharmony_ci	if (ice_reset(hw, reset_type)) {
64962306a36Sopenharmony_ci		dev_err(dev, "reset %d failed\n", reset_type);
65062306a36Sopenharmony_ci		set_bit(ICE_RESET_FAILED, pf->state);
65162306a36Sopenharmony_ci		clear_bit(ICE_RESET_OICR_RECV, pf->state);
65262306a36Sopenharmony_ci		clear_bit(ICE_PREPARED_FOR_RESET, pf->state);
65362306a36Sopenharmony_ci		clear_bit(ICE_PFR_REQ, pf->state);
65462306a36Sopenharmony_ci		clear_bit(ICE_CORER_REQ, pf->state);
65562306a36Sopenharmony_ci		clear_bit(ICE_GLOBR_REQ, pf->state);
65662306a36Sopenharmony_ci		wake_up(&pf->reset_wait_queue);
65762306a36Sopenharmony_ci		return;
65862306a36Sopenharmony_ci	}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	/* PFR is a bit of a special case because it doesn't result in an OICR
66162306a36Sopenharmony_ci	 * interrupt. So for PFR, rebuild after the reset and clear the reset-
66262306a36Sopenharmony_ci	 * associated state bits.
66362306a36Sopenharmony_ci	 */
66462306a36Sopenharmony_ci	if (reset_type == ICE_RESET_PFR) {
66562306a36Sopenharmony_ci		pf->pfr_count++;
66662306a36Sopenharmony_ci		ice_rebuild(pf, reset_type);
66762306a36Sopenharmony_ci		clear_bit(ICE_PREPARED_FOR_RESET, pf->state);
66862306a36Sopenharmony_ci		clear_bit(ICE_PFR_REQ, pf->state);
66962306a36Sopenharmony_ci		wake_up(&pf->reset_wait_queue);
67062306a36Sopenharmony_ci		ice_reset_all_vfs(pf);
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci/**
67562306a36Sopenharmony_ci * ice_reset_subtask - Set up for resetting the device and driver
67662306a36Sopenharmony_ci * @pf: board private structure
67762306a36Sopenharmony_ci */
67862306a36Sopenharmony_cistatic void ice_reset_subtask(struct ice_pf *pf)
67962306a36Sopenharmony_ci{
68062306a36Sopenharmony_ci	enum ice_reset_req reset_type = ICE_RESET_INVAL;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	/* When a CORER/GLOBR/EMPR is about to happen, the hardware triggers an
68362306a36Sopenharmony_ci	 * OICR interrupt. The OICR handler (ice_misc_intr) determines what type
68462306a36Sopenharmony_ci	 * of reset is pending and sets bits in pf->state indicating the reset
68562306a36Sopenharmony_ci	 * type and ICE_RESET_OICR_RECV. So, if the latter bit is set
68662306a36Sopenharmony_ci	 * prepare for pending reset if not already (for PF software-initiated
68762306a36Sopenharmony_ci	 * global resets the software should already be prepared for it as
68862306a36Sopenharmony_ci	 * indicated by ICE_PREPARED_FOR_RESET; for global resets initiated
68962306a36Sopenharmony_ci	 * by firmware or software on other PFs, that bit is not set so prepare
69062306a36Sopenharmony_ci	 * for the reset now), poll for reset done, rebuild and return.
69162306a36Sopenharmony_ci	 */
69262306a36Sopenharmony_ci	if (test_bit(ICE_RESET_OICR_RECV, pf->state)) {
69362306a36Sopenharmony_ci		/* Perform the largest reset requested */
69462306a36Sopenharmony_ci		if (test_and_clear_bit(ICE_CORER_RECV, pf->state))
69562306a36Sopenharmony_ci			reset_type = ICE_RESET_CORER;
69662306a36Sopenharmony_ci		if (test_and_clear_bit(ICE_GLOBR_RECV, pf->state))
69762306a36Sopenharmony_ci			reset_type = ICE_RESET_GLOBR;
69862306a36Sopenharmony_ci		if (test_and_clear_bit(ICE_EMPR_RECV, pf->state))
69962306a36Sopenharmony_ci			reset_type = ICE_RESET_EMPR;
70062306a36Sopenharmony_ci		/* return if no valid reset type requested */
70162306a36Sopenharmony_ci		if (reset_type == ICE_RESET_INVAL)
70262306a36Sopenharmony_ci			return;
70362306a36Sopenharmony_ci		ice_prepare_for_reset(pf, reset_type);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci		/* make sure we are ready to rebuild */
70662306a36Sopenharmony_ci		if (ice_check_reset(&pf->hw)) {
70762306a36Sopenharmony_ci			set_bit(ICE_RESET_FAILED, pf->state);
70862306a36Sopenharmony_ci		} else {
70962306a36Sopenharmony_ci			/* done with reset. start rebuild */
71062306a36Sopenharmony_ci			pf->hw.reset_ongoing = false;
71162306a36Sopenharmony_ci			ice_rebuild(pf, reset_type);
71262306a36Sopenharmony_ci			/* clear bit to resume normal operations, but
71362306a36Sopenharmony_ci			 * ICE_NEEDS_RESTART bit is set in case rebuild failed
71462306a36Sopenharmony_ci			 */
71562306a36Sopenharmony_ci			clear_bit(ICE_RESET_OICR_RECV, pf->state);
71662306a36Sopenharmony_ci			clear_bit(ICE_PREPARED_FOR_RESET, pf->state);
71762306a36Sopenharmony_ci			clear_bit(ICE_PFR_REQ, pf->state);
71862306a36Sopenharmony_ci			clear_bit(ICE_CORER_REQ, pf->state);
71962306a36Sopenharmony_ci			clear_bit(ICE_GLOBR_REQ, pf->state);
72062306a36Sopenharmony_ci			wake_up(&pf->reset_wait_queue);
72162306a36Sopenharmony_ci			ice_reset_all_vfs(pf);
72262306a36Sopenharmony_ci		}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci		return;
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci	/* No pending resets to finish processing. Check for new resets */
72862306a36Sopenharmony_ci	if (test_bit(ICE_PFR_REQ, pf->state)) {
72962306a36Sopenharmony_ci		reset_type = ICE_RESET_PFR;
73062306a36Sopenharmony_ci		if (pf->lag && pf->lag->bonded) {
73162306a36Sopenharmony_ci			dev_dbg(ice_pf_to_dev(pf), "PFR on a bonded interface, promoting to CORER\n");
73262306a36Sopenharmony_ci			reset_type = ICE_RESET_CORER;
73362306a36Sopenharmony_ci		}
73462306a36Sopenharmony_ci	}
73562306a36Sopenharmony_ci	if (test_bit(ICE_CORER_REQ, pf->state))
73662306a36Sopenharmony_ci		reset_type = ICE_RESET_CORER;
73762306a36Sopenharmony_ci	if (test_bit(ICE_GLOBR_REQ, pf->state))
73862306a36Sopenharmony_ci		reset_type = ICE_RESET_GLOBR;
73962306a36Sopenharmony_ci	/* If no valid reset type requested just return */
74062306a36Sopenharmony_ci	if (reset_type == ICE_RESET_INVAL)
74162306a36Sopenharmony_ci		return;
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	/* reset if not already down or busy */
74462306a36Sopenharmony_ci	if (!test_bit(ICE_DOWN, pf->state) &&
74562306a36Sopenharmony_ci	    !test_bit(ICE_CFG_BUSY, pf->state)) {
74662306a36Sopenharmony_ci		ice_do_reset(pf, reset_type);
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci/**
75162306a36Sopenharmony_ci * ice_print_topo_conflict - print topology conflict message
75262306a36Sopenharmony_ci * @vsi: the VSI whose topology status is being checked
75362306a36Sopenharmony_ci */
75462306a36Sopenharmony_cistatic void ice_print_topo_conflict(struct ice_vsi *vsi)
75562306a36Sopenharmony_ci{
75662306a36Sopenharmony_ci	switch (vsi->port_info->phy.link_info.topo_media_conflict) {
75762306a36Sopenharmony_ci	case ICE_AQ_LINK_TOPO_CONFLICT:
75862306a36Sopenharmony_ci	case ICE_AQ_LINK_MEDIA_CONFLICT:
75962306a36Sopenharmony_ci	case ICE_AQ_LINK_TOPO_UNREACH_PRT:
76062306a36Sopenharmony_ci	case ICE_AQ_LINK_TOPO_UNDRUTIL_PRT:
76162306a36Sopenharmony_ci	case ICE_AQ_LINK_TOPO_UNDRUTIL_MEDIA:
76262306a36Sopenharmony_ci		netdev_info(vsi->netdev, "Potential misconfiguration of the Ethernet port detected. If it was not intended, please use the Intel (R) Ethernet Port Configuration Tool to address the issue.\n");
76362306a36Sopenharmony_ci		break;
76462306a36Sopenharmony_ci	case ICE_AQ_LINK_TOPO_UNSUPP_MEDIA:
76562306a36Sopenharmony_ci		if (test_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, vsi->back->flags))
76662306a36Sopenharmony_ci			netdev_warn(vsi->netdev, "An unsupported module type was detected. Refer to the Intel(R) Ethernet Adapters and Devices User Guide for a list of supported modules\n");
76762306a36Sopenharmony_ci		else
76862306a36Sopenharmony_ci			netdev_err(vsi->netdev, "Rx/Tx is disabled on this device because an unsupported module type was detected. Refer to the Intel(R) Ethernet Adapters and Devices User Guide for a list of supported modules.\n");
76962306a36Sopenharmony_ci		break;
77062306a36Sopenharmony_ci	default:
77162306a36Sopenharmony_ci		break;
77262306a36Sopenharmony_ci	}
77362306a36Sopenharmony_ci}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci/**
77662306a36Sopenharmony_ci * ice_print_link_msg - print link up or down message
77762306a36Sopenharmony_ci * @vsi: the VSI whose link status is being queried
77862306a36Sopenharmony_ci * @isup: boolean for if the link is now up or down
77962306a36Sopenharmony_ci */
78062306a36Sopenharmony_civoid ice_print_link_msg(struct ice_vsi *vsi, bool isup)
78162306a36Sopenharmony_ci{
78262306a36Sopenharmony_ci	struct ice_aqc_get_phy_caps_data *caps;
78362306a36Sopenharmony_ci	const char *an_advertised;
78462306a36Sopenharmony_ci	const char *fec_req;
78562306a36Sopenharmony_ci	const char *speed;
78662306a36Sopenharmony_ci	const char *fec;
78762306a36Sopenharmony_ci	const char *fc;
78862306a36Sopenharmony_ci	const char *an;
78962306a36Sopenharmony_ci	int status;
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	if (!vsi)
79262306a36Sopenharmony_ci		return;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	if (vsi->current_isup == isup)
79562306a36Sopenharmony_ci		return;
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	vsi->current_isup = isup;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	if (!isup) {
80062306a36Sopenharmony_ci		netdev_info(vsi->netdev, "NIC Link is Down\n");
80162306a36Sopenharmony_ci		return;
80262306a36Sopenharmony_ci	}
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	switch (vsi->port_info->phy.link_info.link_speed) {
80562306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_100GB:
80662306a36Sopenharmony_ci		speed = "100 G";
80762306a36Sopenharmony_ci		break;
80862306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_50GB:
80962306a36Sopenharmony_ci		speed = "50 G";
81062306a36Sopenharmony_ci		break;
81162306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_40GB:
81262306a36Sopenharmony_ci		speed = "40 G";
81362306a36Sopenharmony_ci		break;
81462306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_25GB:
81562306a36Sopenharmony_ci		speed = "25 G";
81662306a36Sopenharmony_ci		break;
81762306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_20GB:
81862306a36Sopenharmony_ci		speed = "20 G";
81962306a36Sopenharmony_ci		break;
82062306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_10GB:
82162306a36Sopenharmony_ci		speed = "10 G";
82262306a36Sopenharmony_ci		break;
82362306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_5GB:
82462306a36Sopenharmony_ci		speed = "5 G";
82562306a36Sopenharmony_ci		break;
82662306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_2500MB:
82762306a36Sopenharmony_ci		speed = "2.5 G";
82862306a36Sopenharmony_ci		break;
82962306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_1000MB:
83062306a36Sopenharmony_ci		speed = "1 G";
83162306a36Sopenharmony_ci		break;
83262306a36Sopenharmony_ci	case ICE_AQ_LINK_SPEED_100MB:
83362306a36Sopenharmony_ci		speed = "100 M";
83462306a36Sopenharmony_ci		break;
83562306a36Sopenharmony_ci	default:
83662306a36Sopenharmony_ci		speed = "Unknown ";
83762306a36Sopenharmony_ci		break;
83862306a36Sopenharmony_ci	}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	switch (vsi->port_info->fc.current_mode) {
84162306a36Sopenharmony_ci	case ICE_FC_FULL:
84262306a36Sopenharmony_ci		fc = "Rx/Tx";
84362306a36Sopenharmony_ci		break;
84462306a36Sopenharmony_ci	case ICE_FC_TX_PAUSE:
84562306a36Sopenharmony_ci		fc = "Tx";
84662306a36Sopenharmony_ci		break;
84762306a36Sopenharmony_ci	case ICE_FC_RX_PAUSE:
84862306a36Sopenharmony_ci		fc = "Rx";
84962306a36Sopenharmony_ci		break;
85062306a36Sopenharmony_ci	case ICE_FC_NONE:
85162306a36Sopenharmony_ci		fc = "None";
85262306a36Sopenharmony_ci		break;
85362306a36Sopenharmony_ci	default:
85462306a36Sopenharmony_ci		fc = "Unknown";
85562306a36Sopenharmony_ci		break;
85662306a36Sopenharmony_ci	}
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	/* Get FEC mode based on negotiated link info */
85962306a36Sopenharmony_ci	switch (vsi->port_info->phy.link_info.fec_info) {
86062306a36Sopenharmony_ci	case ICE_AQ_LINK_25G_RS_528_FEC_EN:
86162306a36Sopenharmony_ci	case ICE_AQ_LINK_25G_RS_544_FEC_EN:
86262306a36Sopenharmony_ci		fec = "RS-FEC";
86362306a36Sopenharmony_ci		break;
86462306a36Sopenharmony_ci	case ICE_AQ_LINK_25G_KR_FEC_EN:
86562306a36Sopenharmony_ci		fec = "FC-FEC/BASE-R";
86662306a36Sopenharmony_ci		break;
86762306a36Sopenharmony_ci	default:
86862306a36Sopenharmony_ci		fec = "NONE";
86962306a36Sopenharmony_ci		break;
87062306a36Sopenharmony_ci	}
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci	/* check if autoneg completed, might be false due to not supported */
87362306a36Sopenharmony_ci	if (vsi->port_info->phy.link_info.an_info & ICE_AQ_AN_COMPLETED)
87462306a36Sopenharmony_ci		an = "True";
87562306a36Sopenharmony_ci	else
87662306a36Sopenharmony_ci		an = "False";
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	/* Get FEC mode requested based on PHY caps last SW configuration */
87962306a36Sopenharmony_ci	caps = kzalloc(sizeof(*caps), GFP_KERNEL);
88062306a36Sopenharmony_ci	if (!caps) {
88162306a36Sopenharmony_ci		fec_req = "Unknown";
88262306a36Sopenharmony_ci		an_advertised = "Unknown";
88362306a36Sopenharmony_ci		goto done;
88462306a36Sopenharmony_ci	}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	status = ice_aq_get_phy_caps(vsi->port_info, false,
88762306a36Sopenharmony_ci				     ICE_AQC_REPORT_ACTIVE_CFG, caps, NULL);
88862306a36Sopenharmony_ci	if (status)
88962306a36Sopenharmony_ci		netdev_info(vsi->netdev, "Get phy capability failed.\n");
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	an_advertised = ice_is_phy_caps_an_enabled(caps) ? "On" : "Off";
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ ||
89462306a36Sopenharmony_ci	    caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ)
89562306a36Sopenharmony_ci		fec_req = "RS-FEC";
89662306a36Sopenharmony_ci	else if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ ||
89762306a36Sopenharmony_ci		 caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ)
89862306a36Sopenharmony_ci		fec_req = "FC-FEC/BASE-R";
89962306a36Sopenharmony_ci	else
90062306a36Sopenharmony_ci		fec_req = "NONE";
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	kfree(caps);
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_cidone:
90562306a36Sopenharmony_ci	netdev_info(vsi->netdev, "NIC Link is up %sbps Full Duplex, Requested FEC: %s, Negotiated FEC: %s, Autoneg Advertised: %s, Autoneg Negotiated: %s, Flow Control: %s\n",
90662306a36Sopenharmony_ci		    speed, fec_req, fec, an_advertised, an, fc);
90762306a36Sopenharmony_ci	ice_print_topo_conflict(vsi);
90862306a36Sopenharmony_ci}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci/**
91162306a36Sopenharmony_ci * ice_vsi_link_event - update the VSI's netdev
91262306a36Sopenharmony_ci * @vsi: the VSI on which the link event occurred
91362306a36Sopenharmony_ci * @link_up: whether or not the VSI needs to be set up or down
91462306a36Sopenharmony_ci */
91562306a36Sopenharmony_cistatic void ice_vsi_link_event(struct ice_vsi *vsi, bool link_up)
91662306a36Sopenharmony_ci{
91762306a36Sopenharmony_ci	if (!vsi)
91862306a36Sopenharmony_ci		return;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	if (test_bit(ICE_VSI_DOWN, vsi->state) || !vsi->netdev)
92162306a36Sopenharmony_ci		return;
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	if (vsi->type == ICE_VSI_PF) {
92462306a36Sopenharmony_ci		if (link_up == netif_carrier_ok(vsi->netdev))
92562306a36Sopenharmony_ci			return;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci		if (link_up) {
92862306a36Sopenharmony_ci			netif_carrier_on(vsi->netdev);
92962306a36Sopenharmony_ci			netif_tx_wake_all_queues(vsi->netdev);
93062306a36Sopenharmony_ci		} else {
93162306a36Sopenharmony_ci			netif_carrier_off(vsi->netdev);
93262306a36Sopenharmony_ci			netif_tx_stop_all_queues(vsi->netdev);
93362306a36Sopenharmony_ci		}
93462306a36Sopenharmony_ci	}
93562306a36Sopenharmony_ci}
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci/**
93862306a36Sopenharmony_ci * ice_set_dflt_mib - send a default config MIB to the FW
93962306a36Sopenharmony_ci * @pf: private PF struct
94062306a36Sopenharmony_ci *
94162306a36Sopenharmony_ci * This function sends a default configuration MIB to the FW.
94262306a36Sopenharmony_ci *
94362306a36Sopenharmony_ci * If this function errors out at any point, the driver is still able to
94462306a36Sopenharmony_ci * function.  The main impact is that LFC may not operate as expected.
94562306a36Sopenharmony_ci * Therefore an error state in this function should be treated with a DBG
94662306a36Sopenharmony_ci * message and continue on with driver rebuild/reenable.
94762306a36Sopenharmony_ci */
94862306a36Sopenharmony_cistatic void ice_set_dflt_mib(struct ice_pf *pf)
94962306a36Sopenharmony_ci{
95062306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
95162306a36Sopenharmony_ci	u8 mib_type, *buf, *lldpmib = NULL;
95262306a36Sopenharmony_ci	u16 len, typelen, offset = 0;
95362306a36Sopenharmony_ci	struct ice_lldp_org_tlv *tlv;
95462306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
95562306a36Sopenharmony_ci	u32 ouisubtype;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	mib_type = SET_LOCAL_MIB_TYPE_LOCAL_MIB;
95862306a36Sopenharmony_ci	lldpmib = kzalloc(ICE_LLDPDU_SIZE, GFP_KERNEL);
95962306a36Sopenharmony_ci	if (!lldpmib) {
96062306a36Sopenharmony_ci		dev_dbg(dev, "%s Failed to allocate MIB memory\n",
96162306a36Sopenharmony_ci			__func__);
96262306a36Sopenharmony_ci		return;
96362306a36Sopenharmony_ci	}
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	/* Add ETS CFG TLV */
96662306a36Sopenharmony_ci	tlv = (struct ice_lldp_org_tlv *)lldpmib;
96762306a36Sopenharmony_ci	typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
96862306a36Sopenharmony_ci		   ICE_IEEE_ETS_TLV_LEN);
96962306a36Sopenharmony_ci	tlv->typelen = htons(typelen);
97062306a36Sopenharmony_ci	ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
97162306a36Sopenharmony_ci		      ICE_IEEE_SUBTYPE_ETS_CFG);
97262306a36Sopenharmony_ci	tlv->ouisubtype = htonl(ouisubtype);
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	buf = tlv->tlvinfo;
97562306a36Sopenharmony_ci	buf[0] = 0;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	/* ETS CFG all UPs map to TC 0. Next 4 (1 - 4) Octets = 0.
97862306a36Sopenharmony_ci	 * Octets 5 - 12 are BW values, set octet 5 to 100% BW.
97962306a36Sopenharmony_ci	 * Octets 13 - 20 are TSA values - leave as zeros
98062306a36Sopenharmony_ci	 */
98162306a36Sopenharmony_ci	buf[5] = 0x64;
98262306a36Sopenharmony_ci	len = (typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S;
98362306a36Sopenharmony_ci	offset += len + 2;
98462306a36Sopenharmony_ci	tlv = (struct ice_lldp_org_tlv *)
98562306a36Sopenharmony_ci		((char *)tlv + sizeof(tlv->typelen) + len);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	/* Add ETS REC TLV */
98862306a36Sopenharmony_ci	buf = tlv->tlvinfo;
98962306a36Sopenharmony_ci	tlv->typelen = htons(typelen);
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
99262306a36Sopenharmony_ci		      ICE_IEEE_SUBTYPE_ETS_REC);
99362306a36Sopenharmony_ci	tlv->ouisubtype = htonl(ouisubtype);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	/* First octet of buf is reserved
99662306a36Sopenharmony_ci	 * Octets 1 - 4 map UP to TC - all UPs map to zero
99762306a36Sopenharmony_ci	 * Octets 5 - 12 are BW values - set TC 0 to 100%.
99862306a36Sopenharmony_ci	 * Octets 13 - 20 are TSA value - leave as zeros
99962306a36Sopenharmony_ci	 */
100062306a36Sopenharmony_ci	buf[5] = 0x64;
100162306a36Sopenharmony_ci	offset += len + 2;
100262306a36Sopenharmony_ci	tlv = (struct ice_lldp_org_tlv *)
100362306a36Sopenharmony_ci		((char *)tlv + sizeof(tlv->typelen) + len);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	/* Add PFC CFG TLV */
100662306a36Sopenharmony_ci	typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) |
100762306a36Sopenharmony_ci		   ICE_IEEE_PFC_TLV_LEN);
100862306a36Sopenharmony_ci	tlv->typelen = htons(typelen);
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) |
101162306a36Sopenharmony_ci		      ICE_IEEE_SUBTYPE_PFC_CFG);
101262306a36Sopenharmony_ci	tlv->ouisubtype = htonl(ouisubtype);
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	/* Octet 1 left as all zeros - PFC disabled */
101562306a36Sopenharmony_ci	buf[0] = 0x08;
101662306a36Sopenharmony_ci	len = (typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S;
101762306a36Sopenharmony_ci	offset += len + 2;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	if (ice_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, offset, NULL))
102062306a36Sopenharmony_ci		dev_dbg(dev, "%s Failed to set default LLDP MIB\n", __func__);
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	kfree(lldpmib);
102362306a36Sopenharmony_ci}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci/**
102662306a36Sopenharmony_ci * ice_check_phy_fw_load - check if PHY FW load failed
102762306a36Sopenharmony_ci * @pf: pointer to PF struct
102862306a36Sopenharmony_ci * @link_cfg_err: bitmap from the link info structure
102962306a36Sopenharmony_ci *
103062306a36Sopenharmony_ci * check if external PHY FW load failed and print an error message if it did
103162306a36Sopenharmony_ci */
103262306a36Sopenharmony_cistatic void ice_check_phy_fw_load(struct ice_pf *pf, u8 link_cfg_err)
103362306a36Sopenharmony_ci{
103462306a36Sopenharmony_ci	if (!(link_cfg_err & ICE_AQ_LINK_EXTERNAL_PHY_LOAD_FAILURE)) {
103562306a36Sopenharmony_ci		clear_bit(ICE_FLAG_PHY_FW_LOAD_FAILED, pf->flags);
103662306a36Sopenharmony_ci		return;
103762306a36Sopenharmony_ci	}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_PHY_FW_LOAD_FAILED, pf->flags))
104062306a36Sopenharmony_ci		return;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	if (link_cfg_err & ICE_AQ_LINK_EXTERNAL_PHY_LOAD_FAILURE) {
104362306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "Device failed to load the FW for the external PHY. Please download and install the latest NVM for your device and try again\n");
104462306a36Sopenharmony_ci		set_bit(ICE_FLAG_PHY_FW_LOAD_FAILED, pf->flags);
104562306a36Sopenharmony_ci	}
104662306a36Sopenharmony_ci}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci/**
104962306a36Sopenharmony_ci * ice_check_module_power
105062306a36Sopenharmony_ci * @pf: pointer to PF struct
105162306a36Sopenharmony_ci * @link_cfg_err: bitmap from the link info structure
105262306a36Sopenharmony_ci *
105362306a36Sopenharmony_ci * check module power level returned by a previous call to aq_get_link_info
105462306a36Sopenharmony_ci * and print error messages if module power level is not supported
105562306a36Sopenharmony_ci */
105662306a36Sopenharmony_cistatic void ice_check_module_power(struct ice_pf *pf, u8 link_cfg_err)
105762306a36Sopenharmony_ci{
105862306a36Sopenharmony_ci	/* if module power level is supported, clear the flag */
105962306a36Sopenharmony_ci	if (!(link_cfg_err & (ICE_AQ_LINK_INVAL_MAX_POWER_LIMIT |
106062306a36Sopenharmony_ci			      ICE_AQ_LINK_MODULE_POWER_UNSUPPORTED))) {
106162306a36Sopenharmony_ci		clear_bit(ICE_FLAG_MOD_POWER_UNSUPPORTED, pf->flags);
106262306a36Sopenharmony_ci		return;
106362306a36Sopenharmony_ci	}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci	/* if ICE_FLAG_MOD_POWER_UNSUPPORTED was previously set and the
106662306a36Sopenharmony_ci	 * above block didn't clear this bit, there's nothing to do
106762306a36Sopenharmony_ci	 */
106862306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_MOD_POWER_UNSUPPORTED, pf->flags))
106962306a36Sopenharmony_ci		return;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	if (link_cfg_err & ICE_AQ_LINK_INVAL_MAX_POWER_LIMIT) {
107262306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "The installed module is incompatible with the device's NVM image. Cannot start link\n");
107362306a36Sopenharmony_ci		set_bit(ICE_FLAG_MOD_POWER_UNSUPPORTED, pf->flags);
107462306a36Sopenharmony_ci	} else if (link_cfg_err & ICE_AQ_LINK_MODULE_POWER_UNSUPPORTED) {
107562306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "The module's power requirements exceed the device's power supply. Cannot start link\n");
107662306a36Sopenharmony_ci		set_bit(ICE_FLAG_MOD_POWER_UNSUPPORTED, pf->flags);
107762306a36Sopenharmony_ci	}
107862306a36Sopenharmony_ci}
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci/**
108162306a36Sopenharmony_ci * ice_check_link_cfg_err - check if link configuration failed
108262306a36Sopenharmony_ci * @pf: pointer to the PF struct
108362306a36Sopenharmony_ci * @link_cfg_err: bitmap from the link info structure
108462306a36Sopenharmony_ci *
108562306a36Sopenharmony_ci * print if any link configuration failure happens due to the value in the
108662306a36Sopenharmony_ci * link_cfg_err parameter in the link info structure
108762306a36Sopenharmony_ci */
108862306a36Sopenharmony_cistatic void ice_check_link_cfg_err(struct ice_pf *pf, u8 link_cfg_err)
108962306a36Sopenharmony_ci{
109062306a36Sopenharmony_ci	ice_check_module_power(pf, link_cfg_err);
109162306a36Sopenharmony_ci	ice_check_phy_fw_load(pf, link_cfg_err);
109262306a36Sopenharmony_ci}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci/**
109562306a36Sopenharmony_ci * ice_link_event - process the link event
109662306a36Sopenharmony_ci * @pf: PF that the link event is associated with
109762306a36Sopenharmony_ci * @pi: port_info for the port that the link event is associated with
109862306a36Sopenharmony_ci * @link_up: true if the physical link is up and false if it is down
109962306a36Sopenharmony_ci * @link_speed: current link speed received from the link event
110062306a36Sopenharmony_ci *
110162306a36Sopenharmony_ci * Returns 0 on success and negative on failure
110262306a36Sopenharmony_ci */
110362306a36Sopenharmony_cistatic int
110462306a36Sopenharmony_ciice_link_event(struct ice_pf *pf, struct ice_port_info *pi, bool link_up,
110562306a36Sopenharmony_ci	       u16 link_speed)
110662306a36Sopenharmony_ci{
110762306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
110862306a36Sopenharmony_ci	struct ice_phy_info *phy_info;
110962306a36Sopenharmony_ci	struct ice_vsi *vsi;
111062306a36Sopenharmony_ci	u16 old_link_speed;
111162306a36Sopenharmony_ci	bool old_link;
111262306a36Sopenharmony_ci	int status;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	phy_info = &pi->phy;
111562306a36Sopenharmony_ci	phy_info->link_info_old = phy_info->link_info;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	old_link = !!(phy_info->link_info_old.link_info & ICE_AQ_LINK_UP);
111862306a36Sopenharmony_ci	old_link_speed = phy_info->link_info_old.link_speed;
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	/* update the link info structures and re-enable link events,
112162306a36Sopenharmony_ci	 * don't bail on failure due to other book keeping needed
112262306a36Sopenharmony_ci	 */
112362306a36Sopenharmony_ci	status = ice_update_link_info(pi);
112462306a36Sopenharmony_ci	if (status)
112562306a36Sopenharmony_ci		dev_dbg(dev, "Failed to update link status on port %d, err %d aq_err %s\n",
112662306a36Sopenharmony_ci			pi->lport, status,
112762306a36Sopenharmony_ci			ice_aq_str(pi->hw->adminq.sq_last_status));
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	ice_check_link_cfg_err(pf, pi->phy.link_info.link_cfg_err);
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	/* Check if the link state is up after updating link info, and treat
113262306a36Sopenharmony_ci	 * this event as an UP event since the link is actually UP now.
113362306a36Sopenharmony_ci	 */
113462306a36Sopenharmony_ci	if (phy_info->link_info.link_info & ICE_AQ_LINK_UP)
113562306a36Sopenharmony_ci		link_up = true;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	vsi = ice_get_main_vsi(pf);
113862306a36Sopenharmony_ci	if (!vsi || !vsi->port_info)
113962306a36Sopenharmony_ci		return -EINVAL;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	/* turn off PHY if media was removed */
114262306a36Sopenharmony_ci	if (!test_bit(ICE_FLAG_NO_MEDIA, pf->flags) &&
114362306a36Sopenharmony_ci	    !(pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE)) {
114462306a36Sopenharmony_ci		set_bit(ICE_FLAG_NO_MEDIA, pf->flags);
114562306a36Sopenharmony_ci		ice_set_link(vsi, false);
114662306a36Sopenharmony_ci	}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	/* if the old link up/down and speed is the same as the new */
114962306a36Sopenharmony_ci	if (link_up == old_link && link_speed == old_link_speed)
115062306a36Sopenharmony_ci		return 0;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	ice_ptp_link_change(pf, pf->hw.pf_id, link_up);
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	if (ice_is_dcb_active(pf)) {
115562306a36Sopenharmony_ci		if (test_bit(ICE_FLAG_DCB_ENA, pf->flags))
115662306a36Sopenharmony_ci			ice_dcb_rebuild(pf);
115762306a36Sopenharmony_ci	} else {
115862306a36Sopenharmony_ci		if (link_up)
115962306a36Sopenharmony_ci			ice_set_dflt_mib(pf);
116062306a36Sopenharmony_ci	}
116162306a36Sopenharmony_ci	ice_vsi_link_event(vsi, link_up);
116262306a36Sopenharmony_ci	ice_print_link_msg(vsi, link_up);
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	ice_vc_notify_link_state(pf);
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	return 0;
116762306a36Sopenharmony_ci}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci/**
117062306a36Sopenharmony_ci * ice_watchdog_subtask - periodic tasks not using event driven scheduling
117162306a36Sopenharmony_ci * @pf: board private structure
117262306a36Sopenharmony_ci */
117362306a36Sopenharmony_cistatic void ice_watchdog_subtask(struct ice_pf *pf)
117462306a36Sopenharmony_ci{
117562306a36Sopenharmony_ci	int i;
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	/* if interface is down do nothing */
117862306a36Sopenharmony_ci	if (test_bit(ICE_DOWN, pf->state) ||
117962306a36Sopenharmony_ci	    test_bit(ICE_CFG_BUSY, pf->state))
118062306a36Sopenharmony_ci		return;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	/* make sure we don't do these things too often */
118362306a36Sopenharmony_ci	if (time_before(jiffies,
118462306a36Sopenharmony_ci			pf->serv_tmr_prev + pf->serv_tmr_period))
118562306a36Sopenharmony_ci		return;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	pf->serv_tmr_prev = jiffies;
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	/* Update the stats for active netdevs so the network stack
119062306a36Sopenharmony_ci	 * can look at updated numbers whenever it cares to
119162306a36Sopenharmony_ci	 */
119262306a36Sopenharmony_ci	ice_update_pf_stats(pf);
119362306a36Sopenharmony_ci	ice_for_each_vsi(pf, i)
119462306a36Sopenharmony_ci		if (pf->vsi[i] && pf->vsi[i]->netdev)
119562306a36Sopenharmony_ci			ice_update_vsi_stats(pf->vsi[i]);
119662306a36Sopenharmony_ci}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci/**
119962306a36Sopenharmony_ci * ice_init_link_events - enable/initialize link events
120062306a36Sopenharmony_ci * @pi: pointer to the port_info instance
120162306a36Sopenharmony_ci *
120262306a36Sopenharmony_ci * Returns -EIO on failure, 0 on success
120362306a36Sopenharmony_ci */
120462306a36Sopenharmony_cistatic int ice_init_link_events(struct ice_port_info *pi)
120562306a36Sopenharmony_ci{
120662306a36Sopenharmony_ci	u16 mask;
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci	mask = ~((u16)(ICE_AQ_LINK_EVENT_UPDOWN | ICE_AQ_LINK_EVENT_MEDIA_NA |
120962306a36Sopenharmony_ci		       ICE_AQ_LINK_EVENT_MODULE_QUAL_FAIL |
121062306a36Sopenharmony_ci		       ICE_AQ_LINK_EVENT_PHY_FW_LOAD_FAIL));
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	if (ice_aq_set_event_mask(pi->hw, pi->lport, mask, NULL)) {
121362306a36Sopenharmony_ci		dev_dbg(ice_hw_to_dev(pi->hw), "Failed to set link event mask for port %d\n",
121462306a36Sopenharmony_ci			pi->lport);
121562306a36Sopenharmony_ci		return -EIO;
121662306a36Sopenharmony_ci	}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	if (ice_aq_get_link_info(pi, true, NULL, NULL)) {
121962306a36Sopenharmony_ci		dev_dbg(ice_hw_to_dev(pi->hw), "Failed to enable link events for port %d\n",
122062306a36Sopenharmony_ci			pi->lport);
122162306a36Sopenharmony_ci		return -EIO;
122262306a36Sopenharmony_ci	}
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	return 0;
122562306a36Sopenharmony_ci}
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci/**
122862306a36Sopenharmony_ci * ice_handle_link_event - handle link event via ARQ
122962306a36Sopenharmony_ci * @pf: PF that the link event is associated with
123062306a36Sopenharmony_ci * @event: event structure containing link status info
123162306a36Sopenharmony_ci */
123262306a36Sopenharmony_cistatic int
123362306a36Sopenharmony_ciice_handle_link_event(struct ice_pf *pf, struct ice_rq_event_info *event)
123462306a36Sopenharmony_ci{
123562306a36Sopenharmony_ci	struct ice_aqc_get_link_status_data *link_data;
123662306a36Sopenharmony_ci	struct ice_port_info *port_info;
123762306a36Sopenharmony_ci	int status;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	link_data = (struct ice_aqc_get_link_status_data *)event->msg_buf;
124062306a36Sopenharmony_ci	port_info = pf->hw.port_info;
124162306a36Sopenharmony_ci	if (!port_info)
124262306a36Sopenharmony_ci		return -EINVAL;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	status = ice_link_event(pf, port_info,
124562306a36Sopenharmony_ci				!!(link_data->link_info & ICE_AQ_LINK_UP),
124662306a36Sopenharmony_ci				le16_to_cpu(link_data->link_speed));
124762306a36Sopenharmony_ci	if (status)
124862306a36Sopenharmony_ci		dev_dbg(ice_pf_to_dev(pf), "Could not process link event, error %d\n",
124962306a36Sopenharmony_ci			status);
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci	return status;
125262306a36Sopenharmony_ci}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci/**
125562306a36Sopenharmony_ci * ice_aq_prep_for_event - Prepare to wait for an AdminQ event from firmware
125662306a36Sopenharmony_ci * @pf: pointer to the PF private structure
125762306a36Sopenharmony_ci * @task: intermediate helper storage and identifier for waiting
125862306a36Sopenharmony_ci * @opcode: the opcode to wait for
125962306a36Sopenharmony_ci *
126062306a36Sopenharmony_ci * Prepares to wait for a specific AdminQ completion event on the ARQ for
126162306a36Sopenharmony_ci * a given PF. Actual wait would be done by a call to ice_aq_wait_for_event().
126262306a36Sopenharmony_ci *
126362306a36Sopenharmony_ci * Calls are separated to allow caller registering for event before sending
126462306a36Sopenharmony_ci * the command, which mitigates a race between registering and FW responding.
126562306a36Sopenharmony_ci *
126662306a36Sopenharmony_ci * To obtain only the descriptor contents, pass an task->event with null
126762306a36Sopenharmony_ci * msg_buf. If the complete data buffer is desired, allocate the
126862306a36Sopenharmony_ci * task->event.msg_buf with enough space ahead of time.
126962306a36Sopenharmony_ci */
127062306a36Sopenharmony_civoid ice_aq_prep_for_event(struct ice_pf *pf, struct ice_aq_task *task,
127162306a36Sopenharmony_ci			   u16 opcode)
127262306a36Sopenharmony_ci{
127362306a36Sopenharmony_ci	INIT_HLIST_NODE(&task->entry);
127462306a36Sopenharmony_ci	task->opcode = opcode;
127562306a36Sopenharmony_ci	task->state = ICE_AQ_TASK_WAITING;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	spin_lock_bh(&pf->aq_wait_lock);
127862306a36Sopenharmony_ci	hlist_add_head(&task->entry, &pf->aq_wait_list);
127962306a36Sopenharmony_ci	spin_unlock_bh(&pf->aq_wait_lock);
128062306a36Sopenharmony_ci}
128162306a36Sopenharmony_ci
128262306a36Sopenharmony_ci/**
128362306a36Sopenharmony_ci * ice_aq_wait_for_event - Wait for an AdminQ event from firmware
128462306a36Sopenharmony_ci * @pf: pointer to the PF private structure
128562306a36Sopenharmony_ci * @task: ptr prepared by ice_aq_prep_for_event()
128662306a36Sopenharmony_ci * @timeout: how long to wait, in jiffies
128762306a36Sopenharmony_ci *
128862306a36Sopenharmony_ci * Waits for a specific AdminQ completion event on the ARQ for a given PF. The
128962306a36Sopenharmony_ci * current thread will be put to sleep until the specified event occurs or
129062306a36Sopenharmony_ci * until the given timeout is reached.
129162306a36Sopenharmony_ci *
129262306a36Sopenharmony_ci * Returns: zero on success, or a negative error code on failure.
129362306a36Sopenharmony_ci */
129462306a36Sopenharmony_ciint ice_aq_wait_for_event(struct ice_pf *pf, struct ice_aq_task *task,
129562306a36Sopenharmony_ci			  unsigned long timeout)
129662306a36Sopenharmony_ci{
129762306a36Sopenharmony_ci	enum ice_aq_task_state *state = &task->state;
129862306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
129962306a36Sopenharmony_ci	unsigned long start = jiffies;
130062306a36Sopenharmony_ci	long ret;
130162306a36Sopenharmony_ci	int err;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	ret = wait_event_interruptible_timeout(pf->aq_wait_queue,
130462306a36Sopenharmony_ci					       *state != ICE_AQ_TASK_WAITING,
130562306a36Sopenharmony_ci					       timeout);
130662306a36Sopenharmony_ci	switch (*state) {
130762306a36Sopenharmony_ci	case ICE_AQ_TASK_NOT_PREPARED:
130862306a36Sopenharmony_ci		WARN(1, "call to %s without ice_aq_prep_for_event()", __func__);
130962306a36Sopenharmony_ci		err = -EINVAL;
131062306a36Sopenharmony_ci		break;
131162306a36Sopenharmony_ci	case ICE_AQ_TASK_WAITING:
131262306a36Sopenharmony_ci		err = ret < 0 ? ret : -ETIMEDOUT;
131362306a36Sopenharmony_ci		break;
131462306a36Sopenharmony_ci	case ICE_AQ_TASK_CANCELED:
131562306a36Sopenharmony_ci		err = ret < 0 ? ret : -ECANCELED;
131662306a36Sopenharmony_ci		break;
131762306a36Sopenharmony_ci	case ICE_AQ_TASK_COMPLETE:
131862306a36Sopenharmony_ci		err = ret < 0 ? ret : 0;
131962306a36Sopenharmony_ci		break;
132062306a36Sopenharmony_ci	default:
132162306a36Sopenharmony_ci		WARN(1, "Unexpected AdminQ wait task state %u", *state);
132262306a36Sopenharmony_ci		err = -EINVAL;
132362306a36Sopenharmony_ci		break;
132462306a36Sopenharmony_ci	}
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	dev_dbg(dev, "Waited %u msecs (max %u msecs) for firmware response to op 0x%04x\n",
132762306a36Sopenharmony_ci		jiffies_to_msecs(jiffies - start),
132862306a36Sopenharmony_ci		jiffies_to_msecs(timeout),
132962306a36Sopenharmony_ci		task->opcode);
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	spin_lock_bh(&pf->aq_wait_lock);
133262306a36Sopenharmony_ci	hlist_del(&task->entry);
133362306a36Sopenharmony_ci	spin_unlock_bh(&pf->aq_wait_lock);
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	return err;
133662306a36Sopenharmony_ci}
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci/**
133962306a36Sopenharmony_ci * ice_aq_check_events - Check if any thread is waiting for an AdminQ event
134062306a36Sopenharmony_ci * @pf: pointer to the PF private structure
134162306a36Sopenharmony_ci * @opcode: the opcode of the event
134262306a36Sopenharmony_ci * @event: the event to check
134362306a36Sopenharmony_ci *
134462306a36Sopenharmony_ci * Loops over the current list of pending threads waiting for an AdminQ event.
134562306a36Sopenharmony_ci * For each matching task, copy the contents of the event into the task
134662306a36Sopenharmony_ci * structure and wake up the thread.
134762306a36Sopenharmony_ci *
134862306a36Sopenharmony_ci * If multiple threads wait for the same opcode, they will all be woken up.
134962306a36Sopenharmony_ci *
135062306a36Sopenharmony_ci * Note that event->msg_buf will only be duplicated if the event has a buffer
135162306a36Sopenharmony_ci * with enough space already allocated. Otherwise, only the descriptor and
135262306a36Sopenharmony_ci * message length will be copied.
135362306a36Sopenharmony_ci *
135462306a36Sopenharmony_ci * Returns: true if an event was found, false otherwise
135562306a36Sopenharmony_ci */
135662306a36Sopenharmony_cistatic void ice_aq_check_events(struct ice_pf *pf, u16 opcode,
135762306a36Sopenharmony_ci				struct ice_rq_event_info *event)
135862306a36Sopenharmony_ci{
135962306a36Sopenharmony_ci	struct ice_rq_event_info *task_ev;
136062306a36Sopenharmony_ci	struct ice_aq_task *task;
136162306a36Sopenharmony_ci	bool found = false;
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	spin_lock_bh(&pf->aq_wait_lock);
136462306a36Sopenharmony_ci	hlist_for_each_entry(task, &pf->aq_wait_list, entry) {
136562306a36Sopenharmony_ci		if (task->state != ICE_AQ_TASK_WAITING)
136662306a36Sopenharmony_ci			continue;
136762306a36Sopenharmony_ci		if (task->opcode != opcode)
136862306a36Sopenharmony_ci			continue;
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci		task_ev = &task->event;
137162306a36Sopenharmony_ci		memcpy(&task_ev->desc, &event->desc, sizeof(event->desc));
137262306a36Sopenharmony_ci		task_ev->msg_len = event->msg_len;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci		/* Only copy the data buffer if a destination was set */
137562306a36Sopenharmony_ci		if (task_ev->msg_buf && task_ev->buf_len >= event->buf_len) {
137662306a36Sopenharmony_ci			memcpy(task_ev->msg_buf, event->msg_buf,
137762306a36Sopenharmony_ci			       event->buf_len);
137862306a36Sopenharmony_ci			task_ev->buf_len = event->buf_len;
137962306a36Sopenharmony_ci		}
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci		task->state = ICE_AQ_TASK_COMPLETE;
138262306a36Sopenharmony_ci		found = true;
138362306a36Sopenharmony_ci	}
138462306a36Sopenharmony_ci	spin_unlock_bh(&pf->aq_wait_lock);
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	if (found)
138762306a36Sopenharmony_ci		wake_up(&pf->aq_wait_queue);
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci/**
139162306a36Sopenharmony_ci * ice_aq_cancel_waiting_tasks - Immediately cancel all waiting tasks
139262306a36Sopenharmony_ci * @pf: the PF private structure
139362306a36Sopenharmony_ci *
139462306a36Sopenharmony_ci * Set all waiting tasks to ICE_AQ_TASK_CANCELED, and wake up their threads.
139562306a36Sopenharmony_ci * This will then cause ice_aq_wait_for_event to exit with -ECANCELED.
139662306a36Sopenharmony_ci */
139762306a36Sopenharmony_cistatic void ice_aq_cancel_waiting_tasks(struct ice_pf *pf)
139862306a36Sopenharmony_ci{
139962306a36Sopenharmony_ci	struct ice_aq_task *task;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	spin_lock_bh(&pf->aq_wait_lock);
140262306a36Sopenharmony_ci	hlist_for_each_entry(task, &pf->aq_wait_list, entry)
140362306a36Sopenharmony_ci		task->state = ICE_AQ_TASK_CANCELED;
140462306a36Sopenharmony_ci	spin_unlock_bh(&pf->aq_wait_lock);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci	wake_up(&pf->aq_wait_queue);
140762306a36Sopenharmony_ci}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci#define ICE_MBX_OVERFLOW_WATERMARK 64
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci/**
141262306a36Sopenharmony_ci * __ice_clean_ctrlq - helper function to clean controlq rings
141362306a36Sopenharmony_ci * @pf: ptr to struct ice_pf
141462306a36Sopenharmony_ci * @q_type: specific Control queue type
141562306a36Sopenharmony_ci */
141662306a36Sopenharmony_cistatic int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type)
141762306a36Sopenharmony_ci{
141862306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
141962306a36Sopenharmony_ci	struct ice_rq_event_info event;
142062306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
142162306a36Sopenharmony_ci	struct ice_ctl_q_info *cq;
142262306a36Sopenharmony_ci	u16 pending, i = 0;
142362306a36Sopenharmony_ci	const char *qtype;
142462306a36Sopenharmony_ci	u32 oldval, val;
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	/* Do not clean control queue if/when PF reset fails */
142762306a36Sopenharmony_ci	if (test_bit(ICE_RESET_FAILED, pf->state))
142862306a36Sopenharmony_ci		return 0;
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	switch (q_type) {
143162306a36Sopenharmony_ci	case ICE_CTL_Q_ADMIN:
143262306a36Sopenharmony_ci		cq = &hw->adminq;
143362306a36Sopenharmony_ci		qtype = "Admin";
143462306a36Sopenharmony_ci		break;
143562306a36Sopenharmony_ci	case ICE_CTL_Q_SB:
143662306a36Sopenharmony_ci		cq = &hw->sbq;
143762306a36Sopenharmony_ci		qtype = "Sideband";
143862306a36Sopenharmony_ci		break;
143962306a36Sopenharmony_ci	case ICE_CTL_Q_MAILBOX:
144062306a36Sopenharmony_ci		cq = &hw->mailboxq;
144162306a36Sopenharmony_ci		qtype = "Mailbox";
144262306a36Sopenharmony_ci		/* we are going to try to detect a malicious VF, so set the
144362306a36Sopenharmony_ci		 * state to begin detection
144462306a36Sopenharmony_ci		 */
144562306a36Sopenharmony_ci		hw->mbx_snapshot.mbx_buf.state = ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT;
144662306a36Sopenharmony_ci		break;
144762306a36Sopenharmony_ci	default:
144862306a36Sopenharmony_ci		dev_warn(dev, "Unknown control queue type 0x%x\n", q_type);
144962306a36Sopenharmony_ci		return 0;
145062306a36Sopenharmony_ci	}
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	/* check for error indications - PF_xx_AxQLEN register layout for
145362306a36Sopenharmony_ci	 * FW/MBX/SB are identical so just use defines for PF_FW_AxQLEN.
145462306a36Sopenharmony_ci	 */
145562306a36Sopenharmony_ci	val = rd32(hw, cq->rq.len);
145662306a36Sopenharmony_ci	if (val & (PF_FW_ARQLEN_ARQVFE_M | PF_FW_ARQLEN_ARQOVFL_M |
145762306a36Sopenharmony_ci		   PF_FW_ARQLEN_ARQCRIT_M)) {
145862306a36Sopenharmony_ci		oldval = val;
145962306a36Sopenharmony_ci		if (val & PF_FW_ARQLEN_ARQVFE_M)
146062306a36Sopenharmony_ci			dev_dbg(dev, "%s Receive Queue VF Error detected\n",
146162306a36Sopenharmony_ci				qtype);
146262306a36Sopenharmony_ci		if (val & PF_FW_ARQLEN_ARQOVFL_M) {
146362306a36Sopenharmony_ci			dev_dbg(dev, "%s Receive Queue Overflow Error detected\n",
146462306a36Sopenharmony_ci				qtype);
146562306a36Sopenharmony_ci		}
146662306a36Sopenharmony_ci		if (val & PF_FW_ARQLEN_ARQCRIT_M)
146762306a36Sopenharmony_ci			dev_dbg(dev, "%s Receive Queue Critical Error detected\n",
146862306a36Sopenharmony_ci				qtype);
146962306a36Sopenharmony_ci		val &= ~(PF_FW_ARQLEN_ARQVFE_M | PF_FW_ARQLEN_ARQOVFL_M |
147062306a36Sopenharmony_ci			 PF_FW_ARQLEN_ARQCRIT_M);
147162306a36Sopenharmony_ci		if (oldval != val)
147262306a36Sopenharmony_ci			wr32(hw, cq->rq.len, val);
147362306a36Sopenharmony_ci	}
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	val = rd32(hw, cq->sq.len);
147662306a36Sopenharmony_ci	if (val & (PF_FW_ATQLEN_ATQVFE_M | PF_FW_ATQLEN_ATQOVFL_M |
147762306a36Sopenharmony_ci		   PF_FW_ATQLEN_ATQCRIT_M)) {
147862306a36Sopenharmony_ci		oldval = val;
147962306a36Sopenharmony_ci		if (val & PF_FW_ATQLEN_ATQVFE_M)
148062306a36Sopenharmony_ci			dev_dbg(dev, "%s Send Queue VF Error detected\n",
148162306a36Sopenharmony_ci				qtype);
148262306a36Sopenharmony_ci		if (val & PF_FW_ATQLEN_ATQOVFL_M) {
148362306a36Sopenharmony_ci			dev_dbg(dev, "%s Send Queue Overflow Error detected\n",
148462306a36Sopenharmony_ci				qtype);
148562306a36Sopenharmony_ci		}
148662306a36Sopenharmony_ci		if (val & PF_FW_ATQLEN_ATQCRIT_M)
148762306a36Sopenharmony_ci			dev_dbg(dev, "%s Send Queue Critical Error detected\n",
148862306a36Sopenharmony_ci				qtype);
148962306a36Sopenharmony_ci		val &= ~(PF_FW_ATQLEN_ATQVFE_M | PF_FW_ATQLEN_ATQOVFL_M |
149062306a36Sopenharmony_ci			 PF_FW_ATQLEN_ATQCRIT_M);
149162306a36Sopenharmony_ci		if (oldval != val)
149262306a36Sopenharmony_ci			wr32(hw, cq->sq.len, val);
149362306a36Sopenharmony_ci	}
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	event.buf_len = cq->rq_buf_size;
149662306a36Sopenharmony_ci	event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL);
149762306a36Sopenharmony_ci	if (!event.msg_buf)
149862306a36Sopenharmony_ci		return 0;
149962306a36Sopenharmony_ci
150062306a36Sopenharmony_ci	do {
150162306a36Sopenharmony_ci		struct ice_mbx_data data = {};
150262306a36Sopenharmony_ci		u16 opcode;
150362306a36Sopenharmony_ci		int ret;
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci		ret = ice_clean_rq_elem(hw, cq, &event, &pending);
150662306a36Sopenharmony_ci		if (ret == -EALREADY)
150762306a36Sopenharmony_ci			break;
150862306a36Sopenharmony_ci		if (ret) {
150962306a36Sopenharmony_ci			dev_err(dev, "%s Receive Queue event error %d\n", qtype,
151062306a36Sopenharmony_ci				ret);
151162306a36Sopenharmony_ci			break;
151262306a36Sopenharmony_ci		}
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci		opcode = le16_to_cpu(event.desc.opcode);
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci		/* Notify any thread that might be waiting for this event */
151762306a36Sopenharmony_ci		ice_aq_check_events(pf, opcode, &event);
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci		switch (opcode) {
152062306a36Sopenharmony_ci		case ice_aqc_opc_get_link_status:
152162306a36Sopenharmony_ci			if (ice_handle_link_event(pf, &event))
152262306a36Sopenharmony_ci				dev_err(dev, "Could not handle link event\n");
152362306a36Sopenharmony_ci			break;
152462306a36Sopenharmony_ci		case ice_aqc_opc_event_lan_overflow:
152562306a36Sopenharmony_ci			ice_vf_lan_overflow_event(pf, &event);
152662306a36Sopenharmony_ci			break;
152762306a36Sopenharmony_ci		case ice_mbx_opc_send_msg_to_pf:
152862306a36Sopenharmony_ci			data.num_msg_proc = i;
152962306a36Sopenharmony_ci			data.num_pending_arq = pending;
153062306a36Sopenharmony_ci			data.max_num_msgs_mbx = hw->mailboxq.num_rq_entries;
153162306a36Sopenharmony_ci			data.async_watermark_val = ICE_MBX_OVERFLOW_WATERMARK;
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci			ice_vc_process_vf_msg(pf, &event, &data);
153462306a36Sopenharmony_ci			break;
153562306a36Sopenharmony_ci		case ice_aqc_opc_fw_logging:
153662306a36Sopenharmony_ci			ice_output_fw_log(hw, &event.desc, event.msg_buf);
153762306a36Sopenharmony_ci			break;
153862306a36Sopenharmony_ci		case ice_aqc_opc_lldp_set_mib_change:
153962306a36Sopenharmony_ci			ice_dcb_process_lldp_set_mib_change(pf, &event);
154062306a36Sopenharmony_ci			break;
154162306a36Sopenharmony_ci		default:
154262306a36Sopenharmony_ci			dev_dbg(dev, "%s Receive Queue unknown event 0x%04x ignored\n",
154362306a36Sopenharmony_ci				qtype, opcode);
154462306a36Sopenharmony_ci			break;
154562306a36Sopenharmony_ci		}
154662306a36Sopenharmony_ci	} while (pending && (i++ < ICE_DFLT_IRQ_WORK));
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	kfree(event.msg_buf);
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	return pending && (i == ICE_DFLT_IRQ_WORK);
155162306a36Sopenharmony_ci}
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci/**
155462306a36Sopenharmony_ci * ice_ctrlq_pending - check if there is a difference between ntc and ntu
155562306a36Sopenharmony_ci * @hw: pointer to hardware info
155662306a36Sopenharmony_ci * @cq: control queue information
155762306a36Sopenharmony_ci *
155862306a36Sopenharmony_ci * returns true if there are pending messages in a queue, false if there aren't
155962306a36Sopenharmony_ci */
156062306a36Sopenharmony_cistatic bool ice_ctrlq_pending(struct ice_hw *hw, struct ice_ctl_q_info *cq)
156162306a36Sopenharmony_ci{
156262306a36Sopenharmony_ci	u16 ntu;
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	ntu = (u16)(rd32(hw, cq->rq.head) & cq->rq.head_mask);
156562306a36Sopenharmony_ci	return cq->rq.next_to_clean != ntu;
156662306a36Sopenharmony_ci}
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci/**
156962306a36Sopenharmony_ci * ice_clean_adminq_subtask - clean the AdminQ rings
157062306a36Sopenharmony_ci * @pf: board private structure
157162306a36Sopenharmony_ci */
157262306a36Sopenharmony_cistatic void ice_clean_adminq_subtask(struct ice_pf *pf)
157362306a36Sopenharmony_ci{
157462306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	if (!test_bit(ICE_ADMINQ_EVENT_PENDING, pf->state))
157762306a36Sopenharmony_ci		return;
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	if (__ice_clean_ctrlq(pf, ICE_CTL_Q_ADMIN))
158062306a36Sopenharmony_ci		return;
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	clear_bit(ICE_ADMINQ_EVENT_PENDING, pf->state);
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	/* There might be a situation where new messages arrive to a control
158562306a36Sopenharmony_ci	 * queue between processing the last message and clearing the
158662306a36Sopenharmony_ci	 * EVENT_PENDING bit. So before exiting, check queue head again (using
158762306a36Sopenharmony_ci	 * ice_ctrlq_pending) and process new messages if any.
158862306a36Sopenharmony_ci	 */
158962306a36Sopenharmony_ci	if (ice_ctrlq_pending(hw, &hw->adminq))
159062306a36Sopenharmony_ci		__ice_clean_ctrlq(pf, ICE_CTL_Q_ADMIN);
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci	ice_flush(hw);
159362306a36Sopenharmony_ci}
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci/**
159662306a36Sopenharmony_ci * ice_clean_mailboxq_subtask - clean the MailboxQ rings
159762306a36Sopenharmony_ci * @pf: board private structure
159862306a36Sopenharmony_ci */
159962306a36Sopenharmony_cistatic void ice_clean_mailboxq_subtask(struct ice_pf *pf)
160062306a36Sopenharmony_ci{
160162306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	if (!test_bit(ICE_MAILBOXQ_EVENT_PENDING, pf->state))
160462306a36Sopenharmony_ci		return;
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	if (__ice_clean_ctrlq(pf, ICE_CTL_Q_MAILBOX))
160762306a36Sopenharmony_ci		return;
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	clear_bit(ICE_MAILBOXQ_EVENT_PENDING, pf->state);
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	if (ice_ctrlq_pending(hw, &hw->mailboxq))
161262306a36Sopenharmony_ci		__ice_clean_ctrlq(pf, ICE_CTL_Q_MAILBOX);
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	ice_flush(hw);
161562306a36Sopenharmony_ci}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci/**
161862306a36Sopenharmony_ci * ice_clean_sbq_subtask - clean the Sideband Queue rings
161962306a36Sopenharmony_ci * @pf: board private structure
162062306a36Sopenharmony_ci */
162162306a36Sopenharmony_cistatic void ice_clean_sbq_subtask(struct ice_pf *pf)
162262306a36Sopenharmony_ci{
162362306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci	/* Nothing to do here if sideband queue is not supported */
162662306a36Sopenharmony_ci	if (!ice_is_sbq_supported(hw)) {
162762306a36Sopenharmony_ci		clear_bit(ICE_SIDEBANDQ_EVENT_PENDING, pf->state);
162862306a36Sopenharmony_ci		return;
162962306a36Sopenharmony_ci	}
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	if (!test_bit(ICE_SIDEBANDQ_EVENT_PENDING, pf->state))
163262306a36Sopenharmony_ci		return;
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	if (__ice_clean_ctrlq(pf, ICE_CTL_Q_SB))
163562306a36Sopenharmony_ci		return;
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	clear_bit(ICE_SIDEBANDQ_EVENT_PENDING, pf->state);
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci	if (ice_ctrlq_pending(hw, &hw->sbq))
164062306a36Sopenharmony_ci		__ice_clean_ctrlq(pf, ICE_CTL_Q_SB);
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_ci	ice_flush(hw);
164362306a36Sopenharmony_ci}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci/**
164662306a36Sopenharmony_ci * ice_service_task_schedule - schedule the service task to wake up
164762306a36Sopenharmony_ci * @pf: board private structure
164862306a36Sopenharmony_ci *
164962306a36Sopenharmony_ci * If not already scheduled, this puts the task into the work queue.
165062306a36Sopenharmony_ci */
165162306a36Sopenharmony_civoid ice_service_task_schedule(struct ice_pf *pf)
165262306a36Sopenharmony_ci{
165362306a36Sopenharmony_ci	if (!test_bit(ICE_SERVICE_DIS, pf->state) &&
165462306a36Sopenharmony_ci	    !test_and_set_bit(ICE_SERVICE_SCHED, pf->state) &&
165562306a36Sopenharmony_ci	    !test_bit(ICE_NEEDS_RESTART, pf->state))
165662306a36Sopenharmony_ci		queue_work(ice_wq, &pf->serv_task);
165762306a36Sopenharmony_ci}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci/**
166062306a36Sopenharmony_ci * ice_service_task_complete - finish up the service task
166162306a36Sopenharmony_ci * @pf: board private structure
166262306a36Sopenharmony_ci */
166362306a36Sopenharmony_cistatic void ice_service_task_complete(struct ice_pf *pf)
166462306a36Sopenharmony_ci{
166562306a36Sopenharmony_ci	WARN_ON(!test_bit(ICE_SERVICE_SCHED, pf->state));
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	/* force memory (pf->state) to sync before next service task */
166862306a36Sopenharmony_ci	smp_mb__before_atomic();
166962306a36Sopenharmony_ci	clear_bit(ICE_SERVICE_SCHED, pf->state);
167062306a36Sopenharmony_ci}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci/**
167362306a36Sopenharmony_ci * ice_service_task_stop - stop service task and cancel works
167462306a36Sopenharmony_ci * @pf: board private structure
167562306a36Sopenharmony_ci *
167662306a36Sopenharmony_ci * Return 0 if the ICE_SERVICE_DIS bit was not already set,
167762306a36Sopenharmony_ci * 1 otherwise.
167862306a36Sopenharmony_ci */
167962306a36Sopenharmony_cistatic int ice_service_task_stop(struct ice_pf *pf)
168062306a36Sopenharmony_ci{
168162306a36Sopenharmony_ci	int ret;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	ret = test_and_set_bit(ICE_SERVICE_DIS, pf->state);
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	if (pf->serv_tmr.function)
168662306a36Sopenharmony_ci		del_timer_sync(&pf->serv_tmr);
168762306a36Sopenharmony_ci	if (pf->serv_task.func)
168862306a36Sopenharmony_ci		cancel_work_sync(&pf->serv_task);
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	clear_bit(ICE_SERVICE_SCHED, pf->state);
169162306a36Sopenharmony_ci	return ret;
169262306a36Sopenharmony_ci}
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci/**
169562306a36Sopenharmony_ci * ice_service_task_restart - restart service task and schedule works
169662306a36Sopenharmony_ci * @pf: board private structure
169762306a36Sopenharmony_ci *
169862306a36Sopenharmony_ci * This function is needed for suspend and resume works (e.g WoL scenario)
169962306a36Sopenharmony_ci */
170062306a36Sopenharmony_cistatic void ice_service_task_restart(struct ice_pf *pf)
170162306a36Sopenharmony_ci{
170262306a36Sopenharmony_ci	clear_bit(ICE_SERVICE_DIS, pf->state);
170362306a36Sopenharmony_ci	ice_service_task_schedule(pf);
170462306a36Sopenharmony_ci}
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci/**
170762306a36Sopenharmony_ci * ice_service_timer - timer callback to schedule service task
170862306a36Sopenharmony_ci * @t: pointer to timer_list
170962306a36Sopenharmony_ci */
171062306a36Sopenharmony_cistatic void ice_service_timer(struct timer_list *t)
171162306a36Sopenharmony_ci{
171262306a36Sopenharmony_ci	struct ice_pf *pf = from_timer(pf, t, serv_tmr);
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_ci	mod_timer(&pf->serv_tmr, round_jiffies(pf->serv_tmr_period + jiffies));
171562306a36Sopenharmony_ci	ice_service_task_schedule(pf);
171662306a36Sopenharmony_ci}
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci/**
171962306a36Sopenharmony_ci * ice_handle_mdd_event - handle malicious driver detect event
172062306a36Sopenharmony_ci * @pf: pointer to the PF structure
172162306a36Sopenharmony_ci *
172262306a36Sopenharmony_ci * Called from service task. OICR interrupt handler indicates MDD event.
172362306a36Sopenharmony_ci * VF MDD logging is guarded by net_ratelimit. Additional PF and VF log
172462306a36Sopenharmony_ci * messages are wrapped by netif_msg_[rx|tx]_err. Since VF Rx MDD events
172562306a36Sopenharmony_ci * disable the queue, the PF can be configured to reset the VF using ethtool
172662306a36Sopenharmony_ci * private flag mdd-auto-reset-vf.
172762306a36Sopenharmony_ci */
172862306a36Sopenharmony_cistatic void ice_handle_mdd_event(struct ice_pf *pf)
172962306a36Sopenharmony_ci{
173062306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
173162306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
173262306a36Sopenharmony_ci	struct ice_vf *vf;
173362306a36Sopenharmony_ci	unsigned int bkt;
173462306a36Sopenharmony_ci	u32 reg;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	if (!test_and_clear_bit(ICE_MDD_EVENT_PENDING, pf->state)) {
173762306a36Sopenharmony_ci		/* Since the VF MDD event logging is rate limited, check if
173862306a36Sopenharmony_ci		 * there are pending MDD events.
173962306a36Sopenharmony_ci		 */
174062306a36Sopenharmony_ci		ice_print_vfs_mdd_events(pf);
174162306a36Sopenharmony_ci		return;
174262306a36Sopenharmony_ci	}
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	/* find what triggered an MDD event */
174562306a36Sopenharmony_ci	reg = rd32(hw, GL_MDET_TX_PQM);
174662306a36Sopenharmony_ci	if (reg & GL_MDET_TX_PQM_VALID_M) {
174762306a36Sopenharmony_ci		u8 pf_num = (reg & GL_MDET_TX_PQM_PF_NUM_M) >>
174862306a36Sopenharmony_ci				GL_MDET_TX_PQM_PF_NUM_S;
174962306a36Sopenharmony_ci		u16 vf_num = (reg & GL_MDET_TX_PQM_VF_NUM_M) >>
175062306a36Sopenharmony_ci				GL_MDET_TX_PQM_VF_NUM_S;
175162306a36Sopenharmony_ci		u8 event = (reg & GL_MDET_TX_PQM_MAL_TYPE_M) >>
175262306a36Sopenharmony_ci				GL_MDET_TX_PQM_MAL_TYPE_S;
175362306a36Sopenharmony_ci		u16 queue = ((reg & GL_MDET_TX_PQM_QNUM_M) >>
175462306a36Sopenharmony_ci				GL_MDET_TX_PQM_QNUM_S);
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci		if (netif_msg_tx_err(pf))
175762306a36Sopenharmony_ci			dev_info(dev, "Malicious Driver Detection event %d on TX queue %d PF# %d VF# %d\n",
175862306a36Sopenharmony_ci				 event, queue, pf_num, vf_num);
175962306a36Sopenharmony_ci		wr32(hw, GL_MDET_TX_PQM, 0xffffffff);
176062306a36Sopenharmony_ci	}
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	reg = rd32(hw, GL_MDET_TX_TCLAN);
176362306a36Sopenharmony_ci	if (reg & GL_MDET_TX_TCLAN_VALID_M) {
176462306a36Sopenharmony_ci		u8 pf_num = (reg & GL_MDET_TX_TCLAN_PF_NUM_M) >>
176562306a36Sopenharmony_ci				GL_MDET_TX_TCLAN_PF_NUM_S;
176662306a36Sopenharmony_ci		u16 vf_num = (reg & GL_MDET_TX_TCLAN_VF_NUM_M) >>
176762306a36Sopenharmony_ci				GL_MDET_TX_TCLAN_VF_NUM_S;
176862306a36Sopenharmony_ci		u8 event = (reg & GL_MDET_TX_TCLAN_MAL_TYPE_M) >>
176962306a36Sopenharmony_ci				GL_MDET_TX_TCLAN_MAL_TYPE_S;
177062306a36Sopenharmony_ci		u16 queue = ((reg & GL_MDET_TX_TCLAN_QNUM_M) >>
177162306a36Sopenharmony_ci				GL_MDET_TX_TCLAN_QNUM_S);
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci		if (netif_msg_tx_err(pf))
177462306a36Sopenharmony_ci			dev_info(dev, "Malicious Driver Detection event %d on TX queue %d PF# %d VF# %d\n",
177562306a36Sopenharmony_ci				 event, queue, pf_num, vf_num);
177662306a36Sopenharmony_ci		wr32(hw, GL_MDET_TX_TCLAN, 0xffffffff);
177762306a36Sopenharmony_ci	}
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci	reg = rd32(hw, GL_MDET_RX);
178062306a36Sopenharmony_ci	if (reg & GL_MDET_RX_VALID_M) {
178162306a36Sopenharmony_ci		u8 pf_num = (reg & GL_MDET_RX_PF_NUM_M) >>
178262306a36Sopenharmony_ci				GL_MDET_RX_PF_NUM_S;
178362306a36Sopenharmony_ci		u16 vf_num = (reg & GL_MDET_RX_VF_NUM_M) >>
178462306a36Sopenharmony_ci				GL_MDET_RX_VF_NUM_S;
178562306a36Sopenharmony_ci		u8 event = (reg & GL_MDET_RX_MAL_TYPE_M) >>
178662306a36Sopenharmony_ci				GL_MDET_RX_MAL_TYPE_S;
178762306a36Sopenharmony_ci		u16 queue = ((reg & GL_MDET_RX_QNUM_M) >>
178862306a36Sopenharmony_ci				GL_MDET_RX_QNUM_S);
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci		if (netif_msg_rx_err(pf))
179162306a36Sopenharmony_ci			dev_info(dev, "Malicious Driver Detection event %d on RX queue %d PF# %d VF# %d\n",
179262306a36Sopenharmony_ci				 event, queue, pf_num, vf_num);
179362306a36Sopenharmony_ci		wr32(hw, GL_MDET_RX, 0xffffffff);
179462306a36Sopenharmony_ci	}
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	/* check to see if this PF caused an MDD event */
179762306a36Sopenharmony_ci	reg = rd32(hw, PF_MDET_TX_PQM);
179862306a36Sopenharmony_ci	if (reg & PF_MDET_TX_PQM_VALID_M) {
179962306a36Sopenharmony_ci		wr32(hw, PF_MDET_TX_PQM, 0xFFFF);
180062306a36Sopenharmony_ci		if (netif_msg_tx_err(pf))
180162306a36Sopenharmony_ci			dev_info(dev, "Malicious Driver Detection event TX_PQM detected on PF\n");
180262306a36Sopenharmony_ci	}
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci	reg = rd32(hw, PF_MDET_TX_TCLAN);
180562306a36Sopenharmony_ci	if (reg & PF_MDET_TX_TCLAN_VALID_M) {
180662306a36Sopenharmony_ci		wr32(hw, PF_MDET_TX_TCLAN, 0xFFFF);
180762306a36Sopenharmony_ci		if (netif_msg_tx_err(pf))
180862306a36Sopenharmony_ci			dev_info(dev, "Malicious Driver Detection event TX_TCLAN detected on PF\n");
180962306a36Sopenharmony_ci	}
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	reg = rd32(hw, PF_MDET_RX);
181262306a36Sopenharmony_ci	if (reg & PF_MDET_RX_VALID_M) {
181362306a36Sopenharmony_ci		wr32(hw, PF_MDET_RX, 0xFFFF);
181462306a36Sopenharmony_ci		if (netif_msg_rx_err(pf))
181562306a36Sopenharmony_ci			dev_info(dev, "Malicious Driver Detection event RX detected on PF\n");
181662306a36Sopenharmony_ci	}
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	/* Check to see if one of the VFs caused an MDD event, and then
181962306a36Sopenharmony_ci	 * increment counters and set print pending
182062306a36Sopenharmony_ci	 */
182162306a36Sopenharmony_ci	mutex_lock(&pf->vfs.table_lock);
182262306a36Sopenharmony_ci	ice_for_each_vf(pf, bkt, vf) {
182362306a36Sopenharmony_ci		reg = rd32(hw, VP_MDET_TX_PQM(vf->vf_id));
182462306a36Sopenharmony_ci		if (reg & VP_MDET_TX_PQM_VALID_M) {
182562306a36Sopenharmony_ci			wr32(hw, VP_MDET_TX_PQM(vf->vf_id), 0xFFFF);
182662306a36Sopenharmony_ci			vf->mdd_tx_events.count++;
182762306a36Sopenharmony_ci			set_bit(ICE_MDD_VF_PRINT_PENDING, pf->state);
182862306a36Sopenharmony_ci			if (netif_msg_tx_err(pf))
182962306a36Sopenharmony_ci				dev_info(dev, "Malicious Driver Detection event TX_PQM detected on VF %d\n",
183062306a36Sopenharmony_ci					 vf->vf_id);
183162306a36Sopenharmony_ci		}
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci		reg = rd32(hw, VP_MDET_TX_TCLAN(vf->vf_id));
183462306a36Sopenharmony_ci		if (reg & VP_MDET_TX_TCLAN_VALID_M) {
183562306a36Sopenharmony_ci			wr32(hw, VP_MDET_TX_TCLAN(vf->vf_id), 0xFFFF);
183662306a36Sopenharmony_ci			vf->mdd_tx_events.count++;
183762306a36Sopenharmony_ci			set_bit(ICE_MDD_VF_PRINT_PENDING, pf->state);
183862306a36Sopenharmony_ci			if (netif_msg_tx_err(pf))
183962306a36Sopenharmony_ci				dev_info(dev, "Malicious Driver Detection event TX_TCLAN detected on VF %d\n",
184062306a36Sopenharmony_ci					 vf->vf_id);
184162306a36Sopenharmony_ci		}
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci		reg = rd32(hw, VP_MDET_TX_TDPU(vf->vf_id));
184462306a36Sopenharmony_ci		if (reg & VP_MDET_TX_TDPU_VALID_M) {
184562306a36Sopenharmony_ci			wr32(hw, VP_MDET_TX_TDPU(vf->vf_id), 0xFFFF);
184662306a36Sopenharmony_ci			vf->mdd_tx_events.count++;
184762306a36Sopenharmony_ci			set_bit(ICE_MDD_VF_PRINT_PENDING, pf->state);
184862306a36Sopenharmony_ci			if (netif_msg_tx_err(pf))
184962306a36Sopenharmony_ci				dev_info(dev, "Malicious Driver Detection event TX_TDPU detected on VF %d\n",
185062306a36Sopenharmony_ci					 vf->vf_id);
185162306a36Sopenharmony_ci		}
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci		reg = rd32(hw, VP_MDET_RX(vf->vf_id));
185462306a36Sopenharmony_ci		if (reg & VP_MDET_RX_VALID_M) {
185562306a36Sopenharmony_ci			wr32(hw, VP_MDET_RX(vf->vf_id), 0xFFFF);
185662306a36Sopenharmony_ci			vf->mdd_rx_events.count++;
185762306a36Sopenharmony_ci			set_bit(ICE_MDD_VF_PRINT_PENDING, pf->state);
185862306a36Sopenharmony_ci			if (netif_msg_rx_err(pf))
185962306a36Sopenharmony_ci				dev_info(dev, "Malicious Driver Detection event RX detected on VF %d\n",
186062306a36Sopenharmony_ci					 vf->vf_id);
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci			/* Since the queue is disabled on VF Rx MDD events, the
186362306a36Sopenharmony_ci			 * PF can be configured to reset the VF through ethtool
186462306a36Sopenharmony_ci			 * private flag mdd-auto-reset-vf.
186562306a36Sopenharmony_ci			 */
186662306a36Sopenharmony_ci			if (test_bit(ICE_FLAG_MDD_AUTO_RESET_VF, pf->flags)) {
186762306a36Sopenharmony_ci				/* VF MDD event counters will be cleared by
186862306a36Sopenharmony_ci				 * reset, so print the event prior to reset.
186962306a36Sopenharmony_ci				 */
187062306a36Sopenharmony_ci				ice_print_vf_rx_mdd_event(vf);
187162306a36Sopenharmony_ci				ice_reset_vf(vf, ICE_VF_RESET_LOCK);
187262306a36Sopenharmony_ci			}
187362306a36Sopenharmony_ci		}
187462306a36Sopenharmony_ci	}
187562306a36Sopenharmony_ci	mutex_unlock(&pf->vfs.table_lock);
187662306a36Sopenharmony_ci
187762306a36Sopenharmony_ci	ice_print_vfs_mdd_events(pf);
187862306a36Sopenharmony_ci}
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci/**
188162306a36Sopenharmony_ci * ice_force_phys_link_state - Force the physical link state
188262306a36Sopenharmony_ci * @vsi: VSI to force the physical link state to up/down
188362306a36Sopenharmony_ci * @link_up: true/false indicates to set the physical link to up/down
188462306a36Sopenharmony_ci *
188562306a36Sopenharmony_ci * Force the physical link state by getting the current PHY capabilities from
188662306a36Sopenharmony_ci * hardware and setting the PHY config based on the determined capabilities. If
188762306a36Sopenharmony_ci * link changes a link event will be triggered because both the Enable Automatic
188862306a36Sopenharmony_ci * Link Update and LESM Enable bits are set when setting the PHY capabilities.
188962306a36Sopenharmony_ci *
189062306a36Sopenharmony_ci * Returns 0 on success, negative on failure
189162306a36Sopenharmony_ci */
189262306a36Sopenharmony_cistatic int ice_force_phys_link_state(struct ice_vsi *vsi, bool link_up)
189362306a36Sopenharmony_ci{
189462306a36Sopenharmony_ci	struct ice_aqc_get_phy_caps_data *pcaps;
189562306a36Sopenharmony_ci	struct ice_aqc_set_phy_cfg_data *cfg;
189662306a36Sopenharmony_ci	struct ice_port_info *pi;
189762306a36Sopenharmony_ci	struct device *dev;
189862306a36Sopenharmony_ci	int retcode;
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	if (!vsi || !vsi->port_info || !vsi->back)
190162306a36Sopenharmony_ci		return -EINVAL;
190262306a36Sopenharmony_ci	if (vsi->type != ICE_VSI_PF)
190362306a36Sopenharmony_ci		return 0;
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	dev = ice_pf_to_dev(vsi->back);
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci	pi = vsi->port_info;
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
191062306a36Sopenharmony_ci	if (!pcaps)
191162306a36Sopenharmony_ci		return -ENOMEM;
191262306a36Sopenharmony_ci
191362306a36Sopenharmony_ci	retcode = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_ACTIVE_CFG, pcaps,
191462306a36Sopenharmony_ci				      NULL);
191562306a36Sopenharmony_ci	if (retcode) {
191662306a36Sopenharmony_ci		dev_err(dev, "Failed to get phy capabilities, VSI %d error %d\n",
191762306a36Sopenharmony_ci			vsi->vsi_num, retcode);
191862306a36Sopenharmony_ci		retcode = -EIO;
191962306a36Sopenharmony_ci		goto out;
192062306a36Sopenharmony_ci	}
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_ci	/* No change in link */
192362306a36Sopenharmony_ci	if (link_up == !!(pcaps->caps & ICE_AQC_PHY_EN_LINK) &&
192462306a36Sopenharmony_ci	    link_up == !!(pi->phy.link_info.link_info & ICE_AQ_LINK_UP))
192562306a36Sopenharmony_ci		goto out;
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci	/* Use the current user PHY configuration. The current user PHY
192862306a36Sopenharmony_ci	 * configuration is initialized during probe from PHY capabilities
192962306a36Sopenharmony_ci	 * software mode, and updated on set PHY configuration.
193062306a36Sopenharmony_ci	 */
193162306a36Sopenharmony_ci	cfg = kmemdup(&pi->phy.curr_user_phy_cfg, sizeof(*cfg), GFP_KERNEL);
193262306a36Sopenharmony_ci	if (!cfg) {
193362306a36Sopenharmony_ci		retcode = -ENOMEM;
193462306a36Sopenharmony_ci		goto out;
193562306a36Sopenharmony_ci	}
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	cfg->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT;
193862306a36Sopenharmony_ci	if (link_up)
193962306a36Sopenharmony_ci		cfg->caps |= ICE_AQ_PHY_ENA_LINK;
194062306a36Sopenharmony_ci	else
194162306a36Sopenharmony_ci		cfg->caps &= ~ICE_AQ_PHY_ENA_LINK;
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	retcode = ice_aq_set_phy_cfg(&vsi->back->hw, pi, cfg, NULL);
194462306a36Sopenharmony_ci	if (retcode) {
194562306a36Sopenharmony_ci		dev_err(dev, "Failed to set phy config, VSI %d error %d\n",
194662306a36Sopenharmony_ci			vsi->vsi_num, retcode);
194762306a36Sopenharmony_ci		retcode = -EIO;
194862306a36Sopenharmony_ci	}
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	kfree(cfg);
195162306a36Sopenharmony_ciout:
195262306a36Sopenharmony_ci	kfree(pcaps);
195362306a36Sopenharmony_ci	return retcode;
195462306a36Sopenharmony_ci}
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci/**
195762306a36Sopenharmony_ci * ice_init_nvm_phy_type - Initialize the NVM PHY type
195862306a36Sopenharmony_ci * @pi: port info structure
195962306a36Sopenharmony_ci *
196062306a36Sopenharmony_ci * Initialize nvm_phy_type_[low|high] for link lenient mode support
196162306a36Sopenharmony_ci */
196262306a36Sopenharmony_cistatic int ice_init_nvm_phy_type(struct ice_port_info *pi)
196362306a36Sopenharmony_ci{
196462306a36Sopenharmony_ci	struct ice_aqc_get_phy_caps_data *pcaps;
196562306a36Sopenharmony_ci	struct ice_pf *pf = pi->hw->back;
196662306a36Sopenharmony_ci	int err;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
196962306a36Sopenharmony_ci	if (!pcaps)
197062306a36Sopenharmony_ci		return -ENOMEM;
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci	err = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP_NO_MEDIA,
197362306a36Sopenharmony_ci				  pcaps, NULL);
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci	if (err) {
197662306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "Get PHY capability failed.\n");
197762306a36Sopenharmony_ci		goto out;
197862306a36Sopenharmony_ci	}
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	pf->nvm_phy_type_hi = pcaps->phy_type_high;
198162306a36Sopenharmony_ci	pf->nvm_phy_type_lo = pcaps->phy_type_low;
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ciout:
198462306a36Sopenharmony_ci	kfree(pcaps);
198562306a36Sopenharmony_ci	return err;
198662306a36Sopenharmony_ci}
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci/**
198962306a36Sopenharmony_ci * ice_init_link_dflt_override - Initialize link default override
199062306a36Sopenharmony_ci * @pi: port info structure
199162306a36Sopenharmony_ci *
199262306a36Sopenharmony_ci * Initialize link default override and PHY total port shutdown during probe
199362306a36Sopenharmony_ci */
199462306a36Sopenharmony_cistatic void ice_init_link_dflt_override(struct ice_port_info *pi)
199562306a36Sopenharmony_ci{
199662306a36Sopenharmony_ci	struct ice_link_default_override_tlv *ldo;
199762306a36Sopenharmony_ci	struct ice_pf *pf = pi->hw->back;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	ldo = &pf->link_dflt_override;
200062306a36Sopenharmony_ci	if (ice_get_link_default_override(ldo, pi))
200162306a36Sopenharmony_ci		return;
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	if (!(ldo->options & ICE_LINK_OVERRIDE_PORT_DIS))
200462306a36Sopenharmony_ci		return;
200562306a36Sopenharmony_ci
200662306a36Sopenharmony_ci	/* Enable Total Port Shutdown (override/replace link-down-on-close
200762306a36Sopenharmony_ci	 * ethtool private flag) for ports with Port Disable bit set.
200862306a36Sopenharmony_ci	 */
200962306a36Sopenharmony_ci	set_bit(ICE_FLAG_TOTAL_PORT_SHUTDOWN_ENA, pf->flags);
201062306a36Sopenharmony_ci	set_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags);
201162306a36Sopenharmony_ci}
201262306a36Sopenharmony_ci
201362306a36Sopenharmony_ci/**
201462306a36Sopenharmony_ci * ice_init_phy_cfg_dflt_override - Initialize PHY cfg default override settings
201562306a36Sopenharmony_ci * @pi: port info structure
201662306a36Sopenharmony_ci *
201762306a36Sopenharmony_ci * If default override is enabled, initialize the user PHY cfg speed and FEC
201862306a36Sopenharmony_ci * settings using the default override mask from the NVM.
201962306a36Sopenharmony_ci *
202062306a36Sopenharmony_ci * The PHY should only be configured with the default override settings the
202162306a36Sopenharmony_ci * first time media is available. The ICE_LINK_DEFAULT_OVERRIDE_PENDING state
202262306a36Sopenharmony_ci * is used to indicate that the user PHY cfg default override is initialized
202362306a36Sopenharmony_ci * and the PHY has not been configured with the default override settings. The
202462306a36Sopenharmony_ci * state is set here, and cleared in ice_configure_phy the first time the PHY is
202562306a36Sopenharmony_ci * configured.
202662306a36Sopenharmony_ci *
202762306a36Sopenharmony_ci * This function should be called only if the FW doesn't support default
202862306a36Sopenharmony_ci * configuration mode, as reported by ice_fw_supports_report_dflt_cfg.
202962306a36Sopenharmony_ci */
203062306a36Sopenharmony_cistatic void ice_init_phy_cfg_dflt_override(struct ice_port_info *pi)
203162306a36Sopenharmony_ci{
203262306a36Sopenharmony_ci	struct ice_link_default_override_tlv *ldo;
203362306a36Sopenharmony_ci	struct ice_aqc_set_phy_cfg_data *cfg;
203462306a36Sopenharmony_ci	struct ice_phy_info *phy = &pi->phy;
203562306a36Sopenharmony_ci	struct ice_pf *pf = pi->hw->back;
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	ldo = &pf->link_dflt_override;
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci	/* If link default override is enabled, use to mask NVM PHY capabilities
204062306a36Sopenharmony_ci	 * for speed and FEC default configuration.
204162306a36Sopenharmony_ci	 */
204262306a36Sopenharmony_ci	cfg = &phy->curr_user_phy_cfg;
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_ci	if (ldo->phy_type_low || ldo->phy_type_high) {
204562306a36Sopenharmony_ci		cfg->phy_type_low = pf->nvm_phy_type_lo &
204662306a36Sopenharmony_ci				    cpu_to_le64(ldo->phy_type_low);
204762306a36Sopenharmony_ci		cfg->phy_type_high = pf->nvm_phy_type_hi &
204862306a36Sopenharmony_ci				     cpu_to_le64(ldo->phy_type_high);
204962306a36Sopenharmony_ci	}
205062306a36Sopenharmony_ci	cfg->link_fec_opt = ldo->fec_options;
205162306a36Sopenharmony_ci	phy->curr_user_fec_req = ICE_FEC_AUTO;
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	set_bit(ICE_LINK_DEFAULT_OVERRIDE_PENDING, pf->state);
205462306a36Sopenharmony_ci}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci/**
205762306a36Sopenharmony_ci * ice_init_phy_user_cfg - Initialize the PHY user configuration
205862306a36Sopenharmony_ci * @pi: port info structure
205962306a36Sopenharmony_ci *
206062306a36Sopenharmony_ci * Initialize the current user PHY configuration, speed, FEC, and FC requested
206162306a36Sopenharmony_ci * mode to default. The PHY defaults are from get PHY capabilities topology
206262306a36Sopenharmony_ci * with media so call when media is first available. An error is returned if
206362306a36Sopenharmony_ci * called when media is not available. The PHY initialization completed state is
206462306a36Sopenharmony_ci * set here.
206562306a36Sopenharmony_ci *
206662306a36Sopenharmony_ci * These configurations are used when setting PHY
206762306a36Sopenharmony_ci * configuration. The user PHY configuration is updated on set PHY
206862306a36Sopenharmony_ci * configuration. Returns 0 on success, negative on failure
206962306a36Sopenharmony_ci */
207062306a36Sopenharmony_cistatic int ice_init_phy_user_cfg(struct ice_port_info *pi)
207162306a36Sopenharmony_ci{
207262306a36Sopenharmony_ci	struct ice_aqc_get_phy_caps_data *pcaps;
207362306a36Sopenharmony_ci	struct ice_phy_info *phy = &pi->phy;
207462306a36Sopenharmony_ci	struct ice_pf *pf = pi->hw->back;
207562306a36Sopenharmony_ci	int err;
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci	if (!(phy->link_info.link_info & ICE_AQ_MEDIA_AVAILABLE))
207862306a36Sopenharmony_ci		return -EIO;
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci	pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
208162306a36Sopenharmony_ci	if (!pcaps)
208262306a36Sopenharmony_ci		return -ENOMEM;
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	if (ice_fw_supports_report_dflt_cfg(pi->hw))
208562306a36Sopenharmony_ci		err = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_DFLT_CFG,
208662306a36Sopenharmony_ci					  pcaps, NULL);
208762306a36Sopenharmony_ci	else
208862306a36Sopenharmony_ci		err = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP_MEDIA,
208962306a36Sopenharmony_ci					  pcaps, NULL);
209062306a36Sopenharmony_ci	if (err) {
209162306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "Get PHY capability failed.\n");
209262306a36Sopenharmony_ci		goto err_out;
209362306a36Sopenharmony_ci	}
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	ice_copy_phy_caps_to_cfg(pi, pcaps, &pi->phy.curr_user_phy_cfg);
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci	/* check if lenient mode is supported and enabled */
209862306a36Sopenharmony_ci	if (ice_fw_supports_link_override(pi->hw) &&
209962306a36Sopenharmony_ci	    !(pcaps->module_compliance_enforcement &
210062306a36Sopenharmony_ci	      ICE_AQC_MOD_ENFORCE_STRICT_MODE)) {
210162306a36Sopenharmony_ci		set_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags);
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci		/* if the FW supports default PHY configuration mode, then the driver
210462306a36Sopenharmony_ci		 * does not have to apply link override settings. If not,
210562306a36Sopenharmony_ci		 * initialize user PHY configuration with link override values
210662306a36Sopenharmony_ci		 */
210762306a36Sopenharmony_ci		if (!ice_fw_supports_report_dflt_cfg(pi->hw) &&
210862306a36Sopenharmony_ci		    (pf->link_dflt_override.options & ICE_LINK_OVERRIDE_EN)) {
210962306a36Sopenharmony_ci			ice_init_phy_cfg_dflt_override(pi);
211062306a36Sopenharmony_ci			goto out;
211162306a36Sopenharmony_ci		}
211262306a36Sopenharmony_ci	}
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci	/* if link default override is not enabled, set user flow control and
211562306a36Sopenharmony_ci	 * FEC settings based on what get_phy_caps returned
211662306a36Sopenharmony_ci	 */
211762306a36Sopenharmony_ci	phy->curr_user_fec_req = ice_caps_to_fec_mode(pcaps->caps,
211862306a36Sopenharmony_ci						      pcaps->link_fec_options);
211962306a36Sopenharmony_ci	phy->curr_user_fc_req = ice_caps_to_fc_mode(pcaps->caps);
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ciout:
212262306a36Sopenharmony_ci	phy->curr_user_speed_req = ICE_AQ_LINK_SPEED_M;
212362306a36Sopenharmony_ci	set_bit(ICE_PHY_INIT_COMPLETE, pf->state);
212462306a36Sopenharmony_cierr_out:
212562306a36Sopenharmony_ci	kfree(pcaps);
212662306a36Sopenharmony_ci	return err;
212762306a36Sopenharmony_ci}
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci/**
213062306a36Sopenharmony_ci * ice_configure_phy - configure PHY
213162306a36Sopenharmony_ci * @vsi: VSI of PHY
213262306a36Sopenharmony_ci *
213362306a36Sopenharmony_ci * Set the PHY configuration. If the current PHY configuration is the same as
213462306a36Sopenharmony_ci * the curr_user_phy_cfg, then do nothing to avoid link flap. Otherwise
213562306a36Sopenharmony_ci * configure the based get PHY capabilities for topology with media.
213662306a36Sopenharmony_ci */
213762306a36Sopenharmony_cistatic int ice_configure_phy(struct ice_vsi *vsi)
213862306a36Sopenharmony_ci{
213962306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(vsi->back);
214062306a36Sopenharmony_ci	struct ice_port_info *pi = vsi->port_info;
214162306a36Sopenharmony_ci	struct ice_aqc_get_phy_caps_data *pcaps;
214262306a36Sopenharmony_ci	struct ice_aqc_set_phy_cfg_data *cfg;
214362306a36Sopenharmony_ci	struct ice_phy_info *phy = &pi->phy;
214462306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
214562306a36Sopenharmony_ci	int err;
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	/* Ensure we have media as we cannot configure a medialess port */
214862306a36Sopenharmony_ci	if (!(phy->link_info.link_info & ICE_AQ_MEDIA_AVAILABLE))
214962306a36Sopenharmony_ci		return -ENOMEDIUM;
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci	ice_print_topo_conflict(vsi);
215262306a36Sopenharmony_ci
215362306a36Sopenharmony_ci	if (!test_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags) &&
215462306a36Sopenharmony_ci	    phy->link_info.topo_media_conflict == ICE_AQ_LINK_TOPO_UNSUPP_MEDIA)
215562306a36Sopenharmony_ci		return -EPERM;
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags))
215862306a36Sopenharmony_ci		return ice_force_phys_link_state(vsi, true);
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL);
216162306a36Sopenharmony_ci	if (!pcaps)
216262306a36Sopenharmony_ci		return -ENOMEM;
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci	/* Get current PHY config */
216562306a36Sopenharmony_ci	err = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_ACTIVE_CFG, pcaps,
216662306a36Sopenharmony_ci				  NULL);
216762306a36Sopenharmony_ci	if (err) {
216862306a36Sopenharmony_ci		dev_err(dev, "Failed to get PHY configuration, VSI %d error %d\n",
216962306a36Sopenharmony_ci			vsi->vsi_num, err);
217062306a36Sopenharmony_ci		goto done;
217162306a36Sopenharmony_ci	}
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	/* If PHY enable link is configured and configuration has not changed,
217462306a36Sopenharmony_ci	 * there's nothing to do
217562306a36Sopenharmony_ci	 */
217662306a36Sopenharmony_ci	if (pcaps->caps & ICE_AQC_PHY_EN_LINK &&
217762306a36Sopenharmony_ci	    ice_phy_caps_equals_cfg(pcaps, &phy->curr_user_phy_cfg))
217862306a36Sopenharmony_ci		goto done;
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	/* Use PHY topology as baseline for configuration */
218162306a36Sopenharmony_ci	memset(pcaps, 0, sizeof(*pcaps));
218262306a36Sopenharmony_ci	if (ice_fw_supports_report_dflt_cfg(pi->hw))
218362306a36Sopenharmony_ci		err = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_DFLT_CFG,
218462306a36Sopenharmony_ci					  pcaps, NULL);
218562306a36Sopenharmony_ci	else
218662306a36Sopenharmony_ci		err = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP_MEDIA,
218762306a36Sopenharmony_ci					  pcaps, NULL);
218862306a36Sopenharmony_ci	if (err) {
218962306a36Sopenharmony_ci		dev_err(dev, "Failed to get PHY caps, VSI %d error %d\n",
219062306a36Sopenharmony_ci			vsi->vsi_num, err);
219162306a36Sopenharmony_ci		goto done;
219262306a36Sopenharmony_ci	}
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci	cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
219562306a36Sopenharmony_ci	if (!cfg) {
219662306a36Sopenharmony_ci		err = -ENOMEM;
219762306a36Sopenharmony_ci		goto done;
219862306a36Sopenharmony_ci	}
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci	ice_copy_phy_caps_to_cfg(pi, pcaps, cfg);
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_ci	/* Speed - If default override pending, use curr_user_phy_cfg set in
220362306a36Sopenharmony_ci	 * ice_init_phy_user_cfg_ldo.
220462306a36Sopenharmony_ci	 */
220562306a36Sopenharmony_ci	if (test_and_clear_bit(ICE_LINK_DEFAULT_OVERRIDE_PENDING,
220662306a36Sopenharmony_ci			       vsi->back->state)) {
220762306a36Sopenharmony_ci		cfg->phy_type_low = phy->curr_user_phy_cfg.phy_type_low;
220862306a36Sopenharmony_ci		cfg->phy_type_high = phy->curr_user_phy_cfg.phy_type_high;
220962306a36Sopenharmony_ci	} else {
221062306a36Sopenharmony_ci		u64 phy_low = 0, phy_high = 0;
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci		ice_update_phy_type(&phy_low, &phy_high,
221362306a36Sopenharmony_ci				    pi->phy.curr_user_speed_req);
221462306a36Sopenharmony_ci		cfg->phy_type_low = pcaps->phy_type_low & cpu_to_le64(phy_low);
221562306a36Sopenharmony_ci		cfg->phy_type_high = pcaps->phy_type_high &
221662306a36Sopenharmony_ci				     cpu_to_le64(phy_high);
221762306a36Sopenharmony_ci	}
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	/* Can't provide what was requested; use PHY capabilities */
222062306a36Sopenharmony_ci	if (!cfg->phy_type_low && !cfg->phy_type_high) {
222162306a36Sopenharmony_ci		cfg->phy_type_low = pcaps->phy_type_low;
222262306a36Sopenharmony_ci		cfg->phy_type_high = pcaps->phy_type_high;
222362306a36Sopenharmony_ci	}
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	/* FEC */
222662306a36Sopenharmony_ci	ice_cfg_phy_fec(pi, cfg, phy->curr_user_fec_req);
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci	/* Can't provide what was requested; use PHY capabilities */
222962306a36Sopenharmony_ci	if (cfg->link_fec_opt !=
223062306a36Sopenharmony_ci	    (cfg->link_fec_opt & pcaps->link_fec_options)) {
223162306a36Sopenharmony_ci		cfg->caps |= pcaps->caps & ICE_AQC_PHY_EN_AUTO_FEC;
223262306a36Sopenharmony_ci		cfg->link_fec_opt = pcaps->link_fec_options;
223362306a36Sopenharmony_ci	}
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci	/* Flow Control - always supported; no need to check against
223662306a36Sopenharmony_ci	 * capabilities
223762306a36Sopenharmony_ci	 */
223862306a36Sopenharmony_ci	ice_cfg_phy_fc(pi, cfg, phy->curr_user_fc_req);
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci	/* Enable link and link update */
224162306a36Sopenharmony_ci	cfg->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT | ICE_AQ_PHY_ENA_LINK;
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	err = ice_aq_set_phy_cfg(&pf->hw, pi, cfg, NULL);
224462306a36Sopenharmony_ci	if (err)
224562306a36Sopenharmony_ci		dev_err(dev, "Failed to set phy config, VSI %d error %d\n",
224662306a36Sopenharmony_ci			vsi->vsi_num, err);
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	kfree(cfg);
224962306a36Sopenharmony_cidone:
225062306a36Sopenharmony_ci	kfree(pcaps);
225162306a36Sopenharmony_ci	return err;
225262306a36Sopenharmony_ci}
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci/**
225562306a36Sopenharmony_ci * ice_check_media_subtask - Check for media
225662306a36Sopenharmony_ci * @pf: pointer to PF struct
225762306a36Sopenharmony_ci *
225862306a36Sopenharmony_ci * If media is available, then initialize PHY user configuration if it is not
225962306a36Sopenharmony_ci * been, and configure the PHY if the interface is up.
226062306a36Sopenharmony_ci */
226162306a36Sopenharmony_cistatic void ice_check_media_subtask(struct ice_pf *pf)
226262306a36Sopenharmony_ci{
226362306a36Sopenharmony_ci	struct ice_port_info *pi;
226462306a36Sopenharmony_ci	struct ice_vsi *vsi;
226562306a36Sopenharmony_ci	int err;
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci	/* No need to check for media if it's already present */
226862306a36Sopenharmony_ci	if (!test_bit(ICE_FLAG_NO_MEDIA, pf->flags))
226962306a36Sopenharmony_ci		return;
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	vsi = ice_get_main_vsi(pf);
227262306a36Sopenharmony_ci	if (!vsi)
227362306a36Sopenharmony_ci		return;
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	/* Refresh link info and check if media is present */
227662306a36Sopenharmony_ci	pi = vsi->port_info;
227762306a36Sopenharmony_ci	err = ice_update_link_info(pi);
227862306a36Sopenharmony_ci	if (err)
227962306a36Sopenharmony_ci		return;
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci	ice_check_link_cfg_err(pf, pi->phy.link_info.link_cfg_err);
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci	if (pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE) {
228462306a36Sopenharmony_ci		if (!test_bit(ICE_PHY_INIT_COMPLETE, pf->state))
228562306a36Sopenharmony_ci			ice_init_phy_user_cfg(pi);
228662306a36Sopenharmony_ci
228762306a36Sopenharmony_ci		/* PHY settings are reset on media insertion, reconfigure
228862306a36Sopenharmony_ci		 * PHY to preserve settings.
228962306a36Sopenharmony_ci		 */
229062306a36Sopenharmony_ci		if (test_bit(ICE_VSI_DOWN, vsi->state) &&
229162306a36Sopenharmony_ci		    test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags))
229262306a36Sopenharmony_ci			return;
229362306a36Sopenharmony_ci
229462306a36Sopenharmony_ci		err = ice_configure_phy(vsi);
229562306a36Sopenharmony_ci		if (!err)
229662306a36Sopenharmony_ci			clear_bit(ICE_FLAG_NO_MEDIA, pf->flags);
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci		/* A Link Status Event will be generated; the event handler
229962306a36Sopenharmony_ci		 * will complete bringing the interface up
230062306a36Sopenharmony_ci		 */
230162306a36Sopenharmony_ci	}
230262306a36Sopenharmony_ci}
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ci/**
230562306a36Sopenharmony_ci * ice_service_task - manage and run subtasks
230662306a36Sopenharmony_ci * @work: pointer to work_struct contained by the PF struct
230762306a36Sopenharmony_ci */
230862306a36Sopenharmony_cistatic void ice_service_task(struct work_struct *work)
230962306a36Sopenharmony_ci{
231062306a36Sopenharmony_ci	struct ice_pf *pf = container_of(work, struct ice_pf, serv_task);
231162306a36Sopenharmony_ci	unsigned long start_time = jiffies;
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci	/* subtasks */
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci	/* process reset requests first */
231662306a36Sopenharmony_ci	ice_reset_subtask(pf);
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_ci	/* bail if a reset/recovery cycle is pending or rebuild failed */
231962306a36Sopenharmony_ci	if (ice_is_reset_in_progress(pf->state) ||
232062306a36Sopenharmony_ci	    test_bit(ICE_SUSPENDED, pf->state) ||
232162306a36Sopenharmony_ci	    test_bit(ICE_NEEDS_RESTART, pf->state)) {
232262306a36Sopenharmony_ci		ice_service_task_complete(pf);
232362306a36Sopenharmony_ci		return;
232462306a36Sopenharmony_ci	}
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	if (test_and_clear_bit(ICE_AUX_ERR_PENDING, pf->state)) {
232762306a36Sopenharmony_ci		struct iidc_event *event;
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci		event = kzalloc(sizeof(*event), GFP_KERNEL);
233062306a36Sopenharmony_ci		if (event) {
233162306a36Sopenharmony_ci			set_bit(IIDC_EVENT_CRIT_ERR, event->type);
233262306a36Sopenharmony_ci			/* report the entire OICR value to AUX driver */
233362306a36Sopenharmony_ci			swap(event->reg, pf->oicr_err_reg);
233462306a36Sopenharmony_ci			ice_send_event_to_aux(pf, event);
233562306a36Sopenharmony_ci			kfree(event);
233662306a36Sopenharmony_ci		}
233762306a36Sopenharmony_ci	}
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	/* unplug aux dev per request, if an unplug request came in
234062306a36Sopenharmony_ci	 * while processing a plug request, this will handle it
234162306a36Sopenharmony_ci	 */
234262306a36Sopenharmony_ci	if (test_and_clear_bit(ICE_FLAG_UNPLUG_AUX_DEV, pf->flags))
234362306a36Sopenharmony_ci		ice_unplug_aux_dev(pf);
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci	/* Plug aux device per request */
234662306a36Sopenharmony_ci	if (test_and_clear_bit(ICE_FLAG_PLUG_AUX_DEV, pf->flags))
234762306a36Sopenharmony_ci		ice_plug_aux_dev(pf);
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci	if (test_and_clear_bit(ICE_FLAG_MTU_CHANGED, pf->flags)) {
235062306a36Sopenharmony_ci		struct iidc_event *event;
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci		event = kzalloc(sizeof(*event), GFP_KERNEL);
235362306a36Sopenharmony_ci		if (event) {
235462306a36Sopenharmony_ci			set_bit(IIDC_EVENT_AFTER_MTU_CHANGE, event->type);
235562306a36Sopenharmony_ci			ice_send_event_to_aux(pf, event);
235662306a36Sopenharmony_ci			kfree(event);
235762306a36Sopenharmony_ci		}
235862306a36Sopenharmony_ci	}
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci	ice_clean_adminq_subtask(pf);
236162306a36Sopenharmony_ci	ice_check_media_subtask(pf);
236262306a36Sopenharmony_ci	ice_check_for_hang_subtask(pf);
236362306a36Sopenharmony_ci	ice_sync_fltr_subtask(pf);
236462306a36Sopenharmony_ci	ice_handle_mdd_event(pf);
236562306a36Sopenharmony_ci	ice_watchdog_subtask(pf);
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci	if (ice_is_safe_mode(pf)) {
236862306a36Sopenharmony_ci		ice_service_task_complete(pf);
236962306a36Sopenharmony_ci		return;
237062306a36Sopenharmony_ci	}
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	ice_process_vflr_event(pf);
237362306a36Sopenharmony_ci	ice_clean_mailboxq_subtask(pf);
237462306a36Sopenharmony_ci	ice_clean_sbq_subtask(pf);
237562306a36Sopenharmony_ci	ice_sync_arfs_fltrs(pf);
237662306a36Sopenharmony_ci	ice_flush_fdir_ctx(pf);
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci	/* Clear ICE_SERVICE_SCHED flag to allow scheduling next event */
237962306a36Sopenharmony_ci	ice_service_task_complete(pf);
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci	/* If the tasks have taken longer than one service timer period
238262306a36Sopenharmony_ci	 * or there is more work to be done, reset the service timer to
238362306a36Sopenharmony_ci	 * schedule the service task now.
238462306a36Sopenharmony_ci	 */
238562306a36Sopenharmony_ci	if (time_after(jiffies, (start_time + pf->serv_tmr_period)) ||
238662306a36Sopenharmony_ci	    test_bit(ICE_MDD_EVENT_PENDING, pf->state) ||
238762306a36Sopenharmony_ci	    test_bit(ICE_VFLR_EVENT_PENDING, pf->state) ||
238862306a36Sopenharmony_ci	    test_bit(ICE_MAILBOXQ_EVENT_PENDING, pf->state) ||
238962306a36Sopenharmony_ci	    test_bit(ICE_FD_VF_FLUSH_CTX, pf->state) ||
239062306a36Sopenharmony_ci	    test_bit(ICE_SIDEBANDQ_EVENT_PENDING, pf->state) ||
239162306a36Sopenharmony_ci	    test_bit(ICE_ADMINQ_EVENT_PENDING, pf->state))
239262306a36Sopenharmony_ci		mod_timer(&pf->serv_tmr, jiffies);
239362306a36Sopenharmony_ci}
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_ci/**
239662306a36Sopenharmony_ci * ice_set_ctrlq_len - helper function to set controlq length
239762306a36Sopenharmony_ci * @hw: pointer to the HW instance
239862306a36Sopenharmony_ci */
239962306a36Sopenharmony_cistatic void ice_set_ctrlq_len(struct ice_hw *hw)
240062306a36Sopenharmony_ci{
240162306a36Sopenharmony_ci	hw->adminq.num_rq_entries = ICE_AQ_LEN;
240262306a36Sopenharmony_ci	hw->adminq.num_sq_entries = ICE_AQ_LEN;
240362306a36Sopenharmony_ci	hw->adminq.rq_buf_size = ICE_AQ_MAX_BUF_LEN;
240462306a36Sopenharmony_ci	hw->adminq.sq_buf_size = ICE_AQ_MAX_BUF_LEN;
240562306a36Sopenharmony_ci	hw->mailboxq.num_rq_entries = PF_MBX_ARQLEN_ARQLEN_M;
240662306a36Sopenharmony_ci	hw->mailboxq.num_sq_entries = ICE_MBXSQ_LEN;
240762306a36Sopenharmony_ci	hw->mailboxq.rq_buf_size = ICE_MBXQ_MAX_BUF_LEN;
240862306a36Sopenharmony_ci	hw->mailboxq.sq_buf_size = ICE_MBXQ_MAX_BUF_LEN;
240962306a36Sopenharmony_ci	hw->sbq.num_rq_entries = ICE_SBQ_LEN;
241062306a36Sopenharmony_ci	hw->sbq.num_sq_entries = ICE_SBQ_LEN;
241162306a36Sopenharmony_ci	hw->sbq.rq_buf_size = ICE_SBQ_MAX_BUF_LEN;
241262306a36Sopenharmony_ci	hw->sbq.sq_buf_size = ICE_SBQ_MAX_BUF_LEN;
241362306a36Sopenharmony_ci}
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci/**
241662306a36Sopenharmony_ci * ice_schedule_reset - schedule a reset
241762306a36Sopenharmony_ci * @pf: board private structure
241862306a36Sopenharmony_ci * @reset: reset being requested
241962306a36Sopenharmony_ci */
242062306a36Sopenharmony_ciint ice_schedule_reset(struct ice_pf *pf, enum ice_reset_req reset)
242162306a36Sopenharmony_ci{
242262306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_ci	/* bail out if earlier reset has failed */
242562306a36Sopenharmony_ci	if (test_bit(ICE_RESET_FAILED, pf->state)) {
242662306a36Sopenharmony_ci		dev_dbg(dev, "earlier reset has failed\n");
242762306a36Sopenharmony_ci		return -EIO;
242862306a36Sopenharmony_ci	}
242962306a36Sopenharmony_ci	/* bail if reset/recovery already in progress */
243062306a36Sopenharmony_ci	if (ice_is_reset_in_progress(pf->state)) {
243162306a36Sopenharmony_ci		dev_dbg(dev, "Reset already in progress\n");
243262306a36Sopenharmony_ci		return -EBUSY;
243362306a36Sopenharmony_ci	}
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	switch (reset) {
243662306a36Sopenharmony_ci	case ICE_RESET_PFR:
243762306a36Sopenharmony_ci		set_bit(ICE_PFR_REQ, pf->state);
243862306a36Sopenharmony_ci		break;
243962306a36Sopenharmony_ci	case ICE_RESET_CORER:
244062306a36Sopenharmony_ci		set_bit(ICE_CORER_REQ, pf->state);
244162306a36Sopenharmony_ci		break;
244262306a36Sopenharmony_ci	case ICE_RESET_GLOBR:
244362306a36Sopenharmony_ci		set_bit(ICE_GLOBR_REQ, pf->state);
244462306a36Sopenharmony_ci		break;
244562306a36Sopenharmony_ci	default:
244662306a36Sopenharmony_ci		return -EINVAL;
244762306a36Sopenharmony_ci	}
244862306a36Sopenharmony_ci
244962306a36Sopenharmony_ci	ice_service_task_schedule(pf);
245062306a36Sopenharmony_ci	return 0;
245162306a36Sopenharmony_ci}
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci/**
245462306a36Sopenharmony_ci * ice_irq_affinity_notify - Callback for affinity changes
245562306a36Sopenharmony_ci * @notify: context as to what irq was changed
245662306a36Sopenharmony_ci * @mask: the new affinity mask
245762306a36Sopenharmony_ci *
245862306a36Sopenharmony_ci * This is a callback function used by the irq_set_affinity_notifier function
245962306a36Sopenharmony_ci * so that we may register to receive changes to the irq affinity masks.
246062306a36Sopenharmony_ci */
246162306a36Sopenharmony_cistatic void
246262306a36Sopenharmony_ciice_irq_affinity_notify(struct irq_affinity_notify *notify,
246362306a36Sopenharmony_ci			const cpumask_t *mask)
246462306a36Sopenharmony_ci{
246562306a36Sopenharmony_ci	struct ice_q_vector *q_vector =
246662306a36Sopenharmony_ci		container_of(notify, struct ice_q_vector, affinity_notify);
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci	cpumask_copy(&q_vector->affinity_mask, mask);
246962306a36Sopenharmony_ci}
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci/**
247262306a36Sopenharmony_ci * ice_irq_affinity_release - Callback for affinity notifier release
247362306a36Sopenharmony_ci * @ref: internal core kernel usage
247462306a36Sopenharmony_ci *
247562306a36Sopenharmony_ci * This is a callback function used by the irq_set_affinity_notifier function
247662306a36Sopenharmony_ci * to inform the current notification subscriber that they will no longer
247762306a36Sopenharmony_ci * receive notifications.
247862306a36Sopenharmony_ci */
247962306a36Sopenharmony_cistatic void ice_irq_affinity_release(struct kref __always_unused *ref) {}
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_ci/**
248262306a36Sopenharmony_ci * ice_vsi_ena_irq - Enable IRQ for the given VSI
248362306a36Sopenharmony_ci * @vsi: the VSI being configured
248462306a36Sopenharmony_ci */
248562306a36Sopenharmony_cistatic int ice_vsi_ena_irq(struct ice_vsi *vsi)
248662306a36Sopenharmony_ci{
248762306a36Sopenharmony_ci	struct ice_hw *hw = &vsi->back->hw;
248862306a36Sopenharmony_ci	int i;
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci	ice_for_each_q_vector(vsi, i)
249162306a36Sopenharmony_ci		ice_irq_dynamic_ena(hw, vsi, vsi->q_vectors[i]);
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci	ice_flush(hw);
249462306a36Sopenharmony_ci	return 0;
249562306a36Sopenharmony_ci}
249662306a36Sopenharmony_ci
249762306a36Sopenharmony_ci/**
249862306a36Sopenharmony_ci * ice_vsi_req_irq_msix - get MSI-X vectors from the OS for the VSI
249962306a36Sopenharmony_ci * @vsi: the VSI being configured
250062306a36Sopenharmony_ci * @basename: name for the vector
250162306a36Sopenharmony_ci */
250262306a36Sopenharmony_cistatic int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename)
250362306a36Sopenharmony_ci{
250462306a36Sopenharmony_ci	int q_vectors = vsi->num_q_vectors;
250562306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
250662306a36Sopenharmony_ci	struct device *dev;
250762306a36Sopenharmony_ci	int rx_int_idx = 0;
250862306a36Sopenharmony_ci	int tx_int_idx = 0;
250962306a36Sopenharmony_ci	int vector, err;
251062306a36Sopenharmony_ci	int irq_num;
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
251362306a36Sopenharmony_ci	for (vector = 0; vector < q_vectors; vector++) {
251462306a36Sopenharmony_ci		struct ice_q_vector *q_vector = vsi->q_vectors[vector];
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci		irq_num = q_vector->irq.virq;
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_ci		if (q_vector->tx.tx_ring && q_vector->rx.rx_ring) {
251962306a36Sopenharmony_ci			snprintf(q_vector->name, sizeof(q_vector->name) - 1,
252062306a36Sopenharmony_ci				 "%s-%s-%d", basename, "TxRx", rx_int_idx++);
252162306a36Sopenharmony_ci			tx_int_idx++;
252262306a36Sopenharmony_ci		} else if (q_vector->rx.rx_ring) {
252362306a36Sopenharmony_ci			snprintf(q_vector->name, sizeof(q_vector->name) - 1,
252462306a36Sopenharmony_ci				 "%s-%s-%d", basename, "rx", rx_int_idx++);
252562306a36Sopenharmony_ci		} else if (q_vector->tx.tx_ring) {
252662306a36Sopenharmony_ci			snprintf(q_vector->name, sizeof(q_vector->name) - 1,
252762306a36Sopenharmony_ci				 "%s-%s-%d", basename, "tx", tx_int_idx++);
252862306a36Sopenharmony_ci		} else {
252962306a36Sopenharmony_ci			/* skip this unused q_vector */
253062306a36Sopenharmony_ci			continue;
253162306a36Sopenharmony_ci		}
253262306a36Sopenharmony_ci		if (vsi->type == ICE_VSI_CTRL && vsi->vf)
253362306a36Sopenharmony_ci			err = devm_request_irq(dev, irq_num, vsi->irq_handler,
253462306a36Sopenharmony_ci					       IRQF_SHARED, q_vector->name,
253562306a36Sopenharmony_ci					       q_vector);
253662306a36Sopenharmony_ci		else
253762306a36Sopenharmony_ci			err = devm_request_irq(dev, irq_num, vsi->irq_handler,
253862306a36Sopenharmony_ci					       0, q_vector->name, q_vector);
253962306a36Sopenharmony_ci		if (err) {
254062306a36Sopenharmony_ci			netdev_err(vsi->netdev, "MSIX request_irq failed, error: %d\n",
254162306a36Sopenharmony_ci				   err);
254262306a36Sopenharmony_ci			goto free_q_irqs;
254362306a36Sopenharmony_ci		}
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci		/* register for affinity change notifications */
254662306a36Sopenharmony_ci		if (!IS_ENABLED(CONFIG_RFS_ACCEL)) {
254762306a36Sopenharmony_ci			struct irq_affinity_notify *affinity_notify;
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_ci			affinity_notify = &q_vector->affinity_notify;
255062306a36Sopenharmony_ci			affinity_notify->notify = ice_irq_affinity_notify;
255162306a36Sopenharmony_ci			affinity_notify->release = ice_irq_affinity_release;
255262306a36Sopenharmony_ci			irq_set_affinity_notifier(irq_num, affinity_notify);
255362306a36Sopenharmony_ci		}
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci		/* assign the mask for this irq */
255662306a36Sopenharmony_ci		irq_set_affinity_hint(irq_num, &q_vector->affinity_mask);
255762306a36Sopenharmony_ci	}
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_ci	err = ice_set_cpu_rx_rmap(vsi);
256062306a36Sopenharmony_ci	if (err) {
256162306a36Sopenharmony_ci		netdev_err(vsi->netdev, "Failed to setup CPU RMAP on VSI %u: %pe\n",
256262306a36Sopenharmony_ci			   vsi->vsi_num, ERR_PTR(err));
256362306a36Sopenharmony_ci		goto free_q_irqs;
256462306a36Sopenharmony_ci	}
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	vsi->irqs_ready = true;
256762306a36Sopenharmony_ci	return 0;
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_cifree_q_irqs:
257062306a36Sopenharmony_ci	while (vector--) {
257162306a36Sopenharmony_ci		irq_num = vsi->q_vectors[vector]->irq.virq;
257262306a36Sopenharmony_ci		if (!IS_ENABLED(CONFIG_RFS_ACCEL))
257362306a36Sopenharmony_ci			irq_set_affinity_notifier(irq_num, NULL);
257462306a36Sopenharmony_ci		irq_set_affinity_hint(irq_num, NULL);
257562306a36Sopenharmony_ci		devm_free_irq(dev, irq_num, &vsi->q_vectors[vector]);
257662306a36Sopenharmony_ci	}
257762306a36Sopenharmony_ci	return err;
257862306a36Sopenharmony_ci}
257962306a36Sopenharmony_ci
258062306a36Sopenharmony_ci/**
258162306a36Sopenharmony_ci * ice_xdp_alloc_setup_rings - Allocate and setup Tx rings for XDP
258262306a36Sopenharmony_ci * @vsi: VSI to setup Tx rings used by XDP
258362306a36Sopenharmony_ci *
258462306a36Sopenharmony_ci * Return 0 on success and negative value on error
258562306a36Sopenharmony_ci */
258662306a36Sopenharmony_cistatic int ice_xdp_alloc_setup_rings(struct ice_vsi *vsi)
258762306a36Sopenharmony_ci{
258862306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(vsi->back);
258962306a36Sopenharmony_ci	struct ice_tx_desc *tx_desc;
259062306a36Sopenharmony_ci	int i, j;
259162306a36Sopenharmony_ci
259262306a36Sopenharmony_ci	ice_for_each_xdp_txq(vsi, i) {
259362306a36Sopenharmony_ci		u16 xdp_q_idx = vsi->alloc_txq + i;
259462306a36Sopenharmony_ci		struct ice_ring_stats *ring_stats;
259562306a36Sopenharmony_ci		struct ice_tx_ring *xdp_ring;
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci		xdp_ring = kzalloc(sizeof(*xdp_ring), GFP_KERNEL);
259862306a36Sopenharmony_ci		if (!xdp_ring)
259962306a36Sopenharmony_ci			goto free_xdp_rings;
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci		ring_stats = kzalloc(sizeof(*ring_stats), GFP_KERNEL);
260262306a36Sopenharmony_ci		if (!ring_stats) {
260362306a36Sopenharmony_ci			ice_free_tx_ring(xdp_ring);
260462306a36Sopenharmony_ci			goto free_xdp_rings;
260562306a36Sopenharmony_ci		}
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_ci		xdp_ring->ring_stats = ring_stats;
260862306a36Sopenharmony_ci		xdp_ring->q_index = xdp_q_idx;
260962306a36Sopenharmony_ci		xdp_ring->reg_idx = vsi->txq_map[xdp_q_idx];
261062306a36Sopenharmony_ci		xdp_ring->vsi = vsi;
261162306a36Sopenharmony_ci		xdp_ring->netdev = NULL;
261262306a36Sopenharmony_ci		xdp_ring->dev = dev;
261362306a36Sopenharmony_ci		xdp_ring->count = vsi->num_tx_desc;
261462306a36Sopenharmony_ci		WRITE_ONCE(vsi->xdp_rings[i], xdp_ring);
261562306a36Sopenharmony_ci		if (ice_setup_tx_ring(xdp_ring))
261662306a36Sopenharmony_ci			goto free_xdp_rings;
261762306a36Sopenharmony_ci		ice_set_ring_xdp(xdp_ring);
261862306a36Sopenharmony_ci		spin_lock_init(&xdp_ring->tx_lock);
261962306a36Sopenharmony_ci		for (j = 0; j < xdp_ring->count; j++) {
262062306a36Sopenharmony_ci			tx_desc = ICE_TX_DESC(xdp_ring, j);
262162306a36Sopenharmony_ci			tx_desc->cmd_type_offset_bsz = 0;
262262306a36Sopenharmony_ci		}
262362306a36Sopenharmony_ci	}
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_ci	return 0;
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_cifree_xdp_rings:
262862306a36Sopenharmony_ci	for (; i >= 0; i--) {
262962306a36Sopenharmony_ci		if (vsi->xdp_rings[i] && vsi->xdp_rings[i]->desc) {
263062306a36Sopenharmony_ci			kfree_rcu(vsi->xdp_rings[i]->ring_stats, rcu);
263162306a36Sopenharmony_ci			vsi->xdp_rings[i]->ring_stats = NULL;
263262306a36Sopenharmony_ci			ice_free_tx_ring(vsi->xdp_rings[i]);
263362306a36Sopenharmony_ci		}
263462306a36Sopenharmony_ci	}
263562306a36Sopenharmony_ci	return -ENOMEM;
263662306a36Sopenharmony_ci}
263762306a36Sopenharmony_ci
263862306a36Sopenharmony_ci/**
263962306a36Sopenharmony_ci * ice_vsi_assign_bpf_prog - set or clear bpf prog pointer on VSI
264062306a36Sopenharmony_ci * @vsi: VSI to set the bpf prog on
264162306a36Sopenharmony_ci * @prog: the bpf prog pointer
264262306a36Sopenharmony_ci */
264362306a36Sopenharmony_cistatic void ice_vsi_assign_bpf_prog(struct ice_vsi *vsi, struct bpf_prog *prog)
264462306a36Sopenharmony_ci{
264562306a36Sopenharmony_ci	struct bpf_prog *old_prog;
264662306a36Sopenharmony_ci	int i;
264762306a36Sopenharmony_ci
264862306a36Sopenharmony_ci	old_prog = xchg(&vsi->xdp_prog, prog);
264962306a36Sopenharmony_ci	ice_for_each_rxq(vsi, i)
265062306a36Sopenharmony_ci		WRITE_ONCE(vsi->rx_rings[i]->xdp_prog, vsi->xdp_prog);
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_ci	if (old_prog)
265362306a36Sopenharmony_ci		bpf_prog_put(old_prog);
265462306a36Sopenharmony_ci}
265562306a36Sopenharmony_ci
265662306a36Sopenharmony_ci/**
265762306a36Sopenharmony_ci * ice_prepare_xdp_rings - Allocate, configure and setup Tx rings for XDP
265862306a36Sopenharmony_ci * @vsi: VSI to bring up Tx rings used by XDP
265962306a36Sopenharmony_ci * @prog: bpf program that will be assigned to VSI
266062306a36Sopenharmony_ci *
266162306a36Sopenharmony_ci * Return 0 on success and negative value on error
266262306a36Sopenharmony_ci */
266362306a36Sopenharmony_ciint ice_prepare_xdp_rings(struct ice_vsi *vsi, struct bpf_prog *prog)
266462306a36Sopenharmony_ci{
266562306a36Sopenharmony_ci	u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 };
266662306a36Sopenharmony_ci	int xdp_rings_rem = vsi->num_xdp_txq;
266762306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
266862306a36Sopenharmony_ci	struct ice_qs_cfg xdp_qs_cfg = {
266962306a36Sopenharmony_ci		.qs_mutex = &pf->avail_q_mutex,
267062306a36Sopenharmony_ci		.pf_map = pf->avail_txqs,
267162306a36Sopenharmony_ci		.pf_map_size = pf->max_pf_txqs,
267262306a36Sopenharmony_ci		.q_count = vsi->num_xdp_txq,
267362306a36Sopenharmony_ci		.scatter_count = ICE_MAX_SCATTER_TXQS,
267462306a36Sopenharmony_ci		.vsi_map = vsi->txq_map,
267562306a36Sopenharmony_ci		.vsi_map_offset = vsi->alloc_txq,
267662306a36Sopenharmony_ci		.mapping_mode = ICE_VSI_MAP_CONTIG
267762306a36Sopenharmony_ci	};
267862306a36Sopenharmony_ci	struct device *dev;
267962306a36Sopenharmony_ci	int i, v_idx;
268062306a36Sopenharmony_ci	int status;
268162306a36Sopenharmony_ci
268262306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
268362306a36Sopenharmony_ci	vsi->xdp_rings = devm_kcalloc(dev, vsi->num_xdp_txq,
268462306a36Sopenharmony_ci				      sizeof(*vsi->xdp_rings), GFP_KERNEL);
268562306a36Sopenharmony_ci	if (!vsi->xdp_rings)
268662306a36Sopenharmony_ci		return -ENOMEM;
268762306a36Sopenharmony_ci
268862306a36Sopenharmony_ci	vsi->xdp_mapping_mode = xdp_qs_cfg.mapping_mode;
268962306a36Sopenharmony_ci	if (__ice_vsi_get_qs(&xdp_qs_cfg))
269062306a36Sopenharmony_ci		goto err_map_xdp;
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci	if (static_key_enabled(&ice_xdp_locking_key))
269362306a36Sopenharmony_ci		netdev_warn(vsi->netdev,
269462306a36Sopenharmony_ci			    "Could not allocate one XDP Tx ring per CPU, XDP_TX/XDP_REDIRECT actions will be slower\n");
269562306a36Sopenharmony_ci
269662306a36Sopenharmony_ci	if (ice_xdp_alloc_setup_rings(vsi))
269762306a36Sopenharmony_ci		goto clear_xdp_rings;
269862306a36Sopenharmony_ci
269962306a36Sopenharmony_ci	/* follow the logic from ice_vsi_map_rings_to_vectors */
270062306a36Sopenharmony_ci	ice_for_each_q_vector(vsi, v_idx) {
270162306a36Sopenharmony_ci		struct ice_q_vector *q_vector = vsi->q_vectors[v_idx];
270262306a36Sopenharmony_ci		int xdp_rings_per_v, q_id, q_base;
270362306a36Sopenharmony_ci
270462306a36Sopenharmony_ci		xdp_rings_per_v = DIV_ROUND_UP(xdp_rings_rem,
270562306a36Sopenharmony_ci					       vsi->num_q_vectors - v_idx);
270662306a36Sopenharmony_ci		q_base = vsi->num_xdp_txq - xdp_rings_rem;
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_ci		for (q_id = q_base; q_id < (q_base + xdp_rings_per_v); q_id++) {
270962306a36Sopenharmony_ci			struct ice_tx_ring *xdp_ring = vsi->xdp_rings[q_id];
271062306a36Sopenharmony_ci
271162306a36Sopenharmony_ci			xdp_ring->q_vector = q_vector;
271262306a36Sopenharmony_ci			xdp_ring->next = q_vector->tx.tx_ring;
271362306a36Sopenharmony_ci			q_vector->tx.tx_ring = xdp_ring;
271462306a36Sopenharmony_ci		}
271562306a36Sopenharmony_ci		xdp_rings_rem -= xdp_rings_per_v;
271662306a36Sopenharmony_ci	}
271762306a36Sopenharmony_ci
271862306a36Sopenharmony_ci	ice_for_each_rxq(vsi, i) {
271962306a36Sopenharmony_ci		if (static_key_enabled(&ice_xdp_locking_key)) {
272062306a36Sopenharmony_ci			vsi->rx_rings[i]->xdp_ring = vsi->xdp_rings[i % vsi->num_xdp_txq];
272162306a36Sopenharmony_ci		} else {
272262306a36Sopenharmony_ci			struct ice_q_vector *q_vector = vsi->rx_rings[i]->q_vector;
272362306a36Sopenharmony_ci			struct ice_tx_ring *ring;
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_ci			ice_for_each_tx_ring(ring, q_vector->tx) {
272662306a36Sopenharmony_ci				if (ice_ring_is_xdp(ring)) {
272762306a36Sopenharmony_ci					vsi->rx_rings[i]->xdp_ring = ring;
272862306a36Sopenharmony_ci					break;
272962306a36Sopenharmony_ci				}
273062306a36Sopenharmony_ci			}
273162306a36Sopenharmony_ci		}
273262306a36Sopenharmony_ci		ice_tx_xsk_pool(vsi, i);
273362306a36Sopenharmony_ci	}
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci	/* omit the scheduler update if in reset path; XDP queues will be
273662306a36Sopenharmony_ci	 * taken into account at the end of ice_vsi_rebuild, where
273762306a36Sopenharmony_ci	 * ice_cfg_vsi_lan is being called
273862306a36Sopenharmony_ci	 */
273962306a36Sopenharmony_ci	if (ice_is_reset_in_progress(pf->state))
274062306a36Sopenharmony_ci		return 0;
274162306a36Sopenharmony_ci
274262306a36Sopenharmony_ci	/* tell the Tx scheduler that right now we have
274362306a36Sopenharmony_ci	 * additional queues
274462306a36Sopenharmony_ci	 */
274562306a36Sopenharmony_ci	for (i = 0; i < vsi->tc_cfg.numtc; i++)
274662306a36Sopenharmony_ci		max_txqs[i] = vsi->num_txq + vsi->num_xdp_txq;
274762306a36Sopenharmony_ci
274862306a36Sopenharmony_ci	status = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc,
274962306a36Sopenharmony_ci				 max_txqs);
275062306a36Sopenharmony_ci	if (status) {
275162306a36Sopenharmony_ci		dev_err(dev, "Failed VSI LAN queue config for XDP, error: %d\n",
275262306a36Sopenharmony_ci			status);
275362306a36Sopenharmony_ci		goto clear_xdp_rings;
275462306a36Sopenharmony_ci	}
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_ci	/* assign the prog only when it's not already present on VSI;
275762306a36Sopenharmony_ci	 * this flow is a subject of both ethtool -L and ndo_bpf flows;
275862306a36Sopenharmony_ci	 * VSI rebuild that happens under ethtool -L can expose us to
275962306a36Sopenharmony_ci	 * the bpf_prog refcount issues as we would be swapping same
276062306a36Sopenharmony_ci	 * bpf_prog pointers from vsi->xdp_prog and calling bpf_prog_put
276162306a36Sopenharmony_ci	 * on it as it would be treated as an 'old_prog'; for ndo_bpf
276262306a36Sopenharmony_ci	 * this is not harmful as dev_xdp_install bumps the refcount
276362306a36Sopenharmony_ci	 * before calling the op exposed by the driver;
276462306a36Sopenharmony_ci	 */
276562306a36Sopenharmony_ci	if (!ice_is_xdp_ena_vsi(vsi))
276662306a36Sopenharmony_ci		ice_vsi_assign_bpf_prog(vsi, prog);
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_ci	return 0;
276962306a36Sopenharmony_ciclear_xdp_rings:
277062306a36Sopenharmony_ci	ice_for_each_xdp_txq(vsi, i)
277162306a36Sopenharmony_ci		if (vsi->xdp_rings[i]) {
277262306a36Sopenharmony_ci			kfree_rcu(vsi->xdp_rings[i], rcu);
277362306a36Sopenharmony_ci			vsi->xdp_rings[i] = NULL;
277462306a36Sopenharmony_ci		}
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_cierr_map_xdp:
277762306a36Sopenharmony_ci	mutex_lock(&pf->avail_q_mutex);
277862306a36Sopenharmony_ci	ice_for_each_xdp_txq(vsi, i) {
277962306a36Sopenharmony_ci		clear_bit(vsi->txq_map[i + vsi->alloc_txq], pf->avail_txqs);
278062306a36Sopenharmony_ci		vsi->txq_map[i + vsi->alloc_txq] = ICE_INVAL_Q_INDEX;
278162306a36Sopenharmony_ci	}
278262306a36Sopenharmony_ci	mutex_unlock(&pf->avail_q_mutex);
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci	devm_kfree(dev, vsi->xdp_rings);
278562306a36Sopenharmony_ci	return -ENOMEM;
278662306a36Sopenharmony_ci}
278762306a36Sopenharmony_ci
278862306a36Sopenharmony_ci/**
278962306a36Sopenharmony_ci * ice_destroy_xdp_rings - undo the configuration made by ice_prepare_xdp_rings
279062306a36Sopenharmony_ci * @vsi: VSI to remove XDP rings
279162306a36Sopenharmony_ci *
279262306a36Sopenharmony_ci * Detach XDP rings from irq vectors, clean up the PF bitmap and free
279362306a36Sopenharmony_ci * resources
279462306a36Sopenharmony_ci */
279562306a36Sopenharmony_ciint ice_destroy_xdp_rings(struct ice_vsi *vsi)
279662306a36Sopenharmony_ci{
279762306a36Sopenharmony_ci	u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 };
279862306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
279962306a36Sopenharmony_ci	int i, v_idx;
280062306a36Sopenharmony_ci
280162306a36Sopenharmony_ci	/* q_vectors are freed in reset path so there's no point in detaching
280262306a36Sopenharmony_ci	 * rings; in case of rebuild being triggered not from reset bits
280362306a36Sopenharmony_ci	 * in pf->state won't be set, so additionally check first q_vector
280462306a36Sopenharmony_ci	 * against NULL
280562306a36Sopenharmony_ci	 */
280662306a36Sopenharmony_ci	if (ice_is_reset_in_progress(pf->state) || !vsi->q_vectors[0])
280762306a36Sopenharmony_ci		goto free_qmap;
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci	ice_for_each_q_vector(vsi, v_idx) {
281062306a36Sopenharmony_ci		struct ice_q_vector *q_vector = vsi->q_vectors[v_idx];
281162306a36Sopenharmony_ci		struct ice_tx_ring *ring;
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_ci		ice_for_each_tx_ring(ring, q_vector->tx)
281462306a36Sopenharmony_ci			if (!ring->tx_buf || !ice_ring_is_xdp(ring))
281562306a36Sopenharmony_ci				break;
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ci		/* restore the value of last node prior to XDP setup */
281862306a36Sopenharmony_ci		q_vector->tx.tx_ring = ring;
281962306a36Sopenharmony_ci	}
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_cifree_qmap:
282262306a36Sopenharmony_ci	mutex_lock(&pf->avail_q_mutex);
282362306a36Sopenharmony_ci	ice_for_each_xdp_txq(vsi, i) {
282462306a36Sopenharmony_ci		clear_bit(vsi->txq_map[i + vsi->alloc_txq], pf->avail_txqs);
282562306a36Sopenharmony_ci		vsi->txq_map[i + vsi->alloc_txq] = ICE_INVAL_Q_INDEX;
282662306a36Sopenharmony_ci	}
282762306a36Sopenharmony_ci	mutex_unlock(&pf->avail_q_mutex);
282862306a36Sopenharmony_ci
282962306a36Sopenharmony_ci	ice_for_each_xdp_txq(vsi, i)
283062306a36Sopenharmony_ci		if (vsi->xdp_rings[i]) {
283162306a36Sopenharmony_ci			if (vsi->xdp_rings[i]->desc) {
283262306a36Sopenharmony_ci				synchronize_rcu();
283362306a36Sopenharmony_ci				ice_free_tx_ring(vsi->xdp_rings[i]);
283462306a36Sopenharmony_ci			}
283562306a36Sopenharmony_ci			kfree_rcu(vsi->xdp_rings[i]->ring_stats, rcu);
283662306a36Sopenharmony_ci			vsi->xdp_rings[i]->ring_stats = NULL;
283762306a36Sopenharmony_ci			kfree_rcu(vsi->xdp_rings[i], rcu);
283862306a36Sopenharmony_ci			vsi->xdp_rings[i] = NULL;
283962306a36Sopenharmony_ci		}
284062306a36Sopenharmony_ci
284162306a36Sopenharmony_ci	devm_kfree(ice_pf_to_dev(pf), vsi->xdp_rings);
284262306a36Sopenharmony_ci	vsi->xdp_rings = NULL;
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci	if (static_key_enabled(&ice_xdp_locking_key))
284562306a36Sopenharmony_ci		static_branch_dec(&ice_xdp_locking_key);
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_ci	if (ice_is_reset_in_progress(pf->state) || !vsi->q_vectors[0])
284862306a36Sopenharmony_ci		return 0;
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci	ice_vsi_assign_bpf_prog(vsi, NULL);
285162306a36Sopenharmony_ci
285262306a36Sopenharmony_ci	/* notify Tx scheduler that we destroyed XDP queues and bring
285362306a36Sopenharmony_ci	 * back the old number of child nodes
285462306a36Sopenharmony_ci	 */
285562306a36Sopenharmony_ci	for (i = 0; i < vsi->tc_cfg.numtc; i++)
285662306a36Sopenharmony_ci		max_txqs[i] = vsi->num_txq;
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_ci	/* change number of XDP Tx queues to 0 */
285962306a36Sopenharmony_ci	vsi->num_xdp_txq = 0;
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci	return ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc,
286262306a36Sopenharmony_ci			       max_txqs);
286362306a36Sopenharmony_ci}
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci/**
286662306a36Sopenharmony_ci * ice_vsi_rx_napi_schedule - Schedule napi on RX queues from VSI
286762306a36Sopenharmony_ci * @vsi: VSI to schedule napi on
286862306a36Sopenharmony_ci */
286962306a36Sopenharmony_cistatic void ice_vsi_rx_napi_schedule(struct ice_vsi *vsi)
287062306a36Sopenharmony_ci{
287162306a36Sopenharmony_ci	int i;
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci	ice_for_each_rxq(vsi, i) {
287462306a36Sopenharmony_ci		struct ice_rx_ring *rx_ring = vsi->rx_rings[i];
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_ci		if (rx_ring->xsk_pool)
287762306a36Sopenharmony_ci			napi_schedule(&rx_ring->q_vector->napi);
287862306a36Sopenharmony_ci	}
287962306a36Sopenharmony_ci}
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ci/**
288262306a36Sopenharmony_ci * ice_vsi_determine_xdp_res - figure out how many Tx qs can XDP have
288362306a36Sopenharmony_ci * @vsi: VSI to determine the count of XDP Tx qs
288462306a36Sopenharmony_ci *
288562306a36Sopenharmony_ci * returns 0 if Tx qs count is higher than at least half of CPU count,
288662306a36Sopenharmony_ci * -ENOMEM otherwise
288762306a36Sopenharmony_ci */
288862306a36Sopenharmony_ciint ice_vsi_determine_xdp_res(struct ice_vsi *vsi)
288962306a36Sopenharmony_ci{
289062306a36Sopenharmony_ci	u16 avail = ice_get_avail_txq_count(vsi->back);
289162306a36Sopenharmony_ci	u16 cpus = num_possible_cpus();
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci	if (avail < cpus / 2)
289462306a36Sopenharmony_ci		return -ENOMEM;
289562306a36Sopenharmony_ci
289662306a36Sopenharmony_ci	vsi->num_xdp_txq = min_t(u16, avail, cpus);
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_ci	if (vsi->num_xdp_txq < cpus)
289962306a36Sopenharmony_ci		static_branch_inc(&ice_xdp_locking_key);
290062306a36Sopenharmony_ci
290162306a36Sopenharmony_ci	return 0;
290262306a36Sopenharmony_ci}
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_ci/**
290562306a36Sopenharmony_ci * ice_max_xdp_frame_size - returns the maximum allowed frame size for XDP
290662306a36Sopenharmony_ci * @vsi: Pointer to VSI structure
290762306a36Sopenharmony_ci */
290862306a36Sopenharmony_cistatic int ice_max_xdp_frame_size(struct ice_vsi *vsi)
290962306a36Sopenharmony_ci{
291062306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_LEGACY_RX, vsi->back->flags))
291162306a36Sopenharmony_ci		return ICE_RXBUF_1664;
291262306a36Sopenharmony_ci	else
291362306a36Sopenharmony_ci		return ICE_RXBUF_3072;
291462306a36Sopenharmony_ci}
291562306a36Sopenharmony_ci
291662306a36Sopenharmony_ci/**
291762306a36Sopenharmony_ci * ice_xdp_setup_prog - Add or remove XDP eBPF program
291862306a36Sopenharmony_ci * @vsi: VSI to setup XDP for
291962306a36Sopenharmony_ci * @prog: XDP program
292062306a36Sopenharmony_ci * @extack: netlink extended ack
292162306a36Sopenharmony_ci */
292262306a36Sopenharmony_cistatic int
292362306a36Sopenharmony_ciice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog,
292462306a36Sopenharmony_ci		   struct netlink_ext_ack *extack)
292562306a36Sopenharmony_ci{
292662306a36Sopenharmony_ci	unsigned int frame_size = vsi->netdev->mtu + ICE_ETH_PKT_HDR_PAD;
292762306a36Sopenharmony_ci	bool if_running = netif_running(vsi->netdev);
292862306a36Sopenharmony_ci	int ret = 0, xdp_ring_err = 0;
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci	if (prog && !prog->aux->xdp_has_frags) {
293162306a36Sopenharmony_ci		if (frame_size > ice_max_xdp_frame_size(vsi)) {
293262306a36Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack,
293362306a36Sopenharmony_ci					   "MTU is too large for linear frames and XDP prog does not support frags");
293462306a36Sopenharmony_ci			return -EOPNOTSUPP;
293562306a36Sopenharmony_ci		}
293662306a36Sopenharmony_ci	}
293762306a36Sopenharmony_ci
293862306a36Sopenharmony_ci	/* hot swap progs and avoid toggling link */
293962306a36Sopenharmony_ci	if (ice_is_xdp_ena_vsi(vsi) == !!prog) {
294062306a36Sopenharmony_ci		ice_vsi_assign_bpf_prog(vsi, prog);
294162306a36Sopenharmony_ci		return 0;
294262306a36Sopenharmony_ci	}
294362306a36Sopenharmony_ci
294462306a36Sopenharmony_ci	/* need to stop netdev while setting up the program for Rx rings */
294562306a36Sopenharmony_ci	if (if_running && !test_and_set_bit(ICE_VSI_DOWN, vsi->state)) {
294662306a36Sopenharmony_ci		ret = ice_down(vsi);
294762306a36Sopenharmony_ci		if (ret) {
294862306a36Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Preparing device for XDP attach failed");
294962306a36Sopenharmony_ci			return ret;
295062306a36Sopenharmony_ci		}
295162306a36Sopenharmony_ci	}
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci	if (!ice_is_xdp_ena_vsi(vsi) && prog) {
295462306a36Sopenharmony_ci		xdp_ring_err = ice_vsi_determine_xdp_res(vsi);
295562306a36Sopenharmony_ci		if (xdp_ring_err) {
295662306a36Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Not enough Tx resources for XDP");
295762306a36Sopenharmony_ci		} else {
295862306a36Sopenharmony_ci			xdp_ring_err = ice_prepare_xdp_rings(vsi, prog);
295962306a36Sopenharmony_ci			if (xdp_ring_err)
296062306a36Sopenharmony_ci				NL_SET_ERR_MSG_MOD(extack, "Setting up XDP Tx resources failed");
296162306a36Sopenharmony_ci		}
296262306a36Sopenharmony_ci		xdp_features_set_redirect_target(vsi->netdev, true);
296362306a36Sopenharmony_ci		/* reallocate Rx queues that are used for zero-copy */
296462306a36Sopenharmony_ci		xdp_ring_err = ice_realloc_zc_buf(vsi, true);
296562306a36Sopenharmony_ci		if (xdp_ring_err)
296662306a36Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Setting up XDP Rx resources failed");
296762306a36Sopenharmony_ci	} else if (ice_is_xdp_ena_vsi(vsi) && !prog) {
296862306a36Sopenharmony_ci		xdp_features_clear_redirect_target(vsi->netdev);
296962306a36Sopenharmony_ci		xdp_ring_err = ice_destroy_xdp_rings(vsi);
297062306a36Sopenharmony_ci		if (xdp_ring_err)
297162306a36Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Freeing XDP Tx resources failed");
297262306a36Sopenharmony_ci		/* reallocate Rx queues that were used for zero-copy */
297362306a36Sopenharmony_ci		xdp_ring_err = ice_realloc_zc_buf(vsi, false);
297462306a36Sopenharmony_ci		if (xdp_ring_err)
297562306a36Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Freeing XDP Rx resources failed");
297662306a36Sopenharmony_ci	}
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_ci	if (if_running)
297962306a36Sopenharmony_ci		ret = ice_up(vsi);
298062306a36Sopenharmony_ci
298162306a36Sopenharmony_ci	if (!ret && prog)
298262306a36Sopenharmony_ci		ice_vsi_rx_napi_schedule(vsi);
298362306a36Sopenharmony_ci
298462306a36Sopenharmony_ci	return (ret || xdp_ring_err) ? -ENOMEM : 0;
298562306a36Sopenharmony_ci}
298662306a36Sopenharmony_ci
298762306a36Sopenharmony_ci/**
298862306a36Sopenharmony_ci * ice_xdp_safe_mode - XDP handler for safe mode
298962306a36Sopenharmony_ci * @dev: netdevice
299062306a36Sopenharmony_ci * @xdp: XDP command
299162306a36Sopenharmony_ci */
299262306a36Sopenharmony_cistatic int ice_xdp_safe_mode(struct net_device __always_unused *dev,
299362306a36Sopenharmony_ci			     struct netdev_bpf *xdp)
299462306a36Sopenharmony_ci{
299562306a36Sopenharmony_ci	NL_SET_ERR_MSG_MOD(xdp->extack,
299662306a36Sopenharmony_ci			   "Please provide working DDP firmware package in order to use XDP\n"
299762306a36Sopenharmony_ci			   "Refer to Documentation/networking/device_drivers/ethernet/intel/ice.rst");
299862306a36Sopenharmony_ci	return -EOPNOTSUPP;
299962306a36Sopenharmony_ci}
300062306a36Sopenharmony_ci
300162306a36Sopenharmony_ci/**
300262306a36Sopenharmony_ci * ice_xdp - implements XDP handler
300362306a36Sopenharmony_ci * @dev: netdevice
300462306a36Sopenharmony_ci * @xdp: XDP command
300562306a36Sopenharmony_ci */
300662306a36Sopenharmony_cistatic int ice_xdp(struct net_device *dev, struct netdev_bpf *xdp)
300762306a36Sopenharmony_ci{
300862306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(dev);
300962306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
301062306a36Sopenharmony_ci
301162306a36Sopenharmony_ci	if (vsi->type != ICE_VSI_PF) {
301262306a36Sopenharmony_ci		NL_SET_ERR_MSG_MOD(xdp->extack, "XDP can be loaded only on PF VSI");
301362306a36Sopenharmony_ci		return -EINVAL;
301462306a36Sopenharmony_ci	}
301562306a36Sopenharmony_ci
301662306a36Sopenharmony_ci	switch (xdp->command) {
301762306a36Sopenharmony_ci	case XDP_SETUP_PROG:
301862306a36Sopenharmony_ci		return ice_xdp_setup_prog(vsi, xdp->prog, xdp->extack);
301962306a36Sopenharmony_ci	case XDP_SETUP_XSK_POOL:
302062306a36Sopenharmony_ci		return ice_xsk_pool_setup(vsi, xdp->xsk.pool,
302162306a36Sopenharmony_ci					  xdp->xsk.queue_id);
302262306a36Sopenharmony_ci	default:
302362306a36Sopenharmony_ci		return -EINVAL;
302462306a36Sopenharmony_ci	}
302562306a36Sopenharmony_ci}
302662306a36Sopenharmony_ci
302762306a36Sopenharmony_ci/**
302862306a36Sopenharmony_ci * ice_ena_misc_vector - enable the non-queue interrupts
302962306a36Sopenharmony_ci * @pf: board private structure
303062306a36Sopenharmony_ci */
303162306a36Sopenharmony_cistatic void ice_ena_misc_vector(struct ice_pf *pf)
303262306a36Sopenharmony_ci{
303362306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
303462306a36Sopenharmony_ci	u32 val;
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci	/* Disable anti-spoof detection interrupt to prevent spurious event
303762306a36Sopenharmony_ci	 * interrupts during a function reset. Anti-spoof functionally is
303862306a36Sopenharmony_ci	 * still supported.
303962306a36Sopenharmony_ci	 */
304062306a36Sopenharmony_ci	val = rd32(hw, GL_MDCK_TX_TDPU);
304162306a36Sopenharmony_ci	val |= GL_MDCK_TX_TDPU_RCU_ANTISPOOF_ITR_DIS_M;
304262306a36Sopenharmony_ci	wr32(hw, GL_MDCK_TX_TDPU, val);
304362306a36Sopenharmony_ci
304462306a36Sopenharmony_ci	/* clear things first */
304562306a36Sopenharmony_ci	wr32(hw, PFINT_OICR_ENA, 0);	/* disable all */
304662306a36Sopenharmony_ci	rd32(hw, PFINT_OICR);		/* read to clear */
304762306a36Sopenharmony_ci
304862306a36Sopenharmony_ci	val = (PFINT_OICR_ECC_ERR_M |
304962306a36Sopenharmony_ci	       PFINT_OICR_MAL_DETECT_M |
305062306a36Sopenharmony_ci	       PFINT_OICR_GRST_M |
305162306a36Sopenharmony_ci	       PFINT_OICR_PCI_EXCEPTION_M |
305262306a36Sopenharmony_ci	       PFINT_OICR_VFLR_M |
305362306a36Sopenharmony_ci	       PFINT_OICR_HMC_ERR_M |
305462306a36Sopenharmony_ci	       PFINT_OICR_PE_PUSH_M |
305562306a36Sopenharmony_ci	       PFINT_OICR_PE_CRITERR_M);
305662306a36Sopenharmony_ci
305762306a36Sopenharmony_ci	wr32(hw, PFINT_OICR_ENA, val);
305862306a36Sopenharmony_ci
305962306a36Sopenharmony_ci	/* SW_ITR_IDX = 0, but don't change INTENA */
306062306a36Sopenharmony_ci	wr32(hw, GLINT_DYN_CTL(pf->oicr_irq.index),
306162306a36Sopenharmony_ci	     GLINT_DYN_CTL_SW_ITR_INDX_M | GLINT_DYN_CTL_INTENA_MSK_M);
306262306a36Sopenharmony_ci}
306362306a36Sopenharmony_ci
306462306a36Sopenharmony_ci/**
306562306a36Sopenharmony_ci * ice_misc_intr - misc interrupt handler
306662306a36Sopenharmony_ci * @irq: interrupt number
306762306a36Sopenharmony_ci * @data: pointer to a q_vector
306862306a36Sopenharmony_ci */
306962306a36Sopenharmony_cistatic irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
307062306a36Sopenharmony_ci{
307162306a36Sopenharmony_ci	struct ice_pf *pf = (struct ice_pf *)data;
307262306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
307362306a36Sopenharmony_ci	struct device *dev;
307462306a36Sopenharmony_ci	u32 oicr, ena_mask;
307562306a36Sopenharmony_ci
307662306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
307762306a36Sopenharmony_ci	set_bit(ICE_ADMINQ_EVENT_PENDING, pf->state);
307862306a36Sopenharmony_ci	set_bit(ICE_MAILBOXQ_EVENT_PENDING, pf->state);
307962306a36Sopenharmony_ci	set_bit(ICE_SIDEBANDQ_EVENT_PENDING, pf->state);
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_ci	oicr = rd32(hw, PFINT_OICR);
308262306a36Sopenharmony_ci	ena_mask = rd32(hw, PFINT_OICR_ENA);
308362306a36Sopenharmony_ci
308462306a36Sopenharmony_ci	if (oicr & PFINT_OICR_SWINT_M) {
308562306a36Sopenharmony_ci		ena_mask &= ~PFINT_OICR_SWINT_M;
308662306a36Sopenharmony_ci		pf->sw_int_count++;
308762306a36Sopenharmony_ci	}
308862306a36Sopenharmony_ci
308962306a36Sopenharmony_ci	if (oicr & PFINT_OICR_MAL_DETECT_M) {
309062306a36Sopenharmony_ci		ena_mask &= ~PFINT_OICR_MAL_DETECT_M;
309162306a36Sopenharmony_ci		set_bit(ICE_MDD_EVENT_PENDING, pf->state);
309262306a36Sopenharmony_ci	}
309362306a36Sopenharmony_ci	if (oicr & PFINT_OICR_VFLR_M) {
309462306a36Sopenharmony_ci		/* disable any further VFLR event notifications */
309562306a36Sopenharmony_ci		if (test_bit(ICE_VF_RESETS_DISABLED, pf->state)) {
309662306a36Sopenharmony_ci			u32 reg = rd32(hw, PFINT_OICR_ENA);
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci			reg &= ~PFINT_OICR_VFLR_M;
309962306a36Sopenharmony_ci			wr32(hw, PFINT_OICR_ENA, reg);
310062306a36Sopenharmony_ci		} else {
310162306a36Sopenharmony_ci			ena_mask &= ~PFINT_OICR_VFLR_M;
310262306a36Sopenharmony_ci			set_bit(ICE_VFLR_EVENT_PENDING, pf->state);
310362306a36Sopenharmony_ci		}
310462306a36Sopenharmony_ci	}
310562306a36Sopenharmony_ci
310662306a36Sopenharmony_ci	if (oicr & PFINT_OICR_GRST_M) {
310762306a36Sopenharmony_ci		u32 reset;
310862306a36Sopenharmony_ci
310962306a36Sopenharmony_ci		/* we have a reset warning */
311062306a36Sopenharmony_ci		ena_mask &= ~PFINT_OICR_GRST_M;
311162306a36Sopenharmony_ci		reset = (rd32(hw, GLGEN_RSTAT) & GLGEN_RSTAT_RESET_TYPE_M) >>
311262306a36Sopenharmony_ci			GLGEN_RSTAT_RESET_TYPE_S;
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci		if (reset == ICE_RESET_CORER)
311562306a36Sopenharmony_ci			pf->corer_count++;
311662306a36Sopenharmony_ci		else if (reset == ICE_RESET_GLOBR)
311762306a36Sopenharmony_ci			pf->globr_count++;
311862306a36Sopenharmony_ci		else if (reset == ICE_RESET_EMPR)
311962306a36Sopenharmony_ci			pf->empr_count++;
312062306a36Sopenharmony_ci		else
312162306a36Sopenharmony_ci			dev_dbg(dev, "Invalid reset type %d\n", reset);
312262306a36Sopenharmony_ci
312362306a36Sopenharmony_ci		/* If a reset cycle isn't already in progress, we set a bit in
312462306a36Sopenharmony_ci		 * pf->state so that the service task can start a reset/rebuild.
312562306a36Sopenharmony_ci		 */
312662306a36Sopenharmony_ci		if (!test_and_set_bit(ICE_RESET_OICR_RECV, pf->state)) {
312762306a36Sopenharmony_ci			if (reset == ICE_RESET_CORER)
312862306a36Sopenharmony_ci				set_bit(ICE_CORER_RECV, pf->state);
312962306a36Sopenharmony_ci			else if (reset == ICE_RESET_GLOBR)
313062306a36Sopenharmony_ci				set_bit(ICE_GLOBR_RECV, pf->state);
313162306a36Sopenharmony_ci			else
313262306a36Sopenharmony_ci				set_bit(ICE_EMPR_RECV, pf->state);
313362306a36Sopenharmony_ci
313462306a36Sopenharmony_ci			/* There are couple of different bits at play here.
313562306a36Sopenharmony_ci			 * hw->reset_ongoing indicates whether the hardware is
313662306a36Sopenharmony_ci			 * in reset. This is set to true when a reset interrupt
313762306a36Sopenharmony_ci			 * is received and set back to false after the driver
313862306a36Sopenharmony_ci			 * has determined that the hardware is out of reset.
313962306a36Sopenharmony_ci			 *
314062306a36Sopenharmony_ci			 * ICE_RESET_OICR_RECV in pf->state indicates
314162306a36Sopenharmony_ci			 * that a post reset rebuild is required before the
314262306a36Sopenharmony_ci			 * driver is operational again. This is set above.
314362306a36Sopenharmony_ci			 *
314462306a36Sopenharmony_ci			 * As this is the start of the reset/rebuild cycle, set
314562306a36Sopenharmony_ci			 * both to indicate that.
314662306a36Sopenharmony_ci			 */
314762306a36Sopenharmony_ci			hw->reset_ongoing = true;
314862306a36Sopenharmony_ci		}
314962306a36Sopenharmony_ci	}
315062306a36Sopenharmony_ci
315162306a36Sopenharmony_ci	if (oicr & PFINT_OICR_TSYN_TX_M) {
315262306a36Sopenharmony_ci		ena_mask &= ~PFINT_OICR_TSYN_TX_M;
315362306a36Sopenharmony_ci		if (!hw->reset_ongoing)
315462306a36Sopenharmony_ci			set_bit(ICE_MISC_THREAD_TX_TSTAMP, pf->misc_thread);
315562306a36Sopenharmony_ci	}
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_ci	if (oicr & PFINT_OICR_TSYN_EVNT_M) {
315862306a36Sopenharmony_ci		u8 tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
315962306a36Sopenharmony_ci		u32 gltsyn_stat = rd32(hw, GLTSYN_STAT(tmr_idx));
316062306a36Sopenharmony_ci
316162306a36Sopenharmony_ci		ena_mask &= ~PFINT_OICR_TSYN_EVNT_M;
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_ci		if (hw->func_caps.ts_func_info.src_tmr_owned) {
316462306a36Sopenharmony_ci			/* Save EVENTs from GLTSYN register */
316562306a36Sopenharmony_ci			pf->ptp.ext_ts_irq |= gltsyn_stat &
316662306a36Sopenharmony_ci					      (GLTSYN_STAT_EVENT0_M |
316762306a36Sopenharmony_ci					       GLTSYN_STAT_EVENT1_M |
316862306a36Sopenharmony_ci					       GLTSYN_STAT_EVENT2_M);
316962306a36Sopenharmony_ci
317062306a36Sopenharmony_ci			set_bit(ICE_MISC_THREAD_EXTTS_EVENT, pf->misc_thread);
317162306a36Sopenharmony_ci		}
317262306a36Sopenharmony_ci	}
317362306a36Sopenharmony_ci
317462306a36Sopenharmony_ci#define ICE_AUX_CRIT_ERR (PFINT_OICR_PE_CRITERR_M | PFINT_OICR_HMC_ERR_M | PFINT_OICR_PE_PUSH_M)
317562306a36Sopenharmony_ci	if (oicr & ICE_AUX_CRIT_ERR) {
317662306a36Sopenharmony_ci		pf->oicr_err_reg |= oicr;
317762306a36Sopenharmony_ci		set_bit(ICE_AUX_ERR_PENDING, pf->state);
317862306a36Sopenharmony_ci		ena_mask &= ~ICE_AUX_CRIT_ERR;
317962306a36Sopenharmony_ci	}
318062306a36Sopenharmony_ci
318162306a36Sopenharmony_ci	/* Report any remaining unexpected interrupts */
318262306a36Sopenharmony_ci	oicr &= ena_mask;
318362306a36Sopenharmony_ci	if (oicr) {
318462306a36Sopenharmony_ci		dev_dbg(dev, "unhandled interrupt oicr=0x%08x\n", oicr);
318562306a36Sopenharmony_ci		/* If a critical error is pending there is no choice but to
318662306a36Sopenharmony_ci		 * reset the device.
318762306a36Sopenharmony_ci		 */
318862306a36Sopenharmony_ci		if (oicr & (PFINT_OICR_PCI_EXCEPTION_M |
318962306a36Sopenharmony_ci			    PFINT_OICR_ECC_ERR_M)) {
319062306a36Sopenharmony_ci			set_bit(ICE_PFR_REQ, pf->state);
319162306a36Sopenharmony_ci		}
319262306a36Sopenharmony_ci	}
319362306a36Sopenharmony_ci
319462306a36Sopenharmony_ci	return IRQ_WAKE_THREAD;
319562306a36Sopenharmony_ci}
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ci/**
319862306a36Sopenharmony_ci * ice_misc_intr_thread_fn - misc interrupt thread function
319962306a36Sopenharmony_ci * @irq: interrupt number
320062306a36Sopenharmony_ci * @data: pointer to a q_vector
320162306a36Sopenharmony_ci */
320262306a36Sopenharmony_cistatic irqreturn_t ice_misc_intr_thread_fn(int __always_unused irq, void *data)
320362306a36Sopenharmony_ci{
320462306a36Sopenharmony_ci	struct ice_pf *pf = data;
320562306a36Sopenharmony_ci	struct ice_hw *hw;
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_ci	hw = &pf->hw;
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_ci	if (ice_is_reset_in_progress(pf->state))
321062306a36Sopenharmony_ci		return IRQ_HANDLED;
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_ci	ice_service_task_schedule(pf);
321362306a36Sopenharmony_ci
321462306a36Sopenharmony_ci	if (test_and_clear_bit(ICE_MISC_THREAD_EXTTS_EVENT, pf->misc_thread))
321562306a36Sopenharmony_ci		ice_ptp_extts_event(pf);
321662306a36Sopenharmony_ci
321762306a36Sopenharmony_ci	if (test_and_clear_bit(ICE_MISC_THREAD_TX_TSTAMP, pf->misc_thread)) {
321862306a36Sopenharmony_ci		/* Process outstanding Tx timestamps. If there is more work,
321962306a36Sopenharmony_ci		 * re-arm the interrupt to trigger again.
322062306a36Sopenharmony_ci		 */
322162306a36Sopenharmony_ci		if (ice_ptp_process_ts(pf) == ICE_TX_TSTAMP_WORK_PENDING) {
322262306a36Sopenharmony_ci			wr32(hw, PFINT_OICR, PFINT_OICR_TSYN_TX_M);
322362306a36Sopenharmony_ci			ice_flush(hw);
322462306a36Sopenharmony_ci		}
322562306a36Sopenharmony_ci	}
322662306a36Sopenharmony_ci
322762306a36Sopenharmony_ci	ice_irq_dynamic_ena(hw, NULL, NULL);
322862306a36Sopenharmony_ci
322962306a36Sopenharmony_ci	return IRQ_HANDLED;
323062306a36Sopenharmony_ci}
323162306a36Sopenharmony_ci
323262306a36Sopenharmony_ci/**
323362306a36Sopenharmony_ci * ice_dis_ctrlq_interrupts - disable control queue interrupts
323462306a36Sopenharmony_ci * @hw: pointer to HW structure
323562306a36Sopenharmony_ci */
323662306a36Sopenharmony_cistatic void ice_dis_ctrlq_interrupts(struct ice_hw *hw)
323762306a36Sopenharmony_ci{
323862306a36Sopenharmony_ci	/* disable Admin queue Interrupt causes */
323962306a36Sopenharmony_ci	wr32(hw, PFINT_FW_CTL,
324062306a36Sopenharmony_ci	     rd32(hw, PFINT_FW_CTL) & ~PFINT_FW_CTL_CAUSE_ENA_M);
324162306a36Sopenharmony_ci
324262306a36Sopenharmony_ci	/* disable Mailbox queue Interrupt causes */
324362306a36Sopenharmony_ci	wr32(hw, PFINT_MBX_CTL,
324462306a36Sopenharmony_ci	     rd32(hw, PFINT_MBX_CTL) & ~PFINT_MBX_CTL_CAUSE_ENA_M);
324562306a36Sopenharmony_ci
324662306a36Sopenharmony_ci	wr32(hw, PFINT_SB_CTL,
324762306a36Sopenharmony_ci	     rd32(hw, PFINT_SB_CTL) & ~PFINT_SB_CTL_CAUSE_ENA_M);
324862306a36Sopenharmony_ci
324962306a36Sopenharmony_ci	/* disable Control queue Interrupt causes */
325062306a36Sopenharmony_ci	wr32(hw, PFINT_OICR_CTL,
325162306a36Sopenharmony_ci	     rd32(hw, PFINT_OICR_CTL) & ~PFINT_OICR_CTL_CAUSE_ENA_M);
325262306a36Sopenharmony_ci
325362306a36Sopenharmony_ci	ice_flush(hw);
325462306a36Sopenharmony_ci}
325562306a36Sopenharmony_ci
325662306a36Sopenharmony_ci/**
325762306a36Sopenharmony_ci * ice_free_irq_msix_misc - Unroll misc vector setup
325862306a36Sopenharmony_ci * @pf: board private structure
325962306a36Sopenharmony_ci */
326062306a36Sopenharmony_cistatic void ice_free_irq_msix_misc(struct ice_pf *pf)
326162306a36Sopenharmony_ci{
326262306a36Sopenharmony_ci	int misc_irq_num = pf->oicr_irq.virq;
326362306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_ci	ice_dis_ctrlq_interrupts(hw);
326662306a36Sopenharmony_ci
326762306a36Sopenharmony_ci	/* disable OICR interrupt */
326862306a36Sopenharmony_ci	wr32(hw, PFINT_OICR_ENA, 0);
326962306a36Sopenharmony_ci	ice_flush(hw);
327062306a36Sopenharmony_ci
327162306a36Sopenharmony_ci	synchronize_irq(misc_irq_num);
327262306a36Sopenharmony_ci	devm_free_irq(ice_pf_to_dev(pf), misc_irq_num, pf);
327362306a36Sopenharmony_ci
327462306a36Sopenharmony_ci	ice_free_irq(pf, pf->oicr_irq);
327562306a36Sopenharmony_ci}
327662306a36Sopenharmony_ci
327762306a36Sopenharmony_ci/**
327862306a36Sopenharmony_ci * ice_ena_ctrlq_interrupts - enable control queue interrupts
327962306a36Sopenharmony_ci * @hw: pointer to HW structure
328062306a36Sopenharmony_ci * @reg_idx: HW vector index to associate the control queue interrupts with
328162306a36Sopenharmony_ci */
328262306a36Sopenharmony_cistatic void ice_ena_ctrlq_interrupts(struct ice_hw *hw, u16 reg_idx)
328362306a36Sopenharmony_ci{
328462306a36Sopenharmony_ci	u32 val;
328562306a36Sopenharmony_ci
328662306a36Sopenharmony_ci	val = ((reg_idx & PFINT_OICR_CTL_MSIX_INDX_M) |
328762306a36Sopenharmony_ci	       PFINT_OICR_CTL_CAUSE_ENA_M);
328862306a36Sopenharmony_ci	wr32(hw, PFINT_OICR_CTL, val);
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ci	/* enable Admin queue Interrupt causes */
329162306a36Sopenharmony_ci	val = ((reg_idx & PFINT_FW_CTL_MSIX_INDX_M) |
329262306a36Sopenharmony_ci	       PFINT_FW_CTL_CAUSE_ENA_M);
329362306a36Sopenharmony_ci	wr32(hw, PFINT_FW_CTL, val);
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	/* enable Mailbox queue Interrupt causes */
329662306a36Sopenharmony_ci	val = ((reg_idx & PFINT_MBX_CTL_MSIX_INDX_M) |
329762306a36Sopenharmony_ci	       PFINT_MBX_CTL_CAUSE_ENA_M);
329862306a36Sopenharmony_ci	wr32(hw, PFINT_MBX_CTL, val);
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_ci	/* This enables Sideband queue Interrupt causes */
330162306a36Sopenharmony_ci	val = ((reg_idx & PFINT_SB_CTL_MSIX_INDX_M) |
330262306a36Sopenharmony_ci	       PFINT_SB_CTL_CAUSE_ENA_M);
330362306a36Sopenharmony_ci	wr32(hw, PFINT_SB_CTL, val);
330462306a36Sopenharmony_ci
330562306a36Sopenharmony_ci	ice_flush(hw);
330662306a36Sopenharmony_ci}
330762306a36Sopenharmony_ci
330862306a36Sopenharmony_ci/**
330962306a36Sopenharmony_ci * ice_req_irq_msix_misc - Setup the misc vector to handle non queue events
331062306a36Sopenharmony_ci * @pf: board private structure
331162306a36Sopenharmony_ci *
331262306a36Sopenharmony_ci * This sets up the handler for MSIX 0, which is used to manage the
331362306a36Sopenharmony_ci * non-queue interrupts, e.g. AdminQ and errors. This is not used
331462306a36Sopenharmony_ci * when in MSI or Legacy interrupt mode.
331562306a36Sopenharmony_ci */
331662306a36Sopenharmony_cistatic int ice_req_irq_msix_misc(struct ice_pf *pf)
331762306a36Sopenharmony_ci{
331862306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
331962306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
332062306a36Sopenharmony_ci	struct msi_map oicr_irq;
332162306a36Sopenharmony_ci	int err = 0;
332262306a36Sopenharmony_ci
332362306a36Sopenharmony_ci	if (!pf->int_name[0])
332462306a36Sopenharmony_ci		snprintf(pf->int_name, sizeof(pf->int_name) - 1, "%s-%s:misc",
332562306a36Sopenharmony_ci			 dev_driver_string(dev), dev_name(dev));
332662306a36Sopenharmony_ci
332762306a36Sopenharmony_ci	/* Do not request IRQ but do enable OICR interrupt since settings are
332862306a36Sopenharmony_ci	 * lost during reset. Note that this function is called only during
332962306a36Sopenharmony_ci	 * rebuild path and not while reset is in progress.
333062306a36Sopenharmony_ci	 */
333162306a36Sopenharmony_ci	if (ice_is_reset_in_progress(pf->state))
333262306a36Sopenharmony_ci		goto skip_req_irq;
333362306a36Sopenharmony_ci
333462306a36Sopenharmony_ci	/* reserve one vector in irq_tracker for misc interrupts */
333562306a36Sopenharmony_ci	oicr_irq = ice_alloc_irq(pf, false);
333662306a36Sopenharmony_ci	if (oicr_irq.index < 0)
333762306a36Sopenharmony_ci		return oicr_irq.index;
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci	pf->oicr_irq = oicr_irq;
334062306a36Sopenharmony_ci	err = devm_request_threaded_irq(dev, pf->oicr_irq.virq, ice_misc_intr,
334162306a36Sopenharmony_ci					ice_misc_intr_thread_fn, 0,
334262306a36Sopenharmony_ci					pf->int_name, pf);
334362306a36Sopenharmony_ci	if (err) {
334462306a36Sopenharmony_ci		dev_err(dev, "devm_request_threaded_irq for %s failed: %d\n",
334562306a36Sopenharmony_ci			pf->int_name, err);
334662306a36Sopenharmony_ci		ice_free_irq(pf, pf->oicr_irq);
334762306a36Sopenharmony_ci		return err;
334862306a36Sopenharmony_ci	}
334962306a36Sopenharmony_ci
335062306a36Sopenharmony_ciskip_req_irq:
335162306a36Sopenharmony_ci	ice_ena_misc_vector(pf);
335262306a36Sopenharmony_ci
335362306a36Sopenharmony_ci	ice_ena_ctrlq_interrupts(hw, pf->oicr_irq.index);
335462306a36Sopenharmony_ci	wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->oicr_irq.index),
335562306a36Sopenharmony_ci	     ITR_REG_ALIGN(ICE_ITR_8K) >> ICE_ITR_GRAN_S);
335662306a36Sopenharmony_ci
335762306a36Sopenharmony_ci	ice_flush(hw);
335862306a36Sopenharmony_ci	ice_irq_dynamic_ena(hw, NULL, NULL);
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_ci	return 0;
336162306a36Sopenharmony_ci}
336262306a36Sopenharmony_ci
336362306a36Sopenharmony_ci/**
336462306a36Sopenharmony_ci * ice_napi_add - register NAPI handler for the VSI
336562306a36Sopenharmony_ci * @vsi: VSI for which NAPI handler is to be registered
336662306a36Sopenharmony_ci *
336762306a36Sopenharmony_ci * This function is only called in the driver's load path. Registering the NAPI
336862306a36Sopenharmony_ci * handler is done in ice_vsi_alloc_q_vector() for all other cases (i.e. resume,
336962306a36Sopenharmony_ci * reset/rebuild, etc.)
337062306a36Sopenharmony_ci */
337162306a36Sopenharmony_cistatic void ice_napi_add(struct ice_vsi *vsi)
337262306a36Sopenharmony_ci{
337362306a36Sopenharmony_ci	int v_idx;
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_ci	if (!vsi->netdev)
337662306a36Sopenharmony_ci		return;
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_ci	ice_for_each_q_vector(vsi, v_idx)
337962306a36Sopenharmony_ci		netif_napi_add(vsi->netdev, &vsi->q_vectors[v_idx]->napi,
338062306a36Sopenharmony_ci			       ice_napi_poll);
338162306a36Sopenharmony_ci}
338262306a36Sopenharmony_ci
338362306a36Sopenharmony_ci/**
338462306a36Sopenharmony_ci * ice_set_ops - set netdev and ethtools ops for the given netdev
338562306a36Sopenharmony_ci * @vsi: the VSI associated with the new netdev
338662306a36Sopenharmony_ci */
338762306a36Sopenharmony_cistatic void ice_set_ops(struct ice_vsi *vsi)
338862306a36Sopenharmony_ci{
338962306a36Sopenharmony_ci	struct net_device *netdev = vsi->netdev;
339062306a36Sopenharmony_ci	struct ice_pf *pf = ice_netdev_to_pf(netdev);
339162306a36Sopenharmony_ci
339262306a36Sopenharmony_ci	if (ice_is_safe_mode(pf)) {
339362306a36Sopenharmony_ci		netdev->netdev_ops = &ice_netdev_safe_mode_ops;
339462306a36Sopenharmony_ci		ice_set_ethtool_safe_mode_ops(netdev);
339562306a36Sopenharmony_ci		return;
339662306a36Sopenharmony_ci	}
339762306a36Sopenharmony_ci
339862306a36Sopenharmony_ci	netdev->netdev_ops = &ice_netdev_ops;
339962306a36Sopenharmony_ci	netdev->udp_tunnel_nic_info = &pf->hw.udp_tunnel_nic;
340062306a36Sopenharmony_ci	ice_set_ethtool_ops(netdev);
340162306a36Sopenharmony_ci
340262306a36Sopenharmony_ci	if (vsi->type != ICE_VSI_PF)
340362306a36Sopenharmony_ci		return;
340462306a36Sopenharmony_ci
340562306a36Sopenharmony_ci	netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
340662306a36Sopenharmony_ci			       NETDEV_XDP_ACT_XSK_ZEROCOPY |
340762306a36Sopenharmony_ci			       NETDEV_XDP_ACT_RX_SG;
340862306a36Sopenharmony_ci	netdev->xdp_zc_max_segs = ICE_MAX_BUF_TXD;
340962306a36Sopenharmony_ci}
341062306a36Sopenharmony_ci
341162306a36Sopenharmony_ci/**
341262306a36Sopenharmony_ci * ice_set_netdev_features - set features for the given netdev
341362306a36Sopenharmony_ci * @netdev: netdev instance
341462306a36Sopenharmony_ci */
341562306a36Sopenharmony_cistatic void ice_set_netdev_features(struct net_device *netdev)
341662306a36Sopenharmony_ci{
341762306a36Sopenharmony_ci	struct ice_pf *pf = ice_netdev_to_pf(netdev);
341862306a36Sopenharmony_ci	bool is_dvm_ena = ice_is_dvm_ena(&pf->hw);
341962306a36Sopenharmony_ci	netdev_features_t csumo_features;
342062306a36Sopenharmony_ci	netdev_features_t vlano_features;
342162306a36Sopenharmony_ci	netdev_features_t dflt_features;
342262306a36Sopenharmony_ci	netdev_features_t tso_features;
342362306a36Sopenharmony_ci
342462306a36Sopenharmony_ci	if (ice_is_safe_mode(pf)) {
342562306a36Sopenharmony_ci		/* safe mode */
342662306a36Sopenharmony_ci		netdev->features = NETIF_F_SG | NETIF_F_HIGHDMA;
342762306a36Sopenharmony_ci		netdev->hw_features = netdev->features;
342862306a36Sopenharmony_ci		return;
342962306a36Sopenharmony_ci	}
343062306a36Sopenharmony_ci
343162306a36Sopenharmony_ci	dflt_features = NETIF_F_SG	|
343262306a36Sopenharmony_ci			NETIF_F_HIGHDMA	|
343362306a36Sopenharmony_ci			NETIF_F_NTUPLE	|
343462306a36Sopenharmony_ci			NETIF_F_RXHASH;
343562306a36Sopenharmony_ci
343662306a36Sopenharmony_ci	csumo_features = NETIF_F_RXCSUM	  |
343762306a36Sopenharmony_ci			 NETIF_F_IP_CSUM  |
343862306a36Sopenharmony_ci			 NETIF_F_SCTP_CRC |
343962306a36Sopenharmony_ci			 NETIF_F_IPV6_CSUM;
344062306a36Sopenharmony_ci
344162306a36Sopenharmony_ci	vlano_features = NETIF_F_HW_VLAN_CTAG_FILTER |
344262306a36Sopenharmony_ci			 NETIF_F_HW_VLAN_CTAG_TX     |
344362306a36Sopenharmony_ci			 NETIF_F_HW_VLAN_CTAG_RX;
344462306a36Sopenharmony_ci
344562306a36Sopenharmony_ci	/* Enable CTAG/STAG filtering by default in Double VLAN Mode (DVM) */
344662306a36Sopenharmony_ci	if (is_dvm_ena)
344762306a36Sopenharmony_ci		vlano_features |= NETIF_F_HW_VLAN_STAG_FILTER;
344862306a36Sopenharmony_ci
344962306a36Sopenharmony_ci	tso_features = NETIF_F_TSO			|
345062306a36Sopenharmony_ci		       NETIF_F_TSO_ECN			|
345162306a36Sopenharmony_ci		       NETIF_F_TSO6			|
345262306a36Sopenharmony_ci		       NETIF_F_GSO_GRE			|
345362306a36Sopenharmony_ci		       NETIF_F_GSO_UDP_TUNNEL		|
345462306a36Sopenharmony_ci		       NETIF_F_GSO_GRE_CSUM		|
345562306a36Sopenharmony_ci		       NETIF_F_GSO_UDP_TUNNEL_CSUM	|
345662306a36Sopenharmony_ci		       NETIF_F_GSO_PARTIAL		|
345762306a36Sopenharmony_ci		       NETIF_F_GSO_IPXIP4		|
345862306a36Sopenharmony_ci		       NETIF_F_GSO_IPXIP6		|
345962306a36Sopenharmony_ci		       NETIF_F_GSO_UDP_L4;
346062306a36Sopenharmony_ci
346162306a36Sopenharmony_ci	netdev->gso_partial_features |= NETIF_F_GSO_UDP_TUNNEL_CSUM |
346262306a36Sopenharmony_ci					NETIF_F_GSO_GRE_CSUM;
346362306a36Sopenharmony_ci	/* set features that user can change */
346462306a36Sopenharmony_ci	netdev->hw_features = dflt_features | csumo_features |
346562306a36Sopenharmony_ci			      vlano_features | tso_features;
346662306a36Sopenharmony_ci
346762306a36Sopenharmony_ci	/* add support for HW_CSUM on packets with MPLS header */
346862306a36Sopenharmony_ci	netdev->mpls_features =  NETIF_F_HW_CSUM |
346962306a36Sopenharmony_ci				 NETIF_F_TSO     |
347062306a36Sopenharmony_ci				 NETIF_F_TSO6;
347162306a36Sopenharmony_ci
347262306a36Sopenharmony_ci	/* enable features */
347362306a36Sopenharmony_ci	netdev->features |= netdev->hw_features;
347462306a36Sopenharmony_ci
347562306a36Sopenharmony_ci	netdev->hw_features |= NETIF_F_HW_TC;
347662306a36Sopenharmony_ci	netdev->hw_features |= NETIF_F_LOOPBACK;
347762306a36Sopenharmony_ci
347862306a36Sopenharmony_ci	/* encap and VLAN devices inherit default, csumo and tso features */
347962306a36Sopenharmony_ci	netdev->hw_enc_features |= dflt_features | csumo_features |
348062306a36Sopenharmony_ci				   tso_features;
348162306a36Sopenharmony_ci	netdev->vlan_features |= dflt_features | csumo_features |
348262306a36Sopenharmony_ci				 tso_features;
348362306a36Sopenharmony_ci
348462306a36Sopenharmony_ci	/* advertise support but don't enable by default since only one type of
348562306a36Sopenharmony_ci	 * VLAN offload can be enabled at a time (i.e. CTAG or STAG). When one
348662306a36Sopenharmony_ci	 * type turns on the other has to be turned off. This is enforced by the
348762306a36Sopenharmony_ci	 * ice_fix_features() ndo callback.
348862306a36Sopenharmony_ci	 */
348962306a36Sopenharmony_ci	if (is_dvm_ena)
349062306a36Sopenharmony_ci		netdev->hw_features |= NETIF_F_HW_VLAN_STAG_RX |
349162306a36Sopenharmony_ci			NETIF_F_HW_VLAN_STAG_TX;
349262306a36Sopenharmony_ci
349362306a36Sopenharmony_ci	/* Leave CRC / FCS stripping enabled by default, but allow the value to
349462306a36Sopenharmony_ci	 * be changed at runtime
349562306a36Sopenharmony_ci	 */
349662306a36Sopenharmony_ci	netdev->hw_features |= NETIF_F_RXFCS;
349762306a36Sopenharmony_ci
349862306a36Sopenharmony_ci	netif_set_tso_max_size(netdev, ICE_MAX_TSO_SIZE);
349962306a36Sopenharmony_ci}
350062306a36Sopenharmony_ci
350162306a36Sopenharmony_ci/**
350262306a36Sopenharmony_ci * ice_fill_rss_lut - Fill the RSS lookup table with default values
350362306a36Sopenharmony_ci * @lut: Lookup table
350462306a36Sopenharmony_ci * @rss_table_size: Lookup table size
350562306a36Sopenharmony_ci * @rss_size: Range of queue number for hashing
350662306a36Sopenharmony_ci */
350762306a36Sopenharmony_civoid ice_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size)
350862306a36Sopenharmony_ci{
350962306a36Sopenharmony_ci	u16 i;
351062306a36Sopenharmony_ci
351162306a36Sopenharmony_ci	for (i = 0; i < rss_table_size; i++)
351262306a36Sopenharmony_ci		lut[i] = i % rss_size;
351362306a36Sopenharmony_ci}
351462306a36Sopenharmony_ci
351562306a36Sopenharmony_ci/**
351662306a36Sopenharmony_ci * ice_pf_vsi_setup - Set up a PF VSI
351762306a36Sopenharmony_ci * @pf: board private structure
351862306a36Sopenharmony_ci * @pi: pointer to the port_info instance
351962306a36Sopenharmony_ci *
352062306a36Sopenharmony_ci * Returns pointer to the successfully allocated VSI software struct
352162306a36Sopenharmony_ci * on success, otherwise returns NULL on failure.
352262306a36Sopenharmony_ci */
352362306a36Sopenharmony_cistatic struct ice_vsi *
352462306a36Sopenharmony_ciice_pf_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi)
352562306a36Sopenharmony_ci{
352662306a36Sopenharmony_ci	struct ice_vsi_cfg_params params = {};
352762306a36Sopenharmony_ci
352862306a36Sopenharmony_ci	params.type = ICE_VSI_PF;
352962306a36Sopenharmony_ci	params.pi = pi;
353062306a36Sopenharmony_ci	params.flags = ICE_VSI_FLAG_INIT;
353162306a36Sopenharmony_ci
353262306a36Sopenharmony_ci	return ice_vsi_setup(pf, &params);
353362306a36Sopenharmony_ci}
353462306a36Sopenharmony_ci
353562306a36Sopenharmony_cistatic struct ice_vsi *
353662306a36Sopenharmony_ciice_chnl_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi,
353762306a36Sopenharmony_ci		   struct ice_channel *ch)
353862306a36Sopenharmony_ci{
353962306a36Sopenharmony_ci	struct ice_vsi_cfg_params params = {};
354062306a36Sopenharmony_ci
354162306a36Sopenharmony_ci	params.type = ICE_VSI_CHNL;
354262306a36Sopenharmony_ci	params.pi = pi;
354362306a36Sopenharmony_ci	params.ch = ch;
354462306a36Sopenharmony_ci	params.flags = ICE_VSI_FLAG_INIT;
354562306a36Sopenharmony_ci
354662306a36Sopenharmony_ci	return ice_vsi_setup(pf, &params);
354762306a36Sopenharmony_ci}
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_ci/**
355062306a36Sopenharmony_ci * ice_ctrl_vsi_setup - Set up a control VSI
355162306a36Sopenharmony_ci * @pf: board private structure
355262306a36Sopenharmony_ci * @pi: pointer to the port_info instance
355362306a36Sopenharmony_ci *
355462306a36Sopenharmony_ci * Returns pointer to the successfully allocated VSI software struct
355562306a36Sopenharmony_ci * on success, otherwise returns NULL on failure.
355662306a36Sopenharmony_ci */
355762306a36Sopenharmony_cistatic struct ice_vsi *
355862306a36Sopenharmony_ciice_ctrl_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi)
355962306a36Sopenharmony_ci{
356062306a36Sopenharmony_ci	struct ice_vsi_cfg_params params = {};
356162306a36Sopenharmony_ci
356262306a36Sopenharmony_ci	params.type = ICE_VSI_CTRL;
356362306a36Sopenharmony_ci	params.pi = pi;
356462306a36Sopenharmony_ci	params.flags = ICE_VSI_FLAG_INIT;
356562306a36Sopenharmony_ci
356662306a36Sopenharmony_ci	return ice_vsi_setup(pf, &params);
356762306a36Sopenharmony_ci}
356862306a36Sopenharmony_ci
356962306a36Sopenharmony_ci/**
357062306a36Sopenharmony_ci * ice_lb_vsi_setup - Set up a loopback VSI
357162306a36Sopenharmony_ci * @pf: board private structure
357262306a36Sopenharmony_ci * @pi: pointer to the port_info instance
357362306a36Sopenharmony_ci *
357462306a36Sopenharmony_ci * Returns pointer to the successfully allocated VSI software struct
357562306a36Sopenharmony_ci * on success, otherwise returns NULL on failure.
357662306a36Sopenharmony_ci */
357762306a36Sopenharmony_cistruct ice_vsi *
357862306a36Sopenharmony_ciice_lb_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi)
357962306a36Sopenharmony_ci{
358062306a36Sopenharmony_ci	struct ice_vsi_cfg_params params = {};
358162306a36Sopenharmony_ci
358262306a36Sopenharmony_ci	params.type = ICE_VSI_LB;
358362306a36Sopenharmony_ci	params.pi = pi;
358462306a36Sopenharmony_ci	params.flags = ICE_VSI_FLAG_INIT;
358562306a36Sopenharmony_ci
358662306a36Sopenharmony_ci	return ice_vsi_setup(pf, &params);
358762306a36Sopenharmony_ci}
358862306a36Sopenharmony_ci
358962306a36Sopenharmony_ci/**
359062306a36Sopenharmony_ci * ice_vlan_rx_add_vid - Add a VLAN ID filter to HW offload
359162306a36Sopenharmony_ci * @netdev: network interface to be adjusted
359262306a36Sopenharmony_ci * @proto: VLAN TPID
359362306a36Sopenharmony_ci * @vid: VLAN ID to be added
359462306a36Sopenharmony_ci *
359562306a36Sopenharmony_ci * net_device_ops implementation for adding VLAN IDs
359662306a36Sopenharmony_ci */
359762306a36Sopenharmony_cistatic int
359862306a36Sopenharmony_ciice_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
359962306a36Sopenharmony_ci{
360062306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
360162306a36Sopenharmony_ci	struct ice_vsi_vlan_ops *vlan_ops;
360262306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
360362306a36Sopenharmony_ci	struct ice_vlan vlan;
360462306a36Sopenharmony_ci	int ret;
360562306a36Sopenharmony_ci
360662306a36Sopenharmony_ci	/* VLAN 0 is added by default during load/reset */
360762306a36Sopenharmony_ci	if (!vid)
360862306a36Sopenharmony_ci		return 0;
360962306a36Sopenharmony_ci
361062306a36Sopenharmony_ci	while (test_and_set_bit(ICE_CFG_BUSY, vsi->state))
361162306a36Sopenharmony_ci		usleep_range(1000, 2000);
361262306a36Sopenharmony_ci
361362306a36Sopenharmony_ci	/* Add multicast promisc rule for the VLAN ID to be added if
361462306a36Sopenharmony_ci	 * all-multicast is currently enabled.
361562306a36Sopenharmony_ci	 */
361662306a36Sopenharmony_ci	if (vsi->current_netdev_flags & IFF_ALLMULTI) {
361762306a36Sopenharmony_ci		ret = ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx,
361862306a36Sopenharmony_ci					       ICE_MCAST_VLAN_PROMISC_BITS,
361962306a36Sopenharmony_ci					       vid);
362062306a36Sopenharmony_ci		if (ret)
362162306a36Sopenharmony_ci			goto finish;
362262306a36Sopenharmony_ci	}
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ci	vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
362562306a36Sopenharmony_ci
362662306a36Sopenharmony_ci	/* Add a switch rule for this VLAN ID so its corresponding VLAN tagged
362762306a36Sopenharmony_ci	 * packets aren't pruned by the device's internal switch on Rx
362862306a36Sopenharmony_ci	 */
362962306a36Sopenharmony_ci	vlan = ICE_VLAN(be16_to_cpu(proto), vid, 0);
363062306a36Sopenharmony_ci	ret = vlan_ops->add_vlan(vsi, &vlan);
363162306a36Sopenharmony_ci	if (ret)
363262306a36Sopenharmony_ci		goto finish;
363362306a36Sopenharmony_ci
363462306a36Sopenharmony_ci	/* If all-multicast is currently enabled and this VLAN ID is only one
363562306a36Sopenharmony_ci	 * besides VLAN-0 we have to update look-up type of multicast promisc
363662306a36Sopenharmony_ci	 * rule for VLAN-0 from ICE_SW_LKUP_PROMISC to ICE_SW_LKUP_PROMISC_VLAN.
363762306a36Sopenharmony_ci	 */
363862306a36Sopenharmony_ci	if ((vsi->current_netdev_flags & IFF_ALLMULTI) &&
363962306a36Sopenharmony_ci	    ice_vsi_num_non_zero_vlans(vsi) == 1) {
364062306a36Sopenharmony_ci		ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx,
364162306a36Sopenharmony_ci					   ICE_MCAST_PROMISC_BITS, 0);
364262306a36Sopenharmony_ci		ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx,
364362306a36Sopenharmony_ci					 ICE_MCAST_VLAN_PROMISC_BITS, 0);
364462306a36Sopenharmony_ci	}
364562306a36Sopenharmony_ci
364662306a36Sopenharmony_cifinish:
364762306a36Sopenharmony_ci	clear_bit(ICE_CFG_BUSY, vsi->state);
364862306a36Sopenharmony_ci
364962306a36Sopenharmony_ci	return ret;
365062306a36Sopenharmony_ci}
365162306a36Sopenharmony_ci
365262306a36Sopenharmony_ci/**
365362306a36Sopenharmony_ci * ice_vlan_rx_kill_vid - Remove a VLAN ID filter from HW offload
365462306a36Sopenharmony_ci * @netdev: network interface to be adjusted
365562306a36Sopenharmony_ci * @proto: VLAN TPID
365662306a36Sopenharmony_ci * @vid: VLAN ID to be removed
365762306a36Sopenharmony_ci *
365862306a36Sopenharmony_ci * net_device_ops implementation for removing VLAN IDs
365962306a36Sopenharmony_ci */
366062306a36Sopenharmony_cistatic int
366162306a36Sopenharmony_ciice_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
366262306a36Sopenharmony_ci{
366362306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
366462306a36Sopenharmony_ci	struct ice_vsi_vlan_ops *vlan_ops;
366562306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
366662306a36Sopenharmony_ci	struct ice_vlan vlan;
366762306a36Sopenharmony_ci	int ret;
366862306a36Sopenharmony_ci
366962306a36Sopenharmony_ci	/* don't allow removal of VLAN 0 */
367062306a36Sopenharmony_ci	if (!vid)
367162306a36Sopenharmony_ci		return 0;
367262306a36Sopenharmony_ci
367362306a36Sopenharmony_ci	while (test_and_set_bit(ICE_CFG_BUSY, vsi->state))
367462306a36Sopenharmony_ci		usleep_range(1000, 2000);
367562306a36Sopenharmony_ci
367662306a36Sopenharmony_ci	ret = ice_clear_vsi_promisc(&vsi->back->hw, vsi->idx,
367762306a36Sopenharmony_ci				    ICE_MCAST_VLAN_PROMISC_BITS, vid);
367862306a36Sopenharmony_ci	if (ret) {
367962306a36Sopenharmony_ci		netdev_err(netdev, "Error clearing multicast promiscuous mode on VSI %i\n",
368062306a36Sopenharmony_ci			   vsi->vsi_num);
368162306a36Sopenharmony_ci		vsi->current_netdev_flags |= IFF_ALLMULTI;
368262306a36Sopenharmony_ci	}
368362306a36Sopenharmony_ci
368462306a36Sopenharmony_ci	vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
368562306a36Sopenharmony_ci
368662306a36Sopenharmony_ci	/* Make sure VLAN delete is successful before updating VLAN
368762306a36Sopenharmony_ci	 * information
368862306a36Sopenharmony_ci	 */
368962306a36Sopenharmony_ci	vlan = ICE_VLAN(be16_to_cpu(proto), vid, 0);
369062306a36Sopenharmony_ci	ret = vlan_ops->del_vlan(vsi, &vlan);
369162306a36Sopenharmony_ci	if (ret)
369262306a36Sopenharmony_ci		goto finish;
369362306a36Sopenharmony_ci
369462306a36Sopenharmony_ci	/* Remove multicast promisc rule for the removed VLAN ID if
369562306a36Sopenharmony_ci	 * all-multicast is enabled.
369662306a36Sopenharmony_ci	 */
369762306a36Sopenharmony_ci	if (vsi->current_netdev_flags & IFF_ALLMULTI)
369862306a36Sopenharmony_ci		ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx,
369962306a36Sopenharmony_ci					   ICE_MCAST_VLAN_PROMISC_BITS, vid);
370062306a36Sopenharmony_ci
370162306a36Sopenharmony_ci	if (!ice_vsi_has_non_zero_vlans(vsi)) {
370262306a36Sopenharmony_ci		/* Update look-up type of multicast promisc rule for VLAN 0
370362306a36Sopenharmony_ci		 * from ICE_SW_LKUP_PROMISC_VLAN to ICE_SW_LKUP_PROMISC when
370462306a36Sopenharmony_ci		 * all-multicast is enabled and VLAN 0 is the only VLAN rule.
370562306a36Sopenharmony_ci		 */
370662306a36Sopenharmony_ci		if (vsi->current_netdev_flags & IFF_ALLMULTI) {
370762306a36Sopenharmony_ci			ice_fltr_clear_vsi_promisc(&vsi->back->hw, vsi->idx,
370862306a36Sopenharmony_ci						   ICE_MCAST_VLAN_PROMISC_BITS,
370962306a36Sopenharmony_ci						   0);
371062306a36Sopenharmony_ci			ice_fltr_set_vsi_promisc(&vsi->back->hw, vsi->idx,
371162306a36Sopenharmony_ci						 ICE_MCAST_PROMISC_BITS, 0);
371262306a36Sopenharmony_ci		}
371362306a36Sopenharmony_ci	}
371462306a36Sopenharmony_ci
371562306a36Sopenharmony_cifinish:
371662306a36Sopenharmony_ci	clear_bit(ICE_CFG_BUSY, vsi->state);
371762306a36Sopenharmony_ci
371862306a36Sopenharmony_ci	return ret;
371962306a36Sopenharmony_ci}
372062306a36Sopenharmony_ci
372162306a36Sopenharmony_ci/**
372262306a36Sopenharmony_ci * ice_rep_indr_tc_block_unbind
372362306a36Sopenharmony_ci * @cb_priv: indirection block private data
372462306a36Sopenharmony_ci */
372562306a36Sopenharmony_cistatic void ice_rep_indr_tc_block_unbind(void *cb_priv)
372662306a36Sopenharmony_ci{
372762306a36Sopenharmony_ci	struct ice_indr_block_priv *indr_priv = cb_priv;
372862306a36Sopenharmony_ci
372962306a36Sopenharmony_ci	list_del(&indr_priv->list);
373062306a36Sopenharmony_ci	kfree(indr_priv);
373162306a36Sopenharmony_ci}
373262306a36Sopenharmony_ci
373362306a36Sopenharmony_ci/**
373462306a36Sopenharmony_ci * ice_tc_indir_block_unregister - Unregister TC indirect block notifications
373562306a36Sopenharmony_ci * @vsi: VSI struct which has the netdev
373662306a36Sopenharmony_ci */
373762306a36Sopenharmony_cistatic void ice_tc_indir_block_unregister(struct ice_vsi *vsi)
373862306a36Sopenharmony_ci{
373962306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(vsi->netdev);
374062306a36Sopenharmony_ci
374162306a36Sopenharmony_ci	flow_indr_dev_unregister(ice_indr_setup_tc_cb, np,
374262306a36Sopenharmony_ci				 ice_rep_indr_tc_block_unbind);
374362306a36Sopenharmony_ci}
374462306a36Sopenharmony_ci
374562306a36Sopenharmony_ci/**
374662306a36Sopenharmony_ci * ice_tc_indir_block_register - Register TC indirect block notifications
374762306a36Sopenharmony_ci * @vsi: VSI struct which has the netdev
374862306a36Sopenharmony_ci *
374962306a36Sopenharmony_ci * Returns 0 on success, negative value on failure
375062306a36Sopenharmony_ci */
375162306a36Sopenharmony_cistatic int ice_tc_indir_block_register(struct ice_vsi *vsi)
375262306a36Sopenharmony_ci{
375362306a36Sopenharmony_ci	struct ice_netdev_priv *np;
375462306a36Sopenharmony_ci
375562306a36Sopenharmony_ci	if (!vsi || !vsi->netdev)
375662306a36Sopenharmony_ci		return -EINVAL;
375762306a36Sopenharmony_ci
375862306a36Sopenharmony_ci	np = netdev_priv(vsi->netdev);
375962306a36Sopenharmony_ci
376062306a36Sopenharmony_ci	INIT_LIST_HEAD(&np->tc_indr_block_priv_list);
376162306a36Sopenharmony_ci	return flow_indr_dev_register(ice_indr_setup_tc_cb, np);
376262306a36Sopenharmony_ci}
376362306a36Sopenharmony_ci
376462306a36Sopenharmony_ci/**
376562306a36Sopenharmony_ci * ice_get_avail_q_count - Get count of queues in use
376662306a36Sopenharmony_ci * @pf_qmap: bitmap to get queue use count from
376762306a36Sopenharmony_ci * @lock: pointer to a mutex that protects access to pf_qmap
376862306a36Sopenharmony_ci * @size: size of the bitmap
376962306a36Sopenharmony_ci */
377062306a36Sopenharmony_cistatic u16
377162306a36Sopenharmony_ciice_get_avail_q_count(unsigned long *pf_qmap, struct mutex *lock, u16 size)
377262306a36Sopenharmony_ci{
377362306a36Sopenharmony_ci	unsigned long bit;
377462306a36Sopenharmony_ci	u16 count = 0;
377562306a36Sopenharmony_ci
377662306a36Sopenharmony_ci	mutex_lock(lock);
377762306a36Sopenharmony_ci	for_each_clear_bit(bit, pf_qmap, size)
377862306a36Sopenharmony_ci		count++;
377962306a36Sopenharmony_ci	mutex_unlock(lock);
378062306a36Sopenharmony_ci
378162306a36Sopenharmony_ci	return count;
378262306a36Sopenharmony_ci}
378362306a36Sopenharmony_ci
378462306a36Sopenharmony_ci/**
378562306a36Sopenharmony_ci * ice_get_avail_txq_count - Get count of Tx queues in use
378662306a36Sopenharmony_ci * @pf: pointer to an ice_pf instance
378762306a36Sopenharmony_ci */
378862306a36Sopenharmony_ciu16 ice_get_avail_txq_count(struct ice_pf *pf)
378962306a36Sopenharmony_ci{
379062306a36Sopenharmony_ci	return ice_get_avail_q_count(pf->avail_txqs, &pf->avail_q_mutex,
379162306a36Sopenharmony_ci				     pf->max_pf_txqs);
379262306a36Sopenharmony_ci}
379362306a36Sopenharmony_ci
379462306a36Sopenharmony_ci/**
379562306a36Sopenharmony_ci * ice_get_avail_rxq_count - Get count of Rx queues in use
379662306a36Sopenharmony_ci * @pf: pointer to an ice_pf instance
379762306a36Sopenharmony_ci */
379862306a36Sopenharmony_ciu16 ice_get_avail_rxq_count(struct ice_pf *pf)
379962306a36Sopenharmony_ci{
380062306a36Sopenharmony_ci	return ice_get_avail_q_count(pf->avail_rxqs, &pf->avail_q_mutex,
380162306a36Sopenharmony_ci				     pf->max_pf_rxqs);
380262306a36Sopenharmony_ci}
380362306a36Sopenharmony_ci
380462306a36Sopenharmony_ci/**
380562306a36Sopenharmony_ci * ice_deinit_pf - Unrolls initialziations done by ice_init_pf
380662306a36Sopenharmony_ci * @pf: board private structure to initialize
380762306a36Sopenharmony_ci */
380862306a36Sopenharmony_cistatic void ice_deinit_pf(struct ice_pf *pf)
380962306a36Sopenharmony_ci{
381062306a36Sopenharmony_ci	ice_service_task_stop(pf);
381162306a36Sopenharmony_ci	mutex_destroy(&pf->lag_mutex);
381262306a36Sopenharmony_ci	mutex_destroy(&pf->adev_mutex);
381362306a36Sopenharmony_ci	mutex_destroy(&pf->sw_mutex);
381462306a36Sopenharmony_ci	mutex_destroy(&pf->tc_mutex);
381562306a36Sopenharmony_ci	mutex_destroy(&pf->avail_q_mutex);
381662306a36Sopenharmony_ci	mutex_destroy(&pf->vfs.table_lock);
381762306a36Sopenharmony_ci
381862306a36Sopenharmony_ci	if (pf->avail_txqs) {
381962306a36Sopenharmony_ci		bitmap_free(pf->avail_txqs);
382062306a36Sopenharmony_ci		pf->avail_txqs = NULL;
382162306a36Sopenharmony_ci	}
382262306a36Sopenharmony_ci
382362306a36Sopenharmony_ci	if (pf->avail_rxqs) {
382462306a36Sopenharmony_ci		bitmap_free(pf->avail_rxqs);
382562306a36Sopenharmony_ci		pf->avail_rxqs = NULL;
382662306a36Sopenharmony_ci	}
382762306a36Sopenharmony_ci
382862306a36Sopenharmony_ci	if (pf->ptp.clock)
382962306a36Sopenharmony_ci		ptp_clock_unregister(pf->ptp.clock);
383062306a36Sopenharmony_ci}
383162306a36Sopenharmony_ci
383262306a36Sopenharmony_ci/**
383362306a36Sopenharmony_ci * ice_set_pf_caps - set PFs capability flags
383462306a36Sopenharmony_ci * @pf: pointer to the PF instance
383562306a36Sopenharmony_ci */
383662306a36Sopenharmony_cistatic void ice_set_pf_caps(struct ice_pf *pf)
383762306a36Sopenharmony_ci{
383862306a36Sopenharmony_ci	struct ice_hw_func_caps *func_caps = &pf->hw.func_caps;
383962306a36Sopenharmony_ci
384062306a36Sopenharmony_ci	clear_bit(ICE_FLAG_RDMA_ENA, pf->flags);
384162306a36Sopenharmony_ci	if (func_caps->common_cap.rdma)
384262306a36Sopenharmony_ci		set_bit(ICE_FLAG_RDMA_ENA, pf->flags);
384362306a36Sopenharmony_ci	clear_bit(ICE_FLAG_DCB_CAPABLE, pf->flags);
384462306a36Sopenharmony_ci	if (func_caps->common_cap.dcb)
384562306a36Sopenharmony_ci		set_bit(ICE_FLAG_DCB_CAPABLE, pf->flags);
384662306a36Sopenharmony_ci	clear_bit(ICE_FLAG_SRIOV_CAPABLE, pf->flags);
384762306a36Sopenharmony_ci	if (func_caps->common_cap.sr_iov_1_1) {
384862306a36Sopenharmony_ci		set_bit(ICE_FLAG_SRIOV_CAPABLE, pf->flags);
384962306a36Sopenharmony_ci		pf->vfs.num_supported = min_t(int, func_caps->num_allocd_vfs,
385062306a36Sopenharmony_ci					      ICE_MAX_SRIOV_VFS);
385162306a36Sopenharmony_ci	}
385262306a36Sopenharmony_ci	clear_bit(ICE_FLAG_RSS_ENA, pf->flags);
385362306a36Sopenharmony_ci	if (func_caps->common_cap.rss_table_size)
385462306a36Sopenharmony_ci		set_bit(ICE_FLAG_RSS_ENA, pf->flags);
385562306a36Sopenharmony_ci
385662306a36Sopenharmony_ci	clear_bit(ICE_FLAG_FD_ENA, pf->flags);
385762306a36Sopenharmony_ci	if (func_caps->fd_fltr_guar > 0 || func_caps->fd_fltr_best_effort > 0) {
385862306a36Sopenharmony_ci		u16 unused;
385962306a36Sopenharmony_ci
386062306a36Sopenharmony_ci		/* ctrl_vsi_idx will be set to a valid value when flow director
386162306a36Sopenharmony_ci		 * is setup by ice_init_fdir
386262306a36Sopenharmony_ci		 */
386362306a36Sopenharmony_ci		pf->ctrl_vsi_idx = ICE_NO_VSI;
386462306a36Sopenharmony_ci		set_bit(ICE_FLAG_FD_ENA, pf->flags);
386562306a36Sopenharmony_ci		/* force guaranteed filter pool for PF */
386662306a36Sopenharmony_ci		ice_alloc_fd_guar_item(&pf->hw, &unused,
386762306a36Sopenharmony_ci				       func_caps->fd_fltr_guar);
386862306a36Sopenharmony_ci		/* force shared filter pool for PF */
386962306a36Sopenharmony_ci		ice_alloc_fd_shrd_item(&pf->hw, &unused,
387062306a36Sopenharmony_ci				       func_caps->fd_fltr_best_effort);
387162306a36Sopenharmony_ci	}
387262306a36Sopenharmony_ci
387362306a36Sopenharmony_ci	clear_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags);
387462306a36Sopenharmony_ci	if (func_caps->common_cap.ieee_1588)
387562306a36Sopenharmony_ci		set_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags);
387662306a36Sopenharmony_ci
387762306a36Sopenharmony_ci	pf->max_pf_txqs = func_caps->common_cap.num_txq;
387862306a36Sopenharmony_ci	pf->max_pf_rxqs = func_caps->common_cap.num_rxq;
387962306a36Sopenharmony_ci}
388062306a36Sopenharmony_ci
388162306a36Sopenharmony_ci/**
388262306a36Sopenharmony_ci * ice_init_pf - Initialize general software structures (struct ice_pf)
388362306a36Sopenharmony_ci * @pf: board private structure to initialize
388462306a36Sopenharmony_ci */
388562306a36Sopenharmony_cistatic int ice_init_pf(struct ice_pf *pf)
388662306a36Sopenharmony_ci{
388762306a36Sopenharmony_ci	ice_set_pf_caps(pf);
388862306a36Sopenharmony_ci
388962306a36Sopenharmony_ci	mutex_init(&pf->sw_mutex);
389062306a36Sopenharmony_ci	mutex_init(&pf->tc_mutex);
389162306a36Sopenharmony_ci	mutex_init(&pf->adev_mutex);
389262306a36Sopenharmony_ci	mutex_init(&pf->lag_mutex);
389362306a36Sopenharmony_ci
389462306a36Sopenharmony_ci	INIT_HLIST_HEAD(&pf->aq_wait_list);
389562306a36Sopenharmony_ci	spin_lock_init(&pf->aq_wait_lock);
389662306a36Sopenharmony_ci	init_waitqueue_head(&pf->aq_wait_queue);
389762306a36Sopenharmony_ci
389862306a36Sopenharmony_ci	init_waitqueue_head(&pf->reset_wait_queue);
389962306a36Sopenharmony_ci
390062306a36Sopenharmony_ci	/* setup service timer and periodic service task */
390162306a36Sopenharmony_ci	timer_setup(&pf->serv_tmr, ice_service_timer, 0);
390262306a36Sopenharmony_ci	pf->serv_tmr_period = HZ;
390362306a36Sopenharmony_ci	INIT_WORK(&pf->serv_task, ice_service_task);
390462306a36Sopenharmony_ci	clear_bit(ICE_SERVICE_SCHED, pf->state);
390562306a36Sopenharmony_ci
390662306a36Sopenharmony_ci	mutex_init(&pf->avail_q_mutex);
390762306a36Sopenharmony_ci	pf->avail_txqs = bitmap_zalloc(pf->max_pf_txqs, GFP_KERNEL);
390862306a36Sopenharmony_ci	if (!pf->avail_txqs)
390962306a36Sopenharmony_ci		return -ENOMEM;
391062306a36Sopenharmony_ci
391162306a36Sopenharmony_ci	pf->avail_rxqs = bitmap_zalloc(pf->max_pf_rxqs, GFP_KERNEL);
391262306a36Sopenharmony_ci	if (!pf->avail_rxqs) {
391362306a36Sopenharmony_ci		bitmap_free(pf->avail_txqs);
391462306a36Sopenharmony_ci		pf->avail_txqs = NULL;
391562306a36Sopenharmony_ci		return -ENOMEM;
391662306a36Sopenharmony_ci	}
391762306a36Sopenharmony_ci
391862306a36Sopenharmony_ci	mutex_init(&pf->vfs.table_lock);
391962306a36Sopenharmony_ci	hash_init(pf->vfs.table);
392062306a36Sopenharmony_ci	ice_mbx_init_snapshot(&pf->hw);
392162306a36Sopenharmony_ci
392262306a36Sopenharmony_ci	return 0;
392362306a36Sopenharmony_ci}
392462306a36Sopenharmony_ci
392562306a36Sopenharmony_ci/**
392662306a36Sopenharmony_ci * ice_is_wol_supported - check if WoL is supported
392762306a36Sopenharmony_ci * @hw: pointer to hardware info
392862306a36Sopenharmony_ci *
392962306a36Sopenharmony_ci * Check if WoL is supported based on the HW configuration.
393062306a36Sopenharmony_ci * Returns true if NVM supports and enables WoL for this port, false otherwise
393162306a36Sopenharmony_ci */
393262306a36Sopenharmony_cibool ice_is_wol_supported(struct ice_hw *hw)
393362306a36Sopenharmony_ci{
393462306a36Sopenharmony_ci	u16 wol_ctrl;
393562306a36Sopenharmony_ci
393662306a36Sopenharmony_ci	/* A bit set to 1 in the NVM Software Reserved Word 2 (WoL control
393762306a36Sopenharmony_ci	 * word) indicates WoL is not supported on the corresponding PF ID.
393862306a36Sopenharmony_ci	 */
393962306a36Sopenharmony_ci	if (ice_read_sr_word(hw, ICE_SR_NVM_WOL_CFG, &wol_ctrl))
394062306a36Sopenharmony_ci		return false;
394162306a36Sopenharmony_ci
394262306a36Sopenharmony_ci	return !(BIT(hw->port_info->lport) & wol_ctrl);
394362306a36Sopenharmony_ci}
394462306a36Sopenharmony_ci
394562306a36Sopenharmony_ci/**
394662306a36Sopenharmony_ci * ice_vsi_recfg_qs - Change the number of queues on a VSI
394762306a36Sopenharmony_ci * @vsi: VSI being changed
394862306a36Sopenharmony_ci * @new_rx: new number of Rx queues
394962306a36Sopenharmony_ci * @new_tx: new number of Tx queues
395062306a36Sopenharmony_ci * @locked: is adev device_lock held
395162306a36Sopenharmony_ci *
395262306a36Sopenharmony_ci * Only change the number of queues if new_tx, or new_rx is non-0.
395362306a36Sopenharmony_ci *
395462306a36Sopenharmony_ci * Returns 0 on success.
395562306a36Sopenharmony_ci */
395662306a36Sopenharmony_ciint ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx, bool locked)
395762306a36Sopenharmony_ci{
395862306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
395962306a36Sopenharmony_ci	int err = 0, timeout = 50;
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_ci	if (!new_rx && !new_tx)
396262306a36Sopenharmony_ci		return -EINVAL;
396362306a36Sopenharmony_ci
396462306a36Sopenharmony_ci	while (test_and_set_bit(ICE_CFG_BUSY, pf->state)) {
396562306a36Sopenharmony_ci		timeout--;
396662306a36Sopenharmony_ci		if (!timeout)
396762306a36Sopenharmony_ci			return -EBUSY;
396862306a36Sopenharmony_ci		usleep_range(1000, 2000);
396962306a36Sopenharmony_ci	}
397062306a36Sopenharmony_ci
397162306a36Sopenharmony_ci	if (new_tx)
397262306a36Sopenharmony_ci		vsi->req_txq = (u16)new_tx;
397362306a36Sopenharmony_ci	if (new_rx)
397462306a36Sopenharmony_ci		vsi->req_rxq = (u16)new_rx;
397562306a36Sopenharmony_ci
397662306a36Sopenharmony_ci	/* set for the next time the netdev is started */
397762306a36Sopenharmony_ci	if (!netif_running(vsi->netdev)) {
397862306a36Sopenharmony_ci		ice_vsi_rebuild(vsi, ICE_VSI_FLAG_NO_INIT);
397962306a36Sopenharmony_ci		dev_dbg(ice_pf_to_dev(pf), "Link is down, queue count change happens when link is brought up\n");
398062306a36Sopenharmony_ci		goto done;
398162306a36Sopenharmony_ci	}
398262306a36Sopenharmony_ci
398362306a36Sopenharmony_ci	ice_vsi_close(vsi);
398462306a36Sopenharmony_ci	ice_vsi_rebuild(vsi, ICE_VSI_FLAG_NO_INIT);
398562306a36Sopenharmony_ci	ice_pf_dcb_recfg(pf, locked);
398662306a36Sopenharmony_ci	ice_vsi_open(vsi);
398762306a36Sopenharmony_cidone:
398862306a36Sopenharmony_ci	clear_bit(ICE_CFG_BUSY, pf->state);
398962306a36Sopenharmony_ci	return err;
399062306a36Sopenharmony_ci}
399162306a36Sopenharmony_ci
399262306a36Sopenharmony_ci/**
399362306a36Sopenharmony_ci * ice_set_safe_mode_vlan_cfg - configure PF VSI to allow all VLANs in safe mode
399462306a36Sopenharmony_ci * @pf: PF to configure
399562306a36Sopenharmony_ci *
399662306a36Sopenharmony_ci * No VLAN offloads/filtering are advertised in safe mode so make sure the PF
399762306a36Sopenharmony_ci * VSI can still Tx/Rx VLAN tagged packets.
399862306a36Sopenharmony_ci */
399962306a36Sopenharmony_cistatic void ice_set_safe_mode_vlan_cfg(struct ice_pf *pf)
400062306a36Sopenharmony_ci{
400162306a36Sopenharmony_ci	struct ice_vsi *vsi = ice_get_main_vsi(pf);
400262306a36Sopenharmony_ci	struct ice_vsi_ctx *ctxt;
400362306a36Sopenharmony_ci	struct ice_hw *hw;
400462306a36Sopenharmony_ci	int status;
400562306a36Sopenharmony_ci
400662306a36Sopenharmony_ci	if (!vsi)
400762306a36Sopenharmony_ci		return;
400862306a36Sopenharmony_ci
400962306a36Sopenharmony_ci	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
401062306a36Sopenharmony_ci	if (!ctxt)
401162306a36Sopenharmony_ci		return;
401262306a36Sopenharmony_ci
401362306a36Sopenharmony_ci	hw = &pf->hw;
401462306a36Sopenharmony_ci	ctxt->info = vsi->info;
401562306a36Sopenharmony_ci
401662306a36Sopenharmony_ci	ctxt->info.valid_sections =
401762306a36Sopenharmony_ci		cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID |
401862306a36Sopenharmony_ci			    ICE_AQ_VSI_PROP_SECURITY_VALID |
401962306a36Sopenharmony_ci			    ICE_AQ_VSI_PROP_SW_VALID);
402062306a36Sopenharmony_ci
402162306a36Sopenharmony_ci	/* disable VLAN anti-spoof */
402262306a36Sopenharmony_ci	ctxt->info.sec_flags &= ~(ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA <<
402362306a36Sopenharmony_ci				  ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S);
402462306a36Sopenharmony_ci
402562306a36Sopenharmony_ci	/* disable VLAN pruning and keep all other settings */
402662306a36Sopenharmony_ci	ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA;
402762306a36Sopenharmony_ci
402862306a36Sopenharmony_ci	/* allow all VLANs on Tx and don't strip on Rx */
402962306a36Sopenharmony_ci	ctxt->info.inner_vlan_flags = ICE_AQ_VSI_INNER_VLAN_TX_MODE_ALL |
403062306a36Sopenharmony_ci		ICE_AQ_VSI_INNER_VLAN_EMODE_NOTHING;
403162306a36Sopenharmony_ci
403262306a36Sopenharmony_ci	status = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
403362306a36Sopenharmony_ci	if (status) {
403462306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(vsi->back), "Failed to update VSI for safe mode VLANs, err %d aq_err %s\n",
403562306a36Sopenharmony_ci			status, ice_aq_str(hw->adminq.sq_last_status));
403662306a36Sopenharmony_ci	} else {
403762306a36Sopenharmony_ci		vsi->info.sec_flags = ctxt->info.sec_flags;
403862306a36Sopenharmony_ci		vsi->info.sw_flags2 = ctxt->info.sw_flags2;
403962306a36Sopenharmony_ci		vsi->info.inner_vlan_flags = ctxt->info.inner_vlan_flags;
404062306a36Sopenharmony_ci	}
404162306a36Sopenharmony_ci
404262306a36Sopenharmony_ci	kfree(ctxt);
404362306a36Sopenharmony_ci}
404462306a36Sopenharmony_ci
404562306a36Sopenharmony_ci/**
404662306a36Sopenharmony_ci * ice_log_pkg_init - log result of DDP package load
404762306a36Sopenharmony_ci * @hw: pointer to hardware info
404862306a36Sopenharmony_ci * @state: state of package load
404962306a36Sopenharmony_ci */
405062306a36Sopenharmony_cistatic void ice_log_pkg_init(struct ice_hw *hw, enum ice_ddp_state state)
405162306a36Sopenharmony_ci{
405262306a36Sopenharmony_ci	struct ice_pf *pf = hw->back;
405362306a36Sopenharmony_ci	struct device *dev;
405462306a36Sopenharmony_ci
405562306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
405662306a36Sopenharmony_ci
405762306a36Sopenharmony_ci	switch (state) {
405862306a36Sopenharmony_ci	case ICE_DDP_PKG_SUCCESS:
405962306a36Sopenharmony_ci		dev_info(dev, "The DDP package was successfully loaded: %s version %d.%d.%d.%d\n",
406062306a36Sopenharmony_ci			 hw->active_pkg_name,
406162306a36Sopenharmony_ci			 hw->active_pkg_ver.major,
406262306a36Sopenharmony_ci			 hw->active_pkg_ver.minor,
406362306a36Sopenharmony_ci			 hw->active_pkg_ver.update,
406462306a36Sopenharmony_ci			 hw->active_pkg_ver.draft);
406562306a36Sopenharmony_ci		break;
406662306a36Sopenharmony_ci	case ICE_DDP_PKG_SAME_VERSION_ALREADY_LOADED:
406762306a36Sopenharmony_ci		dev_info(dev, "DDP package already present on device: %s version %d.%d.%d.%d\n",
406862306a36Sopenharmony_ci			 hw->active_pkg_name,
406962306a36Sopenharmony_ci			 hw->active_pkg_ver.major,
407062306a36Sopenharmony_ci			 hw->active_pkg_ver.minor,
407162306a36Sopenharmony_ci			 hw->active_pkg_ver.update,
407262306a36Sopenharmony_ci			 hw->active_pkg_ver.draft);
407362306a36Sopenharmony_ci		break;
407462306a36Sopenharmony_ci	case ICE_DDP_PKG_ALREADY_LOADED_NOT_SUPPORTED:
407562306a36Sopenharmony_ci		dev_err(dev, "The device has a DDP package that is not supported by the driver.  The device has package '%s' version %d.%d.x.x.  The driver requires version %d.%d.x.x.  Entering Safe Mode.\n",
407662306a36Sopenharmony_ci			hw->active_pkg_name,
407762306a36Sopenharmony_ci			hw->active_pkg_ver.major,
407862306a36Sopenharmony_ci			hw->active_pkg_ver.minor,
407962306a36Sopenharmony_ci			ICE_PKG_SUPP_VER_MAJ, ICE_PKG_SUPP_VER_MNR);
408062306a36Sopenharmony_ci		break;
408162306a36Sopenharmony_ci	case ICE_DDP_PKG_COMPATIBLE_ALREADY_LOADED:
408262306a36Sopenharmony_ci		dev_info(dev, "The driver could not load the DDP package file because a compatible DDP package is already present on the device.  The device has package '%s' version %d.%d.%d.%d.  The package file found by the driver: '%s' version %d.%d.%d.%d.\n",
408362306a36Sopenharmony_ci			 hw->active_pkg_name,
408462306a36Sopenharmony_ci			 hw->active_pkg_ver.major,
408562306a36Sopenharmony_ci			 hw->active_pkg_ver.minor,
408662306a36Sopenharmony_ci			 hw->active_pkg_ver.update,
408762306a36Sopenharmony_ci			 hw->active_pkg_ver.draft,
408862306a36Sopenharmony_ci			 hw->pkg_name,
408962306a36Sopenharmony_ci			 hw->pkg_ver.major,
409062306a36Sopenharmony_ci			 hw->pkg_ver.minor,
409162306a36Sopenharmony_ci			 hw->pkg_ver.update,
409262306a36Sopenharmony_ci			 hw->pkg_ver.draft);
409362306a36Sopenharmony_ci		break;
409462306a36Sopenharmony_ci	case ICE_DDP_PKG_FW_MISMATCH:
409562306a36Sopenharmony_ci		dev_err(dev, "The firmware loaded on the device is not compatible with the DDP package.  Please update the device's NVM.  Entering safe mode.\n");
409662306a36Sopenharmony_ci		break;
409762306a36Sopenharmony_ci	case ICE_DDP_PKG_INVALID_FILE:
409862306a36Sopenharmony_ci		dev_err(dev, "The DDP package file is invalid. Entering Safe Mode.\n");
409962306a36Sopenharmony_ci		break;
410062306a36Sopenharmony_ci	case ICE_DDP_PKG_FILE_VERSION_TOO_HIGH:
410162306a36Sopenharmony_ci		dev_err(dev, "The DDP package file version is higher than the driver supports.  Please use an updated driver.  Entering Safe Mode.\n");
410262306a36Sopenharmony_ci		break;
410362306a36Sopenharmony_ci	case ICE_DDP_PKG_FILE_VERSION_TOO_LOW:
410462306a36Sopenharmony_ci		dev_err(dev, "The DDP package file version is lower than the driver supports.  The driver requires version %d.%d.x.x.  Please use an updated DDP Package file.  Entering Safe Mode.\n",
410562306a36Sopenharmony_ci			ICE_PKG_SUPP_VER_MAJ, ICE_PKG_SUPP_VER_MNR);
410662306a36Sopenharmony_ci		break;
410762306a36Sopenharmony_ci	case ICE_DDP_PKG_FILE_SIGNATURE_INVALID:
410862306a36Sopenharmony_ci		dev_err(dev, "The DDP package could not be loaded because its signature is not valid.  Please use a valid DDP Package.  Entering Safe Mode.\n");
410962306a36Sopenharmony_ci		break;
411062306a36Sopenharmony_ci	case ICE_DDP_PKG_FILE_REVISION_TOO_LOW:
411162306a36Sopenharmony_ci		dev_err(dev, "The DDP Package could not be loaded because its security revision is too low.  Please use an updated DDP Package.  Entering Safe Mode.\n");
411262306a36Sopenharmony_ci		break;
411362306a36Sopenharmony_ci	case ICE_DDP_PKG_LOAD_ERROR:
411462306a36Sopenharmony_ci		dev_err(dev, "An error occurred on the device while loading the DDP package.  The device will be reset.\n");
411562306a36Sopenharmony_ci		/* poll for reset to complete */
411662306a36Sopenharmony_ci		if (ice_check_reset(hw))
411762306a36Sopenharmony_ci			dev_err(dev, "Error resetting device. Please reload the driver\n");
411862306a36Sopenharmony_ci		break;
411962306a36Sopenharmony_ci	case ICE_DDP_PKG_ERR:
412062306a36Sopenharmony_ci	default:
412162306a36Sopenharmony_ci		dev_err(dev, "An unknown error occurred when loading the DDP package.  Entering Safe Mode.\n");
412262306a36Sopenharmony_ci		break;
412362306a36Sopenharmony_ci	}
412462306a36Sopenharmony_ci}
412562306a36Sopenharmony_ci
412662306a36Sopenharmony_ci/**
412762306a36Sopenharmony_ci * ice_load_pkg - load/reload the DDP Package file
412862306a36Sopenharmony_ci * @firmware: firmware structure when firmware requested or NULL for reload
412962306a36Sopenharmony_ci * @pf: pointer to the PF instance
413062306a36Sopenharmony_ci *
413162306a36Sopenharmony_ci * Called on probe and post CORER/GLOBR rebuild to load DDP Package and
413262306a36Sopenharmony_ci * initialize HW tables.
413362306a36Sopenharmony_ci */
413462306a36Sopenharmony_cistatic void
413562306a36Sopenharmony_ciice_load_pkg(const struct firmware *firmware, struct ice_pf *pf)
413662306a36Sopenharmony_ci{
413762306a36Sopenharmony_ci	enum ice_ddp_state state = ICE_DDP_PKG_ERR;
413862306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
413962306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
414062306a36Sopenharmony_ci
414162306a36Sopenharmony_ci	/* Load DDP Package */
414262306a36Sopenharmony_ci	if (firmware && !hw->pkg_copy) {
414362306a36Sopenharmony_ci		state = ice_copy_and_init_pkg(hw, firmware->data,
414462306a36Sopenharmony_ci					      firmware->size);
414562306a36Sopenharmony_ci		ice_log_pkg_init(hw, state);
414662306a36Sopenharmony_ci	} else if (!firmware && hw->pkg_copy) {
414762306a36Sopenharmony_ci		/* Reload package during rebuild after CORER/GLOBR reset */
414862306a36Sopenharmony_ci		state = ice_init_pkg(hw, hw->pkg_copy, hw->pkg_size);
414962306a36Sopenharmony_ci		ice_log_pkg_init(hw, state);
415062306a36Sopenharmony_ci	} else {
415162306a36Sopenharmony_ci		dev_err(dev, "The DDP package file failed to load. Entering Safe Mode.\n");
415262306a36Sopenharmony_ci	}
415362306a36Sopenharmony_ci
415462306a36Sopenharmony_ci	if (!ice_is_init_pkg_successful(state)) {
415562306a36Sopenharmony_ci		/* Safe Mode */
415662306a36Sopenharmony_ci		clear_bit(ICE_FLAG_ADV_FEATURES, pf->flags);
415762306a36Sopenharmony_ci		return;
415862306a36Sopenharmony_ci	}
415962306a36Sopenharmony_ci
416062306a36Sopenharmony_ci	/* Successful download package is the precondition for advanced
416162306a36Sopenharmony_ci	 * features, hence setting the ICE_FLAG_ADV_FEATURES flag
416262306a36Sopenharmony_ci	 */
416362306a36Sopenharmony_ci	set_bit(ICE_FLAG_ADV_FEATURES, pf->flags);
416462306a36Sopenharmony_ci}
416562306a36Sopenharmony_ci
416662306a36Sopenharmony_ci/**
416762306a36Sopenharmony_ci * ice_verify_cacheline_size - verify driver's assumption of 64 Byte cache lines
416862306a36Sopenharmony_ci * @pf: pointer to the PF structure
416962306a36Sopenharmony_ci *
417062306a36Sopenharmony_ci * There is no error returned here because the driver should be able to handle
417162306a36Sopenharmony_ci * 128 Byte cache lines, so we only print a warning in case issues are seen,
417262306a36Sopenharmony_ci * specifically with Tx.
417362306a36Sopenharmony_ci */
417462306a36Sopenharmony_cistatic void ice_verify_cacheline_size(struct ice_pf *pf)
417562306a36Sopenharmony_ci{
417662306a36Sopenharmony_ci	if (rd32(&pf->hw, GLPCI_CNF2) & GLPCI_CNF2_CACHELINE_SIZE_M)
417762306a36Sopenharmony_ci		dev_warn(ice_pf_to_dev(pf), "%d Byte cache line assumption is invalid, driver may have Tx timeouts!\n",
417862306a36Sopenharmony_ci			 ICE_CACHE_LINE_BYTES);
417962306a36Sopenharmony_ci}
418062306a36Sopenharmony_ci
418162306a36Sopenharmony_ci/**
418262306a36Sopenharmony_ci * ice_send_version - update firmware with driver version
418362306a36Sopenharmony_ci * @pf: PF struct
418462306a36Sopenharmony_ci *
418562306a36Sopenharmony_ci * Returns 0 on success, else error code
418662306a36Sopenharmony_ci */
418762306a36Sopenharmony_cistatic int ice_send_version(struct ice_pf *pf)
418862306a36Sopenharmony_ci{
418962306a36Sopenharmony_ci	struct ice_driver_ver dv;
419062306a36Sopenharmony_ci
419162306a36Sopenharmony_ci	dv.major_ver = 0xff;
419262306a36Sopenharmony_ci	dv.minor_ver = 0xff;
419362306a36Sopenharmony_ci	dv.build_ver = 0xff;
419462306a36Sopenharmony_ci	dv.subbuild_ver = 0;
419562306a36Sopenharmony_ci	strscpy((char *)dv.driver_string, UTS_RELEASE,
419662306a36Sopenharmony_ci		sizeof(dv.driver_string));
419762306a36Sopenharmony_ci	return ice_aq_send_driver_ver(&pf->hw, &dv, NULL);
419862306a36Sopenharmony_ci}
419962306a36Sopenharmony_ci
420062306a36Sopenharmony_ci/**
420162306a36Sopenharmony_ci * ice_init_fdir - Initialize flow director VSI and configuration
420262306a36Sopenharmony_ci * @pf: pointer to the PF instance
420362306a36Sopenharmony_ci *
420462306a36Sopenharmony_ci * returns 0 on success, negative on error
420562306a36Sopenharmony_ci */
420662306a36Sopenharmony_cistatic int ice_init_fdir(struct ice_pf *pf)
420762306a36Sopenharmony_ci{
420862306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
420962306a36Sopenharmony_ci	struct ice_vsi *ctrl_vsi;
421062306a36Sopenharmony_ci	int err;
421162306a36Sopenharmony_ci
421262306a36Sopenharmony_ci	/* Side Band Flow Director needs to have a control VSI.
421362306a36Sopenharmony_ci	 * Allocate it and store it in the PF.
421462306a36Sopenharmony_ci	 */
421562306a36Sopenharmony_ci	ctrl_vsi = ice_ctrl_vsi_setup(pf, pf->hw.port_info);
421662306a36Sopenharmony_ci	if (!ctrl_vsi) {
421762306a36Sopenharmony_ci		dev_dbg(dev, "could not create control VSI\n");
421862306a36Sopenharmony_ci		return -ENOMEM;
421962306a36Sopenharmony_ci	}
422062306a36Sopenharmony_ci
422162306a36Sopenharmony_ci	err = ice_vsi_open_ctrl(ctrl_vsi);
422262306a36Sopenharmony_ci	if (err) {
422362306a36Sopenharmony_ci		dev_dbg(dev, "could not open control VSI\n");
422462306a36Sopenharmony_ci		goto err_vsi_open;
422562306a36Sopenharmony_ci	}
422662306a36Sopenharmony_ci
422762306a36Sopenharmony_ci	mutex_init(&pf->hw.fdir_fltr_lock);
422862306a36Sopenharmony_ci
422962306a36Sopenharmony_ci	err = ice_fdir_create_dflt_rules(pf);
423062306a36Sopenharmony_ci	if (err)
423162306a36Sopenharmony_ci		goto err_fdir_rule;
423262306a36Sopenharmony_ci
423362306a36Sopenharmony_ci	return 0;
423462306a36Sopenharmony_ci
423562306a36Sopenharmony_cierr_fdir_rule:
423662306a36Sopenharmony_ci	ice_fdir_release_flows(&pf->hw);
423762306a36Sopenharmony_ci	ice_vsi_close(ctrl_vsi);
423862306a36Sopenharmony_cierr_vsi_open:
423962306a36Sopenharmony_ci	ice_vsi_release(ctrl_vsi);
424062306a36Sopenharmony_ci	if (pf->ctrl_vsi_idx != ICE_NO_VSI) {
424162306a36Sopenharmony_ci		pf->vsi[pf->ctrl_vsi_idx] = NULL;
424262306a36Sopenharmony_ci		pf->ctrl_vsi_idx = ICE_NO_VSI;
424362306a36Sopenharmony_ci	}
424462306a36Sopenharmony_ci	return err;
424562306a36Sopenharmony_ci}
424662306a36Sopenharmony_ci
424762306a36Sopenharmony_cistatic void ice_deinit_fdir(struct ice_pf *pf)
424862306a36Sopenharmony_ci{
424962306a36Sopenharmony_ci	struct ice_vsi *vsi = ice_get_ctrl_vsi(pf);
425062306a36Sopenharmony_ci
425162306a36Sopenharmony_ci	if (!vsi)
425262306a36Sopenharmony_ci		return;
425362306a36Sopenharmony_ci
425462306a36Sopenharmony_ci	ice_vsi_manage_fdir(vsi, false);
425562306a36Sopenharmony_ci	ice_vsi_release(vsi);
425662306a36Sopenharmony_ci	if (pf->ctrl_vsi_idx != ICE_NO_VSI) {
425762306a36Sopenharmony_ci		pf->vsi[pf->ctrl_vsi_idx] = NULL;
425862306a36Sopenharmony_ci		pf->ctrl_vsi_idx = ICE_NO_VSI;
425962306a36Sopenharmony_ci	}
426062306a36Sopenharmony_ci
426162306a36Sopenharmony_ci	mutex_destroy(&(&pf->hw)->fdir_fltr_lock);
426262306a36Sopenharmony_ci}
426362306a36Sopenharmony_ci
426462306a36Sopenharmony_ci/**
426562306a36Sopenharmony_ci * ice_get_opt_fw_name - return optional firmware file name or NULL
426662306a36Sopenharmony_ci * @pf: pointer to the PF instance
426762306a36Sopenharmony_ci */
426862306a36Sopenharmony_cistatic char *ice_get_opt_fw_name(struct ice_pf *pf)
426962306a36Sopenharmony_ci{
427062306a36Sopenharmony_ci	/* Optional firmware name same as default with additional dash
427162306a36Sopenharmony_ci	 * followed by a EUI-64 identifier (PCIe Device Serial Number)
427262306a36Sopenharmony_ci	 */
427362306a36Sopenharmony_ci	struct pci_dev *pdev = pf->pdev;
427462306a36Sopenharmony_ci	char *opt_fw_filename;
427562306a36Sopenharmony_ci	u64 dsn;
427662306a36Sopenharmony_ci
427762306a36Sopenharmony_ci	/* Determine the name of the optional file using the DSN (two
427862306a36Sopenharmony_ci	 * dwords following the start of the DSN Capability).
427962306a36Sopenharmony_ci	 */
428062306a36Sopenharmony_ci	dsn = pci_get_dsn(pdev);
428162306a36Sopenharmony_ci	if (!dsn)
428262306a36Sopenharmony_ci		return NULL;
428362306a36Sopenharmony_ci
428462306a36Sopenharmony_ci	opt_fw_filename = kzalloc(NAME_MAX, GFP_KERNEL);
428562306a36Sopenharmony_ci	if (!opt_fw_filename)
428662306a36Sopenharmony_ci		return NULL;
428762306a36Sopenharmony_ci
428862306a36Sopenharmony_ci	snprintf(opt_fw_filename, NAME_MAX, "%sice-%016llx.pkg",
428962306a36Sopenharmony_ci		 ICE_DDP_PKG_PATH, dsn);
429062306a36Sopenharmony_ci
429162306a36Sopenharmony_ci	return opt_fw_filename;
429262306a36Sopenharmony_ci}
429362306a36Sopenharmony_ci
429462306a36Sopenharmony_ci/**
429562306a36Sopenharmony_ci * ice_request_fw - Device initialization routine
429662306a36Sopenharmony_ci * @pf: pointer to the PF instance
429762306a36Sopenharmony_ci */
429862306a36Sopenharmony_cistatic void ice_request_fw(struct ice_pf *pf)
429962306a36Sopenharmony_ci{
430062306a36Sopenharmony_ci	char *opt_fw_filename = ice_get_opt_fw_name(pf);
430162306a36Sopenharmony_ci	const struct firmware *firmware = NULL;
430262306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
430362306a36Sopenharmony_ci	int err = 0;
430462306a36Sopenharmony_ci
430562306a36Sopenharmony_ci	/* optional device-specific DDP (if present) overrides the default DDP
430662306a36Sopenharmony_ci	 * package file. kernel logs a debug message if the file doesn't exist,
430762306a36Sopenharmony_ci	 * and warning messages for other errors.
430862306a36Sopenharmony_ci	 */
430962306a36Sopenharmony_ci	if (opt_fw_filename) {
431062306a36Sopenharmony_ci		err = firmware_request_nowarn(&firmware, opt_fw_filename, dev);
431162306a36Sopenharmony_ci		if (err) {
431262306a36Sopenharmony_ci			kfree(opt_fw_filename);
431362306a36Sopenharmony_ci			goto dflt_pkg_load;
431462306a36Sopenharmony_ci		}
431562306a36Sopenharmony_ci
431662306a36Sopenharmony_ci		/* request for firmware was successful. Download to device */
431762306a36Sopenharmony_ci		ice_load_pkg(firmware, pf);
431862306a36Sopenharmony_ci		kfree(opt_fw_filename);
431962306a36Sopenharmony_ci		release_firmware(firmware);
432062306a36Sopenharmony_ci		return;
432162306a36Sopenharmony_ci	}
432262306a36Sopenharmony_ci
432362306a36Sopenharmony_cidflt_pkg_load:
432462306a36Sopenharmony_ci	err = request_firmware(&firmware, ICE_DDP_PKG_FILE, dev);
432562306a36Sopenharmony_ci	if (err) {
432662306a36Sopenharmony_ci		dev_err(dev, "The DDP package file was not found or could not be read. Entering Safe Mode\n");
432762306a36Sopenharmony_ci		return;
432862306a36Sopenharmony_ci	}
432962306a36Sopenharmony_ci
433062306a36Sopenharmony_ci	/* request for firmware was successful. Download to device */
433162306a36Sopenharmony_ci	ice_load_pkg(firmware, pf);
433262306a36Sopenharmony_ci	release_firmware(firmware);
433362306a36Sopenharmony_ci}
433462306a36Sopenharmony_ci
433562306a36Sopenharmony_ci/**
433662306a36Sopenharmony_ci * ice_print_wake_reason - show the wake up cause in the log
433762306a36Sopenharmony_ci * @pf: pointer to the PF struct
433862306a36Sopenharmony_ci */
433962306a36Sopenharmony_cistatic void ice_print_wake_reason(struct ice_pf *pf)
434062306a36Sopenharmony_ci{
434162306a36Sopenharmony_ci	u32 wus = pf->wakeup_reason;
434262306a36Sopenharmony_ci	const char *wake_str;
434362306a36Sopenharmony_ci
434462306a36Sopenharmony_ci	/* if no wake event, nothing to print */
434562306a36Sopenharmony_ci	if (!wus)
434662306a36Sopenharmony_ci		return;
434762306a36Sopenharmony_ci
434862306a36Sopenharmony_ci	if (wus & PFPM_WUS_LNKC_M)
434962306a36Sopenharmony_ci		wake_str = "Link\n";
435062306a36Sopenharmony_ci	else if (wus & PFPM_WUS_MAG_M)
435162306a36Sopenharmony_ci		wake_str = "Magic Packet\n";
435262306a36Sopenharmony_ci	else if (wus & PFPM_WUS_MNG_M)
435362306a36Sopenharmony_ci		wake_str = "Management\n";
435462306a36Sopenharmony_ci	else if (wus & PFPM_WUS_FW_RST_WK_M)
435562306a36Sopenharmony_ci		wake_str = "Firmware Reset\n";
435662306a36Sopenharmony_ci	else
435762306a36Sopenharmony_ci		wake_str = "Unknown\n";
435862306a36Sopenharmony_ci
435962306a36Sopenharmony_ci	dev_info(ice_pf_to_dev(pf), "Wake reason: %s", wake_str);
436062306a36Sopenharmony_ci}
436162306a36Sopenharmony_ci
436262306a36Sopenharmony_ci/**
436362306a36Sopenharmony_ci * ice_register_netdev - register netdev
436462306a36Sopenharmony_ci * @vsi: pointer to the VSI struct
436562306a36Sopenharmony_ci */
436662306a36Sopenharmony_cistatic int ice_register_netdev(struct ice_vsi *vsi)
436762306a36Sopenharmony_ci{
436862306a36Sopenharmony_ci	int err;
436962306a36Sopenharmony_ci
437062306a36Sopenharmony_ci	if (!vsi || !vsi->netdev)
437162306a36Sopenharmony_ci		return -EIO;
437262306a36Sopenharmony_ci
437362306a36Sopenharmony_ci	err = register_netdev(vsi->netdev);
437462306a36Sopenharmony_ci	if (err)
437562306a36Sopenharmony_ci		return err;
437662306a36Sopenharmony_ci
437762306a36Sopenharmony_ci	set_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
437862306a36Sopenharmony_ci	netif_carrier_off(vsi->netdev);
437962306a36Sopenharmony_ci	netif_tx_stop_all_queues(vsi->netdev);
438062306a36Sopenharmony_ci
438162306a36Sopenharmony_ci	return 0;
438262306a36Sopenharmony_ci}
438362306a36Sopenharmony_ci
438462306a36Sopenharmony_cistatic void ice_unregister_netdev(struct ice_vsi *vsi)
438562306a36Sopenharmony_ci{
438662306a36Sopenharmony_ci	if (!vsi || !vsi->netdev)
438762306a36Sopenharmony_ci		return;
438862306a36Sopenharmony_ci
438962306a36Sopenharmony_ci	unregister_netdev(vsi->netdev);
439062306a36Sopenharmony_ci	clear_bit(ICE_VSI_NETDEV_REGISTERED, vsi->state);
439162306a36Sopenharmony_ci}
439262306a36Sopenharmony_ci
439362306a36Sopenharmony_ci/**
439462306a36Sopenharmony_ci * ice_cfg_netdev - Allocate, configure and register a netdev
439562306a36Sopenharmony_ci * @vsi: the VSI associated with the new netdev
439662306a36Sopenharmony_ci *
439762306a36Sopenharmony_ci * Returns 0 on success, negative value on failure
439862306a36Sopenharmony_ci */
439962306a36Sopenharmony_cistatic int ice_cfg_netdev(struct ice_vsi *vsi)
440062306a36Sopenharmony_ci{
440162306a36Sopenharmony_ci	struct ice_netdev_priv *np;
440262306a36Sopenharmony_ci	struct net_device *netdev;
440362306a36Sopenharmony_ci	u8 mac_addr[ETH_ALEN];
440462306a36Sopenharmony_ci
440562306a36Sopenharmony_ci	netdev = alloc_etherdev_mqs(sizeof(*np), vsi->alloc_txq,
440662306a36Sopenharmony_ci				    vsi->alloc_rxq);
440762306a36Sopenharmony_ci	if (!netdev)
440862306a36Sopenharmony_ci		return -ENOMEM;
440962306a36Sopenharmony_ci
441062306a36Sopenharmony_ci	set_bit(ICE_VSI_NETDEV_ALLOCD, vsi->state);
441162306a36Sopenharmony_ci	vsi->netdev = netdev;
441262306a36Sopenharmony_ci	np = netdev_priv(netdev);
441362306a36Sopenharmony_ci	np->vsi = vsi;
441462306a36Sopenharmony_ci
441562306a36Sopenharmony_ci	ice_set_netdev_features(netdev);
441662306a36Sopenharmony_ci	ice_set_ops(vsi);
441762306a36Sopenharmony_ci
441862306a36Sopenharmony_ci	if (vsi->type == ICE_VSI_PF) {
441962306a36Sopenharmony_ci		SET_NETDEV_DEV(netdev, ice_pf_to_dev(vsi->back));
442062306a36Sopenharmony_ci		ether_addr_copy(mac_addr, vsi->port_info->mac.perm_addr);
442162306a36Sopenharmony_ci		eth_hw_addr_set(netdev, mac_addr);
442262306a36Sopenharmony_ci	}
442362306a36Sopenharmony_ci
442462306a36Sopenharmony_ci	netdev->priv_flags |= IFF_UNICAST_FLT;
442562306a36Sopenharmony_ci
442662306a36Sopenharmony_ci	/* Setup netdev TC information */
442762306a36Sopenharmony_ci	ice_vsi_cfg_netdev_tc(vsi, vsi->tc_cfg.ena_tc);
442862306a36Sopenharmony_ci
442962306a36Sopenharmony_ci	netdev->max_mtu = ICE_MAX_MTU;
443062306a36Sopenharmony_ci
443162306a36Sopenharmony_ci	return 0;
443262306a36Sopenharmony_ci}
443362306a36Sopenharmony_ci
443462306a36Sopenharmony_cistatic void ice_decfg_netdev(struct ice_vsi *vsi)
443562306a36Sopenharmony_ci{
443662306a36Sopenharmony_ci	clear_bit(ICE_VSI_NETDEV_ALLOCD, vsi->state);
443762306a36Sopenharmony_ci	free_netdev(vsi->netdev);
443862306a36Sopenharmony_ci	vsi->netdev = NULL;
443962306a36Sopenharmony_ci}
444062306a36Sopenharmony_ci
444162306a36Sopenharmony_cistatic int ice_start_eth(struct ice_vsi *vsi)
444262306a36Sopenharmony_ci{
444362306a36Sopenharmony_ci	int err;
444462306a36Sopenharmony_ci
444562306a36Sopenharmony_ci	err = ice_init_mac_fltr(vsi->back);
444662306a36Sopenharmony_ci	if (err)
444762306a36Sopenharmony_ci		return err;
444862306a36Sopenharmony_ci
444962306a36Sopenharmony_ci	err = ice_vsi_open(vsi);
445062306a36Sopenharmony_ci	if (err)
445162306a36Sopenharmony_ci		ice_fltr_remove_all(vsi);
445262306a36Sopenharmony_ci
445362306a36Sopenharmony_ci	return err;
445462306a36Sopenharmony_ci}
445562306a36Sopenharmony_ci
445662306a36Sopenharmony_cistatic void ice_stop_eth(struct ice_vsi *vsi)
445762306a36Sopenharmony_ci{
445862306a36Sopenharmony_ci	ice_fltr_remove_all(vsi);
445962306a36Sopenharmony_ci	ice_vsi_close(vsi);
446062306a36Sopenharmony_ci}
446162306a36Sopenharmony_ci
446262306a36Sopenharmony_cistatic int ice_init_eth(struct ice_pf *pf)
446362306a36Sopenharmony_ci{
446462306a36Sopenharmony_ci	struct ice_vsi *vsi = ice_get_main_vsi(pf);
446562306a36Sopenharmony_ci	int err;
446662306a36Sopenharmony_ci
446762306a36Sopenharmony_ci	if (!vsi)
446862306a36Sopenharmony_ci		return -EINVAL;
446962306a36Sopenharmony_ci
447062306a36Sopenharmony_ci	/* init channel list */
447162306a36Sopenharmony_ci	INIT_LIST_HEAD(&vsi->ch_list);
447262306a36Sopenharmony_ci
447362306a36Sopenharmony_ci	err = ice_cfg_netdev(vsi);
447462306a36Sopenharmony_ci	if (err)
447562306a36Sopenharmony_ci		return err;
447662306a36Sopenharmony_ci	/* Setup DCB netlink interface */
447762306a36Sopenharmony_ci	ice_dcbnl_setup(vsi);
447862306a36Sopenharmony_ci
447962306a36Sopenharmony_ci	err = ice_init_mac_fltr(pf);
448062306a36Sopenharmony_ci	if (err)
448162306a36Sopenharmony_ci		goto err_init_mac_fltr;
448262306a36Sopenharmony_ci
448362306a36Sopenharmony_ci	err = ice_devlink_create_pf_port(pf);
448462306a36Sopenharmony_ci	if (err)
448562306a36Sopenharmony_ci		goto err_devlink_create_pf_port;
448662306a36Sopenharmony_ci
448762306a36Sopenharmony_ci	SET_NETDEV_DEVLINK_PORT(vsi->netdev, &pf->devlink_port);
448862306a36Sopenharmony_ci
448962306a36Sopenharmony_ci	err = ice_register_netdev(vsi);
449062306a36Sopenharmony_ci	if (err)
449162306a36Sopenharmony_ci		goto err_register_netdev;
449262306a36Sopenharmony_ci
449362306a36Sopenharmony_ci	err = ice_tc_indir_block_register(vsi);
449462306a36Sopenharmony_ci	if (err)
449562306a36Sopenharmony_ci		goto err_tc_indir_block_register;
449662306a36Sopenharmony_ci
449762306a36Sopenharmony_ci	ice_napi_add(vsi);
449862306a36Sopenharmony_ci
449962306a36Sopenharmony_ci	return 0;
450062306a36Sopenharmony_ci
450162306a36Sopenharmony_cierr_tc_indir_block_register:
450262306a36Sopenharmony_ci	ice_unregister_netdev(vsi);
450362306a36Sopenharmony_cierr_register_netdev:
450462306a36Sopenharmony_ci	ice_devlink_destroy_pf_port(pf);
450562306a36Sopenharmony_cierr_devlink_create_pf_port:
450662306a36Sopenharmony_cierr_init_mac_fltr:
450762306a36Sopenharmony_ci	ice_decfg_netdev(vsi);
450862306a36Sopenharmony_ci	return err;
450962306a36Sopenharmony_ci}
451062306a36Sopenharmony_ci
451162306a36Sopenharmony_cistatic void ice_deinit_eth(struct ice_pf *pf)
451262306a36Sopenharmony_ci{
451362306a36Sopenharmony_ci	struct ice_vsi *vsi = ice_get_main_vsi(pf);
451462306a36Sopenharmony_ci
451562306a36Sopenharmony_ci	if (!vsi)
451662306a36Sopenharmony_ci		return;
451762306a36Sopenharmony_ci
451862306a36Sopenharmony_ci	ice_vsi_close(vsi);
451962306a36Sopenharmony_ci	ice_unregister_netdev(vsi);
452062306a36Sopenharmony_ci	ice_devlink_destroy_pf_port(pf);
452162306a36Sopenharmony_ci	ice_tc_indir_block_unregister(vsi);
452262306a36Sopenharmony_ci	ice_decfg_netdev(vsi);
452362306a36Sopenharmony_ci}
452462306a36Sopenharmony_ci
452562306a36Sopenharmony_ci/**
452662306a36Sopenharmony_ci * ice_wait_for_fw - wait for full FW readiness
452762306a36Sopenharmony_ci * @hw: pointer to the hardware structure
452862306a36Sopenharmony_ci * @timeout: milliseconds that can elapse before timing out
452962306a36Sopenharmony_ci */
453062306a36Sopenharmony_cistatic int ice_wait_for_fw(struct ice_hw *hw, u32 timeout)
453162306a36Sopenharmony_ci{
453262306a36Sopenharmony_ci	int fw_loading;
453362306a36Sopenharmony_ci	u32 elapsed = 0;
453462306a36Sopenharmony_ci
453562306a36Sopenharmony_ci	while (elapsed <= timeout) {
453662306a36Sopenharmony_ci		fw_loading = rd32(hw, GL_MNG_FWSM) & GL_MNG_FWSM_FW_LOADING_M;
453762306a36Sopenharmony_ci
453862306a36Sopenharmony_ci		/* firmware was not yet loaded, we have to wait more */
453962306a36Sopenharmony_ci		if (fw_loading) {
454062306a36Sopenharmony_ci			elapsed += 100;
454162306a36Sopenharmony_ci			msleep(100);
454262306a36Sopenharmony_ci			continue;
454362306a36Sopenharmony_ci		}
454462306a36Sopenharmony_ci		return 0;
454562306a36Sopenharmony_ci	}
454662306a36Sopenharmony_ci
454762306a36Sopenharmony_ci	return -ETIMEDOUT;
454862306a36Sopenharmony_ci}
454962306a36Sopenharmony_ci
455062306a36Sopenharmony_cistatic int ice_init_dev(struct ice_pf *pf)
455162306a36Sopenharmony_ci{
455262306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
455362306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
455462306a36Sopenharmony_ci	int err;
455562306a36Sopenharmony_ci
455662306a36Sopenharmony_ci	err = ice_init_hw(hw);
455762306a36Sopenharmony_ci	if (err) {
455862306a36Sopenharmony_ci		dev_err(dev, "ice_init_hw failed: %d\n", err);
455962306a36Sopenharmony_ci		return err;
456062306a36Sopenharmony_ci	}
456162306a36Sopenharmony_ci
456262306a36Sopenharmony_ci	/* Some cards require longer initialization times
456362306a36Sopenharmony_ci	 * due to necessity of loading FW from an external source.
456462306a36Sopenharmony_ci	 * This can take even half a minute.
456562306a36Sopenharmony_ci	 */
456662306a36Sopenharmony_ci	if (ice_is_pf_c827(hw)) {
456762306a36Sopenharmony_ci		err = ice_wait_for_fw(hw, 30000);
456862306a36Sopenharmony_ci		if (err) {
456962306a36Sopenharmony_ci			dev_err(dev, "ice_wait_for_fw timed out");
457062306a36Sopenharmony_ci			return err;
457162306a36Sopenharmony_ci		}
457262306a36Sopenharmony_ci	}
457362306a36Sopenharmony_ci
457462306a36Sopenharmony_ci	ice_init_feature_support(pf);
457562306a36Sopenharmony_ci
457662306a36Sopenharmony_ci	ice_request_fw(pf);
457762306a36Sopenharmony_ci
457862306a36Sopenharmony_ci	/* if ice_request_fw fails, ICE_FLAG_ADV_FEATURES bit won't be
457962306a36Sopenharmony_ci	 * set in pf->state, which will cause ice_is_safe_mode to return
458062306a36Sopenharmony_ci	 * true
458162306a36Sopenharmony_ci	 */
458262306a36Sopenharmony_ci	if (ice_is_safe_mode(pf)) {
458362306a36Sopenharmony_ci		/* we already got function/device capabilities but these don't
458462306a36Sopenharmony_ci		 * reflect what the driver needs to do in safe mode. Instead of
458562306a36Sopenharmony_ci		 * adding conditional logic everywhere to ignore these
458662306a36Sopenharmony_ci		 * device/function capabilities, override them.
458762306a36Sopenharmony_ci		 */
458862306a36Sopenharmony_ci		ice_set_safe_mode_caps(hw);
458962306a36Sopenharmony_ci	}
459062306a36Sopenharmony_ci
459162306a36Sopenharmony_ci	err = ice_init_pf(pf);
459262306a36Sopenharmony_ci	if (err) {
459362306a36Sopenharmony_ci		dev_err(dev, "ice_init_pf failed: %d\n", err);
459462306a36Sopenharmony_ci		goto err_init_pf;
459562306a36Sopenharmony_ci	}
459662306a36Sopenharmony_ci
459762306a36Sopenharmony_ci	pf->hw.udp_tunnel_nic.set_port = ice_udp_tunnel_set_port;
459862306a36Sopenharmony_ci	pf->hw.udp_tunnel_nic.unset_port = ice_udp_tunnel_unset_port;
459962306a36Sopenharmony_ci	pf->hw.udp_tunnel_nic.flags = UDP_TUNNEL_NIC_INFO_MAY_SLEEP;
460062306a36Sopenharmony_ci	pf->hw.udp_tunnel_nic.shared = &pf->hw.udp_tunnel_shared;
460162306a36Sopenharmony_ci	if (pf->hw.tnl.valid_count[TNL_VXLAN]) {
460262306a36Sopenharmony_ci		pf->hw.udp_tunnel_nic.tables[0].n_entries =
460362306a36Sopenharmony_ci			pf->hw.tnl.valid_count[TNL_VXLAN];
460462306a36Sopenharmony_ci		pf->hw.udp_tunnel_nic.tables[0].tunnel_types =
460562306a36Sopenharmony_ci			UDP_TUNNEL_TYPE_VXLAN;
460662306a36Sopenharmony_ci	}
460762306a36Sopenharmony_ci	if (pf->hw.tnl.valid_count[TNL_GENEVE]) {
460862306a36Sopenharmony_ci		pf->hw.udp_tunnel_nic.tables[1].n_entries =
460962306a36Sopenharmony_ci			pf->hw.tnl.valid_count[TNL_GENEVE];
461062306a36Sopenharmony_ci		pf->hw.udp_tunnel_nic.tables[1].tunnel_types =
461162306a36Sopenharmony_ci			UDP_TUNNEL_TYPE_GENEVE;
461262306a36Sopenharmony_ci	}
461362306a36Sopenharmony_ci
461462306a36Sopenharmony_ci	err = ice_init_interrupt_scheme(pf);
461562306a36Sopenharmony_ci	if (err) {
461662306a36Sopenharmony_ci		dev_err(dev, "ice_init_interrupt_scheme failed: %d\n", err);
461762306a36Sopenharmony_ci		err = -EIO;
461862306a36Sopenharmony_ci		goto err_init_interrupt_scheme;
461962306a36Sopenharmony_ci	}
462062306a36Sopenharmony_ci
462162306a36Sopenharmony_ci	/* In case of MSIX we are going to setup the misc vector right here
462262306a36Sopenharmony_ci	 * to handle admin queue events etc. In case of legacy and MSI
462362306a36Sopenharmony_ci	 * the misc functionality and queue processing is combined in
462462306a36Sopenharmony_ci	 * the same vector and that gets setup at open.
462562306a36Sopenharmony_ci	 */
462662306a36Sopenharmony_ci	err = ice_req_irq_msix_misc(pf);
462762306a36Sopenharmony_ci	if (err) {
462862306a36Sopenharmony_ci		dev_err(dev, "setup of misc vector failed: %d\n", err);
462962306a36Sopenharmony_ci		goto err_req_irq_msix_misc;
463062306a36Sopenharmony_ci	}
463162306a36Sopenharmony_ci
463262306a36Sopenharmony_ci	return 0;
463362306a36Sopenharmony_ci
463462306a36Sopenharmony_cierr_req_irq_msix_misc:
463562306a36Sopenharmony_ci	ice_clear_interrupt_scheme(pf);
463662306a36Sopenharmony_cierr_init_interrupt_scheme:
463762306a36Sopenharmony_ci	ice_deinit_pf(pf);
463862306a36Sopenharmony_cierr_init_pf:
463962306a36Sopenharmony_ci	ice_deinit_hw(hw);
464062306a36Sopenharmony_ci	return err;
464162306a36Sopenharmony_ci}
464262306a36Sopenharmony_ci
464362306a36Sopenharmony_cistatic void ice_deinit_dev(struct ice_pf *pf)
464462306a36Sopenharmony_ci{
464562306a36Sopenharmony_ci	ice_free_irq_msix_misc(pf);
464662306a36Sopenharmony_ci	ice_deinit_pf(pf);
464762306a36Sopenharmony_ci	ice_deinit_hw(&pf->hw);
464862306a36Sopenharmony_ci
464962306a36Sopenharmony_ci	/* Service task is already stopped, so call reset directly. */
465062306a36Sopenharmony_ci	ice_reset(&pf->hw, ICE_RESET_PFR);
465162306a36Sopenharmony_ci	pci_wait_for_pending_transaction(pf->pdev);
465262306a36Sopenharmony_ci	ice_clear_interrupt_scheme(pf);
465362306a36Sopenharmony_ci}
465462306a36Sopenharmony_ci
465562306a36Sopenharmony_cistatic void ice_init_features(struct ice_pf *pf)
465662306a36Sopenharmony_ci{
465762306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
465862306a36Sopenharmony_ci
465962306a36Sopenharmony_ci	if (ice_is_safe_mode(pf))
466062306a36Sopenharmony_ci		return;
466162306a36Sopenharmony_ci
466262306a36Sopenharmony_ci	/* initialize DDP driven features */
466362306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags))
466462306a36Sopenharmony_ci		ice_ptp_init(pf);
466562306a36Sopenharmony_ci
466662306a36Sopenharmony_ci	if (ice_is_feature_supported(pf, ICE_F_GNSS))
466762306a36Sopenharmony_ci		ice_gnss_init(pf);
466862306a36Sopenharmony_ci
466962306a36Sopenharmony_ci	/* Note: Flow director init failure is non-fatal to load */
467062306a36Sopenharmony_ci	if (ice_init_fdir(pf))
467162306a36Sopenharmony_ci		dev_err(dev, "could not initialize flow director\n");
467262306a36Sopenharmony_ci
467362306a36Sopenharmony_ci	/* Note: DCB init failure is non-fatal to load */
467462306a36Sopenharmony_ci	if (ice_init_pf_dcb(pf, false)) {
467562306a36Sopenharmony_ci		clear_bit(ICE_FLAG_DCB_CAPABLE, pf->flags);
467662306a36Sopenharmony_ci		clear_bit(ICE_FLAG_DCB_ENA, pf->flags);
467762306a36Sopenharmony_ci	} else {
467862306a36Sopenharmony_ci		ice_cfg_lldp_mib_change(&pf->hw, true);
467962306a36Sopenharmony_ci	}
468062306a36Sopenharmony_ci
468162306a36Sopenharmony_ci	if (ice_init_lag(pf))
468262306a36Sopenharmony_ci		dev_warn(dev, "Failed to init link aggregation support\n");
468362306a36Sopenharmony_ci}
468462306a36Sopenharmony_ci
468562306a36Sopenharmony_cistatic void ice_deinit_features(struct ice_pf *pf)
468662306a36Sopenharmony_ci{
468762306a36Sopenharmony_ci	if (ice_is_safe_mode(pf))
468862306a36Sopenharmony_ci		return;
468962306a36Sopenharmony_ci
469062306a36Sopenharmony_ci	ice_deinit_lag(pf);
469162306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_DCB_CAPABLE, pf->flags))
469262306a36Sopenharmony_ci		ice_cfg_lldp_mib_change(&pf->hw, false);
469362306a36Sopenharmony_ci	ice_deinit_fdir(pf);
469462306a36Sopenharmony_ci	if (ice_is_feature_supported(pf, ICE_F_GNSS))
469562306a36Sopenharmony_ci		ice_gnss_exit(pf);
469662306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags))
469762306a36Sopenharmony_ci		ice_ptp_release(pf);
469862306a36Sopenharmony_ci}
469962306a36Sopenharmony_ci
470062306a36Sopenharmony_cistatic void ice_init_wakeup(struct ice_pf *pf)
470162306a36Sopenharmony_ci{
470262306a36Sopenharmony_ci	/* Save wakeup reason register for later use */
470362306a36Sopenharmony_ci	pf->wakeup_reason = rd32(&pf->hw, PFPM_WUS);
470462306a36Sopenharmony_ci
470562306a36Sopenharmony_ci	/* check for a power management event */
470662306a36Sopenharmony_ci	ice_print_wake_reason(pf);
470762306a36Sopenharmony_ci
470862306a36Sopenharmony_ci	/* clear wake status, all bits */
470962306a36Sopenharmony_ci	wr32(&pf->hw, PFPM_WUS, U32_MAX);
471062306a36Sopenharmony_ci
471162306a36Sopenharmony_ci	/* Disable WoL at init, wait for user to enable */
471262306a36Sopenharmony_ci	device_set_wakeup_enable(ice_pf_to_dev(pf), false);
471362306a36Sopenharmony_ci}
471462306a36Sopenharmony_ci
471562306a36Sopenharmony_cistatic int ice_init_link(struct ice_pf *pf)
471662306a36Sopenharmony_ci{
471762306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
471862306a36Sopenharmony_ci	int err;
471962306a36Sopenharmony_ci
472062306a36Sopenharmony_ci	err = ice_init_link_events(pf->hw.port_info);
472162306a36Sopenharmony_ci	if (err) {
472262306a36Sopenharmony_ci		dev_err(dev, "ice_init_link_events failed: %d\n", err);
472362306a36Sopenharmony_ci		return err;
472462306a36Sopenharmony_ci	}
472562306a36Sopenharmony_ci
472662306a36Sopenharmony_ci	/* not a fatal error if this fails */
472762306a36Sopenharmony_ci	err = ice_init_nvm_phy_type(pf->hw.port_info);
472862306a36Sopenharmony_ci	if (err)
472962306a36Sopenharmony_ci		dev_err(dev, "ice_init_nvm_phy_type failed: %d\n", err);
473062306a36Sopenharmony_ci
473162306a36Sopenharmony_ci	/* not a fatal error if this fails */
473262306a36Sopenharmony_ci	err = ice_update_link_info(pf->hw.port_info);
473362306a36Sopenharmony_ci	if (err)
473462306a36Sopenharmony_ci		dev_err(dev, "ice_update_link_info failed: %d\n", err);
473562306a36Sopenharmony_ci
473662306a36Sopenharmony_ci	ice_init_link_dflt_override(pf->hw.port_info);
473762306a36Sopenharmony_ci
473862306a36Sopenharmony_ci	ice_check_link_cfg_err(pf,
473962306a36Sopenharmony_ci			       pf->hw.port_info->phy.link_info.link_cfg_err);
474062306a36Sopenharmony_ci
474162306a36Sopenharmony_ci	/* if media available, initialize PHY settings */
474262306a36Sopenharmony_ci	if (pf->hw.port_info->phy.link_info.link_info &
474362306a36Sopenharmony_ci	    ICE_AQ_MEDIA_AVAILABLE) {
474462306a36Sopenharmony_ci		/* not a fatal error if this fails */
474562306a36Sopenharmony_ci		err = ice_init_phy_user_cfg(pf->hw.port_info);
474662306a36Sopenharmony_ci		if (err)
474762306a36Sopenharmony_ci			dev_err(dev, "ice_init_phy_user_cfg failed: %d\n", err);
474862306a36Sopenharmony_ci
474962306a36Sopenharmony_ci		if (!test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags)) {
475062306a36Sopenharmony_ci			struct ice_vsi *vsi = ice_get_main_vsi(pf);
475162306a36Sopenharmony_ci
475262306a36Sopenharmony_ci			if (vsi)
475362306a36Sopenharmony_ci				ice_configure_phy(vsi);
475462306a36Sopenharmony_ci		}
475562306a36Sopenharmony_ci	} else {
475662306a36Sopenharmony_ci		set_bit(ICE_FLAG_NO_MEDIA, pf->flags);
475762306a36Sopenharmony_ci	}
475862306a36Sopenharmony_ci
475962306a36Sopenharmony_ci	return err;
476062306a36Sopenharmony_ci}
476162306a36Sopenharmony_ci
476262306a36Sopenharmony_cistatic int ice_init_pf_sw(struct ice_pf *pf)
476362306a36Sopenharmony_ci{
476462306a36Sopenharmony_ci	bool dvm = ice_is_dvm_ena(&pf->hw);
476562306a36Sopenharmony_ci	struct ice_vsi *vsi;
476662306a36Sopenharmony_ci	int err;
476762306a36Sopenharmony_ci
476862306a36Sopenharmony_ci	/* create switch struct for the switch element created by FW on boot */
476962306a36Sopenharmony_ci	pf->first_sw = kzalloc(sizeof(*pf->first_sw), GFP_KERNEL);
477062306a36Sopenharmony_ci	if (!pf->first_sw)
477162306a36Sopenharmony_ci		return -ENOMEM;
477262306a36Sopenharmony_ci
477362306a36Sopenharmony_ci	if (pf->hw.evb_veb)
477462306a36Sopenharmony_ci		pf->first_sw->bridge_mode = BRIDGE_MODE_VEB;
477562306a36Sopenharmony_ci	else
477662306a36Sopenharmony_ci		pf->first_sw->bridge_mode = BRIDGE_MODE_VEPA;
477762306a36Sopenharmony_ci
477862306a36Sopenharmony_ci	pf->first_sw->pf = pf;
477962306a36Sopenharmony_ci
478062306a36Sopenharmony_ci	/* record the sw_id available for later use */
478162306a36Sopenharmony_ci	pf->first_sw->sw_id = pf->hw.port_info->sw_id;
478262306a36Sopenharmony_ci
478362306a36Sopenharmony_ci	err = ice_aq_set_port_params(pf->hw.port_info, dvm, NULL);
478462306a36Sopenharmony_ci	if (err)
478562306a36Sopenharmony_ci		goto err_aq_set_port_params;
478662306a36Sopenharmony_ci
478762306a36Sopenharmony_ci	vsi = ice_pf_vsi_setup(pf, pf->hw.port_info);
478862306a36Sopenharmony_ci	if (!vsi) {
478962306a36Sopenharmony_ci		err = -ENOMEM;
479062306a36Sopenharmony_ci		goto err_pf_vsi_setup;
479162306a36Sopenharmony_ci	}
479262306a36Sopenharmony_ci
479362306a36Sopenharmony_ci	return 0;
479462306a36Sopenharmony_ci
479562306a36Sopenharmony_cierr_pf_vsi_setup:
479662306a36Sopenharmony_cierr_aq_set_port_params:
479762306a36Sopenharmony_ci	kfree(pf->first_sw);
479862306a36Sopenharmony_ci	return err;
479962306a36Sopenharmony_ci}
480062306a36Sopenharmony_ci
480162306a36Sopenharmony_cistatic void ice_deinit_pf_sw(struct ice_pf *pf)
480262306a36Sopenharmony_ci{
480362306a36Sopenharmony_ci	struct ice_vsi *vsi = ice_get_main_vsi(pf);
480462306a36Sopenharmony_ci
480562306a36Sopenharmony_ci	if (!vsi)
480662306a36Sopenharmony_ci		return;
480762306a36Sopenharmony_ci
480862306a36Sopenharmony_ci	ice_vsi_release(vsi);
480962306a36Sopenharmony_ci	kfree(pf->first_sw);
481062306a36Sopenharmony_ci}
481162306a36Sopenharmony_ci
481262306a36Sopenharmony_cistatic int ice_alloc_vsis(struct ice_pf *pf)
481362306a36Sopenharmony_ci{
481462306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
481562306a36Sopenharmony_ci
481662306a36Sopenharmony_ci	pf->num_alloc_vsi = pf->hw.func_caps.guar_num_vsi;
481762306a36Sopenharmony_ci	if (!pf->num_alloc_vsi)
481862306a36Sopenharmony_ci		return -EIO;
481962306a36Sopenharmony_ci
482062306a36Sopenharmony_ci	if (pf->num_alloc_vsi > UDP_TUNNEL_NIC_MAX_SHARING_DEVICES) {
482162306a36Sopenharmony_ci		dev_warn(dev,
482262306a36Sopenharmony_ci			 "limiting the VSI count due to UDP tunnel limitation %d > %d\n",
482362306a36Sopenharmony_ci			 pf->num_alloc_vsi, UDP_TUNNEL_NIC_MAX_SHARING_DEVICES);
482462306a36Sopenharmony_ci		pf->num_alloc_vsi = UDP_TUNNEL_NIC_MAX_SHARING_DEVICES;
482562306a36Sopenharmony_ci	}
482662306a36Sopenharmony_ci
482762306a36Sopenharmony_ci	pf->vsi = devm_kcalloc(dev, pf->num_alloc_vsi, sizeof(*pf->vsi),
482862306a36Sopenharmony_ci			       GFP_KERNEL);
482962306a36Sopenharmony_ci	if (!pf->vsi)
483062306a36Sopenharmony_ci		return -ENOMEM;
483162306a36Sopenharmony_ci
483262306a36Sopenharmony_ci	pf->vsi_stats = devm_kcalloc(dev, pf->num_alloc_vsi,
483362306a36Sopenharmony_ci				     sizeof(*pf->vsi_stats), GFP_KERNEL);
483462306a36Sopenharmony_ci	if (!pf->vsi_stats) {
483562306a36Sopenharmony_ci		devm_kfree(dev, pf->vsi);
483662306a36Sopenharmony_ci		return -ENOMEM;
483762306a36Sopenharmony_ci	}
483862306a36Sopenharmony_ci
483962306a36Sopenharmony_ci	return 0;
484062306a36Sopenharmony_ci}
484162306a36Sopenharmony_ci
484262306a36Sopenharmony_cistatic void ice_dealloc_vsis(struct ice_pf *pf)
484362306a36Sopenharmony_ci{
484462306a36Sopenharmony_ci	devm_kfree(ice_pf_to_dev(pf), pf->vsi_stats);
484562306a36Sopenharmony_ci	pf->vsi_stats = NULL;
484662306a36Sopenharmony_ci
484762306a36Sopenharmony_ci	pf->num_alloc_vsi = 0;
484862306a36Sopenharmony_ci	devm_kfree(ice_pf_to_dev(pf), pf->vsi);
484962306a36Sopenharmony_ci	pf->vsi = NULL;
485062306a36Sopenharmony_ci}
485162306a36Sopenharmony_ci
485262306a36Sopenharmony_cistatic int ice_init_devlink(struct ice_pf *pf)
485362306a36Sopenharmony_ci{
485462306a36Sopenharmony_ci	int err;
485562306a36Sopenharmony_ci
485662306a36Sopenharmony_ci	err = ice_devlink_register_params(pf);
485762306a36Sopenharmony_ci	if (err)
485862306a36Sopenharmony_ci		return err;
485962306a36Sopenharmony_ci
486062306a36Sopenharmony_ci	ice_devlink_init_regions(pf);
486162306a36Sopenharmony_ci	ice_devlink_register(pf);
486262306a36Sopenharmony_ci
486362306a36Sopenharmony_ci	return 0;
486462306a36Sopenharmony_ci}
486562306a36Sopenharmony_ci
486662306a36Sopenharmony_cistatic void ice_deinit_devlink(struct ice_pf *pf)
486762306a36Sopenharmony_ci{
486862306a36Sopenharmony_ci	ice_devlink_unregister(pf);
486962306a36Sopenharmony_ci	ice_devlink_destroy_regions(pf);
487062306a36Sopenharmony_ci	ice_devlink_unregister_params(pf);
487162306a36Sopenharmony_ci}
487262306a36Sopenharmony_ci
487362306a36Sopenharmony_cistatic int ice_init(struct ice_pf *pf)
487462306a36Sopenharmony_ci{
487562306a36Sopenharmony_ci	int err;
487662306a36Sopenharmony_ci
487762306a36Sopenharmony_ci	err = ice_init_dev(pf);
487862306a36Sopenharmony_ci	if (err)
487962306a36Sopenharmony_ci		return err;
488062306a36Sopenharmony_ci
488162306a36Sopenharmony_ci	err = ice_alloc_vsis(pf);
488262306a36Sopenharmony_ci	if (err)
488362306a36Sopenharmony_ci		goto err_alloc_vsis;
488462306a36Sopenharmony_ci
488562306a36Sopenharmony_ci	err = ice_init_pf_sw(pf);
488662306a36Sopenharmony_ci	if (err)
488762306a36Sopenharmony_ci		goto err_init_pf_sw;
488862306a36Sopenharmony_ci
488962306a36Sopenharmony_ci	ice_init_wakeup(pf);
489062306a36Sopenharmony_ci
489162306a36Sopenharmony_ci	err = ice_init_link(pf);
489262306a36Sopenharmony_ci	if (err)
489362306a36Sopenharmony_ci		goto err_init_link;
489462306a36Sopenharmony_ci
489562306a36Sopenharmony_ci	err = ice_send_version(pf);
489662306a36Sopenharmony_ci	if (err)
489762306a36Sopenharmony_ci		goto err_init_link;
489862306a36Sopenharmony_ci
489962306a36Sopenharmony_ci	ice_verify_cacheline_size(pf);
490062306a36Sopenharmony_ci
490162306a36Sopenharmony_ci	if (ice_is_safe_mode(pf))
490262306a36Sopenharmony_ci		ice_set_safe_mode_vlan_cfg(pf);
490362306a36Sopenharmony_ci	else
490462306a36Sopenharmony_ci		/* print PCI link speed and width */
490562306a36Sopenharmony_ci		pcie_print_link_status(pf->pdev);
490662306a36Sopenharmony_ci
490762306a36Sopenharmony_ci	/* ready to go, so clear down state bit */
490862306a36Sopenharmony_ci	clear_bit(ICE_DOWN, pf->state);
490962306a36Sopenharmony_ci	clear_bit(ICE_SERVICE_DIS, pf->state);
491062306a36Sopenharmony_ci
491162306a36Sopenharmony_ci	/* since everything is good, start the service timer */
491262306a36Sopenharmony_ci	mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
491362306a36Sopenharmony_ci
491462306a36Sopenharmony_ci	return 0;
491562306a36Sopenharmony_ci
491662306a36Sopenharmony_cierr_init_link:
491762306a36Sopenharmony_ci	ice_deinit_pf_sw(pf);
491862306a36Sopenharmony_cierr_init_pf_sw:
491962306a36Sopenharmony_ci	ice_dealloc_vsis(pf);
492062306a36Sopenharmony_cierr_alloc_vsis:
492162306a36Sopenharmony_ci	ice_deinit_dev(pf);
492262306a36Sopenharmony_ci	return err;
492362306a36Sopenharmony_ci}
492462306a36Sopenharmony_ci
492562306a36Sopenharmony_cistatic void ice_deinit(struct ice_pf *pf)
492662306a36Sopenharmony_ci{
492762306a36Sopenharmony_ci	set_bit(ICE_SERVICE_DIS, pf->state);
492862306a36Sopenharmony_ci	set_bit(ICE_DOWN, pf->state);
492962306a36Sopenharmony_ci
493062306a36Sopenharmony_ci	ice_deinit_pf_sw(pf);
493162306a36Sopenharmony_ci	ice_dealloc_vsis(pf);
493262306a36Sopenharmony_ci	ice_deinit_dev(pf);
493362306a36Sopenharmony_ci}
493462306a36Sopenharmony_ci
493562306a36Sopenharmony_ci/**
493662306a36Sopenharmony_ci * ice_load - load pf by init hw and starting VSI
493762306a36Sopenharmony_ci * @pf: pointer to the pf instance
493862306a36Sopenharmony_ci */
493962306a36Sopenharmony_ciint ice_load(struct ice_pf *pf)
494062306a36Sopenharmony_ci{
494162306a36Sopenharmony_ci	struct ice_vsi_cfg_params params = {};
494262306a36Sopenharmony_ci	struct ice_vsi *vsi;
494362306a36Sopenharmony_ci	int err;
494462306a36Sopenharmony_ci
494562306a36Sopenharmony_ci	err = ice_init_dev(pf);
494662306a36Sopenharmony_ci	if (err)
494762306a36Sopenharmony_ci		return err;
494862306a36Sopenharmony_ci
494962306a36Sopenharmony_ci	vsi = ice_get_main_vsi(pf);
495062306a36Sopenharmony_ci
495162306a36Sopenharmony_ci	params = ice_vsi_to_params(vsi);
495262306a36Sopenharmony_ci	params.flags = ICE_VSI_FLAG_INIT;
495362306a36Sopenharmony_ci
495462306a36Sopenharmony_ci	rtnl_lock();
495562306a36Sopenharmony_ci	err = ice_vsi_cfg(vsi, &params);
495662306a36Sopenharmony_ci	if (err)
495762306a36Sopenharmony_ci		goto err_vsi_cfg;
495862306a36Sopenharmony_ci
495962306a36Sopenharmony_ci	err = ice_start_eth(ice_get_main_vsi(pf));
496062306a36Sopenharmony_ci	if (err)
496162306a36Sopenharmony_ci		goto err_start_eth;
496262306a36Sopenharmony_ci	rtnl_unlock();
496362306a36Sopenharmony_ci
496462306a36Sopenharmony_ci	err = ice_init_rdma(pf);
496562306a36Sopenharmony_ci	if (err)
496662306a36Sopenharmony_ci		goto err_init_rdma;
496762306a36Sopenharmony_ci
496862306a36Sopenharmony_ci	ice_init_features(pf);
496962306a36Sopenharmony_ci	ice_service_task_restart(pf);
497062306a36Sopenharmony_ci
497162306a36Sopenharmony_ci	clear_bit(ICE_DOWN, pf->state);
497262306a36Sopenharmony_ci
497362306a36Sopenharmony_ci	return 0;
497462306a36Sopenharmony_ci
497562306a36Sopenharmony_cierr_init_rdma:
497662306a36Sopenharmony_ci	ice_vsi_close(ice_get_main_vsi(pf));
497762306a36Sopenharmony_ci	rtnl_lock();
497862306a36Sopenharmony_cierr_start_eth:
497962306a36Sopenharmony_ci	ice_vsi_decfg(ice_get_main_vsi(pf));
498062306a36Sopenharmony_cierr_vsi_cfg:
498162306a36Sopenharmony_ci	rtnl_unlock();
498262306a36Sopenharmony_ci	ice_deinit_dev(pf);
498362306a36Sopenharmony_ci	return err;
498462306a36Sopenharmony_ci}
498562306a36Sopenharmony_ci
498662306a36Sopenharmony_ci/**
498762306a36Sopenharmony_ci * ice_unload - unload pf by stopping VSI and deinit hw
498862306a36Sopenharmony_ci * @pf: pointer to the pf instance
498962306a36Sopenharmony_ci */
499062306a36Sopenharmony_civoid ice_unload(struct ice_pf *pf)
499162306a36Sopenharmony_ci{
499262306a36Sopenharmony_ci	ice_deinit_features(pf);
499362306a36Sopenharmony_ci	ice_deinit_rdma(pf);
499462306a36Sopenharmony_ci	rtnl_lock();
499562306a36Sopenharmony_ci	ice_stop_eth(ice_get_main_vsi(pf));
499662306a36Sopenharmony_ci	ice_vsi_decfg(ice_get_main_vsi(pf));
499762306a36Sopenharmony_ci	rtnl_unlock();
499862306a36Sopenharmony_ci	ice_deinit_dev(pf);
499962306a36Sopenharmony_ci}
500062306a36Sopenharmony_ci
500162306a36Sopenharmony_ci/**
500262306a36Sopenharmony_ci * ice_probe - Device initialization routine
500362306a36Sopenharmony_ci * @pdev: PCI device information struct
500462306a36Sopenharmony_ci * @ent: entry in ice_pci_tbl
500562306a36Sopenharmony_ci *
500662306a36Sopenharmony_ci * Returns 0 on success, negative on failure
500762306a36Sopenharmony_ci */
500862306a36Sopenharmony_cistatic int
500962306a36Sopenharmony_ciice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
501062306a36Sopenharmony_ci{
501162306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
501262306a36Sopenharmony_ci	struct ice_pf *pf;
501362306a36Sopenharmony_ci	struct ice_hw *hw;
501462306a36Sopenharmony_ci	int err;
501562306a36Sopenharmony_ci
501662306a36Sopenharmony_ci	if (pdev->is_virtfn) {
501762306a36Sopenharmony_ci		dev_err(dev, "can't probe a virtual function\n");
501862306a36Sopenharmony_ci		return -EINVAL;
501962306a36Sopenharmony_ci	}
502062306a36Sopenharmony_ci
502162306a36Sopenharmony_ci	/* when under a kdump kernel initiate a reset before enabling the
502262306a36Sopenharmony_ci	 * device in order to clear out any pending DMA transactions. These
502362306a36Sopenharmony_ci	 * transactions can cause some systems to machine check when doing
502462306a36Sopenharmony_ci	 * the pcim_enable_device() below.
502562306a36Sopenharmony_ci	 */
502662306a36Sopenharmony_ci	if (is_kdump_kernel()) {
502762306a36Sopenharmony_ci		pci_save_state(pdev);
502862306a36Sopenharmony_ci		pci_clear_master(pdev);
502962306a36Sopenharmony_ci		err = pcie_flr(pdev);
503062306a36Sopenharmony_ci		if (err)
503162306a36Sopenharmony_ci			return err;
503262306a36Sopenharmony_ci		pci_restore_state(pdev);
503362306a36Sopenharmony_ci	}
503462306a36Sopenharmony_ci
503562306a36Sopenharmony_ci	/* this driver uses devres, see
503662306a36Sopenharmony_ci	 * Documentation/driver-api/driver-model/devres.rst
503762306a36Sopenharmony_ci	 */
503862306a36Sopenharmony_ci	err = pcim_enable_device(pdev);
503962306a36Sopenharmony_ci	if (err)
504062306a36Sopenharmony_ci		return err;
504162306a36Sopenharmony_ci
504262306a36Sopenharmony_ci	err = pcim_iomap_regions(pdev, BIT(ICE_BAR0), dev_driver_string(dev));
504362306a36Sopenharmony_ci	if (err) {
504462306a36Sopenharmony_ci		dev_err(dev, "BAR0 I/O map error %d\n", err);
504562306a36Sopenharmony_ci		return err;
504662306a36Sopenharmony_ci	}
504762306a36Sopenharmony_ci
504862306a36Sopenharmony_ci	pf = ice_allocate_pf(dev);
504962306a36Sopenharmony_ci	if (!pf)
505062306a36Sopenharmony_ci		return -ENOMEM;
505162306a36Sopenharmony_ci
505262306a36Sopenharmony_ci	/* initialize Auxiliary index to invalid value */
505362306a36Sopenharmony_ci	pf->aux_idx = -1;
505462306a36Sopenharmony_ci
505562306a36Sopenharmony_ci	/* set up for high or low DMA */
505662306a36Sopenharmony_ci	err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
505762306a36Sopenharmony_ci	if (err) {
505862306a36Sopenharmony_ci		dev_err(dev, "DMA configuration failed: 0x%x\n", err);
505962306a36Sopenharmony_ci		return err;
506062306a36Sopenharmony_ci	}
506162306a36Sopenharmony_ci
506262306a36Sopenharmony_ci	pci_set_master(pdev);
506362306a36Sopenharmony_ci
506462306a36Sopenharmony_ci	pf->pdev = pdev;
506562306a36Sopenharmony_ci	pci_set_drvdata(pdev, pf);
506662306a36Sopenharmony_ci	set_bit(ICE_DOWN, pf->state);
506762306a36Sopenharmony_ci	/* Disable service task until DOWN bit is cleared */
506862306a36Sopenharmony_ci	set_bit(ICE_SERVICE_DIS, pf->state);
506962306a36Sopenharmony_ci
507062306a36Sopenharmony_ci	hw = &pf->hw;
507162306a36Sopenharmony_ci	hw->hw_addr = pcim_iomap_table(pdev)[ICE_BAR0];
507262306a36Sopenharmony_ci	pci_save_state(pdev);
507362306a36Sopenharmony_ci
507462306a36Sopenharmony_ci	hw->back = pf;
507562306a36Sopenharmony_ci	hw->port_info = NULL;
507662306a36Sopenharmony_ci	hw->vendor_id = pdev->vendor;
507762306a36Sopenharmony_ci	hw->device_id = pdev->device;
507862306a36Sopenharmony_ci	pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
507962306a36Sopenharmony_ci	hw->subsystem_vendor_id = pdev->subsystem_vendor;
508062306a36Sopenharmony_ci	hw->subsystem_device_id = pdev->subsystem_device;
508162306a36Sopenharmony_ci	hw->bus.device = PCI_SLOT(pdev->devfn);
508262306a36Sopenharmony_ci	hw->bus.func = PCI_FUNC(pdev->devfn);
508362306a36Sopenharmony_ci	ice_set_ctrlq_len(hw);
508462306a36Sopenharmony_ci
508562306a36Sopenharmony_ci	pf->msg_enable = netif_msg_init(debug, ICE_DFLT_NETIF_M);
508662306a36Sopenharmony_ci
508762306a36Sopenharmony_ci#ifndef CONFIG_DYNAMIC_DEBUG
508862306a36Sopenharmony_ci	if (debug < -1)
508962306a36Sopenharmony_ci		hw->debug_mask = debug;
509062306a36Sopenharmony_ci#endif
509162306a36Sopenharmony_ci
509262306a36Sopenharmony_ci	err = ice_init(pf);
509362306a36Sopenharmony_ci	if (err)
509462306a36Sopenharmony_ci		goto err_init;
509562306a36Sopenharmony_ci
509662306a36Sopenharmony_ci	err = ice_init_eth(pf);
509762306a36Sopenharmony_ci	if (err)
509862306a36Sopenharmony_ci		goto err_init_eth;
509962306a36Sopenharmony_ci
510062306a36Sopenharmony_ci	err = ice_init_rdma(pf);
510162306a36Sopenharmony_ci	if (err)
510262306a36Sopenharmony_ci		goto err_init_rdma;
510362306a36Sopenharmony_ci
510462306a36Sopenharmony_ci	err = ice_init_devlink(pf);
510562306a36Sopenharmony_ci	if (err)
510662306a36Sopenharmony_ci		goto err_init_devlink;
510762306a36Sopenharmony_ci
510862306a36Sopenharmony_ci	ice_init_features(pf);
510962306a36Sopenharmony_ci
511062306a36Sopenharmony_ci	return 0;
511162306a36Sopenharmony_ci
511262306a36Sopenharmony_cierr_init_devlink:
511362306a36Sopenharmony_ci	ice_deinit_rdma(pf);
511462306a36Sopenharmony_cierr_init_rdma:
511562306a36Sopenharmony_ci	ice_deinit_eth(pf);
511662306a36Sopenharmony_cierr_init_eth:
511762306a36Sopenharmony_ci	ice_deinit(pf);
511862306a36Sopenharmony_cierr_init:
511962306a36Sopenharmony_ci	pci_disable_device(pdev);
512062306a36Sopenharmony_ci	return err;
512162306a36Sopenharmony_ci}
512262306a36Sopenharmony_ci
512362306a36Sopenharmony_ci/**
512462306a36Sopenharmony_ci * ice_set_wake - enable or disable Wake on LAN
512562306a36Sopenharmony_ci * @pf: pointer to the PF struct
512662306a36Sopenharmony_ci *
512762306a36Sopenharmony_ci * Simple helper for WoL control
512862306a36Sopenharmony_ci */
512962306a36Sopenharmony_cistatic void ice_set_wake(struct ice_pf *pf)
513062306a36Sopenharmony_ci{
513162306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
513262306a36Sopenharmony_ci	bool wol = pf->wol_ena;
513362306a36Sopenharmony_ci
513462306a36Sopenharmony_ci	/* clear wake state, otherwise new wake events won't fire */
513562306a36Sopenharmony_ci	wr32(hw, PFPM_WUS, U32_MAX);
513662306a36Sopenharmony_ci
513762306a36Sopenharmony_ci	/* enable / disable APM wake up, no RMW needed */
513862306a36Sopenharmony_ci	wr32(hw, PFPM_APM, wol ? PFPM_APM_APME_M : 0);
513962306a36Sopenharmony_ci
514062306a36Sopenharmony_ci	/* set magic packet filter enabled */
514162306a36Sopenharmony_ci	wr32(hw, PFPM_WUFC, wol ? PFPM_WUFC_MAG_M : 0);
514262306a36Sopenharmony_ci}
514362306a36Sopenharmony_ci
514462306a36Sopenharmony_ci/**
514562306a36Sopenharmony_ci * ice_setup_mc_magic_wake - setup device to wake on multicast magic packet
514662306a36Sopenharmony_ci * @pf: pointer to the PF struct
514762306a36Sopenharmony_ci *
514862306a36Sopenharmony_ci * Issue firmware command to enable multicast magic wake, making
514962306a36Sopenharmony_ci * sure that any locally administered address (LAA) is used for
515062306a36Sopenharmony_ci * wake, and that PF reset doesn't undo the LAA.
515162306a36Sopenharmony_ci */
515262306a36Sopenharmony_cistatic void ice_setup_mc_magic_wake(struct ice_pf *pf)
515362306a36Sopenharmony_ci{
515462306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
515562306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
515662306a36Sopenharmony_ci	u8 mac_addr[ETH_ALEN];
515762306a36Sopenharmony_ci	struct ice_vsi *vsi;
515862306a36Sopenharmony_ci	int status;
515962306a36Sopenharmony_ci	u8 flags;
516062306a36Sopenharmony_ci
516162306a36Sopenharmony_ci	if (!pf->wol_ena)
516262306a36Sopenharmony_ci		return;
516362306a36Sopenharmony_ci
516462306a36Sopenharmony_ci	vsi = ice_get_main_vsi(pf);
516562306a36Sopenharmony_ci	if (!vsi)
516662306a36Sopenharmony_ci		return;
516762306a36Sopenharmony_ci
516862306a36Sopenharmony_ci	/* Get current MAC address in case it's an LAA */
516962306a36Sopenharmony_ci	if (vsi->netdev)
517062306a36Sopenharmony_ci		ether_addr_copy(mac_addr, vsi->netdev->dev_addr);
517162306a36Sopenharmony_ci	else
517262306a36Sopenharmony_ci		ether_addr_copy(mac_addr, vsi->port_info->mac.perm_addr);
517362306a36Sopenharmony_ci
517462306a36Sopenharmony_ci	flags = ICE_AQC_MAN_MAC_WR_MC_MAG_EN |
517562306a36Sopenharmony_ci		ICE_AQC_MAN_MAC_UPDATE_LAA_WOL |
517662306a36Sopenharmony_ci		ICE_AQC_MAN_MAC_WR_WOL_LAA_PFR_KEEP;
517762306a36Sopenharmony_ci
517862306a36Sopenharmony_ci	status = ice_aq_manage_mac_write(hw, mac_addr, flags, NULL);
517962306a36Sopenharmony_ci	if (status)
518062306a36Sopenharmony_ci		dev_err(dev, "Failed to enable Multicast Magic Packet wake, err %d aq_err %s\n",
518162306a36Sopenharmony_ci			status, ice_aq_str(hw->adminq.sq_last_status));
518262306a36Sopenharmony_ci}
518362306a36Sopenharmony_ci
518462306a36Sopenharmony_ci/**
518562306a36Sopenharmony_ci * ice_remove - Device removal routine
518662306a36Sopenharmony_ci * @pdev: PCI device information struct
518762306a36Sopenharmony_ci */
518862306a36Sopenharmony_cistatic void ice_remove(struct pci_dev *pdev)
518962306a36Sopenharmony_ci{
519062306a36Sopenharmony_ci	struct ice_pf *pf = pci_get_drvdata(pdev);
519162306a36Sopenharmony_ci	int i;
519262306a36Sopenharmony_ci
519362306a36Sopenharmony_ci	for (i = 0; i < ICE_MAX_RESET_WAIT; i++) {
519462306a36Sopenharmony_ci		if (!ice_is_reset_in_progress(pf->state))
519562306a36Sopenharmony_ci			break;
519662306a36Sopenharmony_ci		msleep(100);
519762306a36Sopenharmony_ci	}
519862306a36Sopenharmony_ci
519962306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_SRIOV_ENA, pf->flags)) {
520062306a36Sopenharmony_ci		set_bit(ICE_VF_RESETS_DISABLED, pf->state);
520162306a36Sopenharmony_ci		ice_free_vfs(pf);
520262306a36Sopenharmony_ci	}
520362306a36Sopenharmony_ci
520462306a36Sopenharmony_ci	ice_service_task_stop(pf);
520562306a36Sopenharmony_ci	ice_aq_cancel_waiting_tasks(pf);
520662306a36Sopenharmony_ci	set_bit(ICE_DOWN, pf->state);
520762306a36Sopenharmony_ci
520862306a36Sopenharmony_ci	if (!ice_is_safe_mode(pf))
520962306a36Sopenharmony_ci		ice_remove_arfs(pf);
521062306a36Sopenharmony_ci	ice_deinit_features(pf);
521162306a36Sopenharmony_ci	ice_deinit_devlink(pf);
521262306a36Sopenharmony_ci	ice_deinit_rdma(pf);
521362306a36Sopenharmony_ci	ice_deinit_eth(pf);
521462306a36Sopenharmony_ci	ice_deinit(pf);
521562306a36Sopenharmony_ci
521662306a36Sopenharmony_ci	ice_vsi_release_all(pf);
521762306a36Sopenharmony_ci
521862306a36Sopenharmony_ci	ice_setup_mc_magic_wake(pf);
521962306a36Sopenharmony_ci	ice_set_wake(pf);
522062306a36Sopenharmony_ci
522162306a36Sopenharmony_ci	pci_disable_device(pdev);
522262306a36Sopenharmony_ci}
522362306a36Sopenharmony_ci
522462306a36Sopenharmony_ci/**
522562306a36Sopenharmony_ci * ice_shutdown - PCI callback for shutting down device
522662306a36Sopenharmony_ci * @pdev: PCI device information struct
522762306a36Sopenharmony_ci */
522862306a36Sopenharmony_cistatic void ice_shutdown(struct pci_dev *pdev)
522962306a36Sopenharmony_ci{
523062306a36Sopenharmony_ci	struct ice_pf *pf = pci_get_drvdata(pdev);
523162306a36Sopenharmony_ci
523262306a36Sopenharmony_ci	ice_remove(pdev);
523362306a36Sopenharmony_ci
523462306a36Sopenharmony_ci	if (system_state == SYSTEM_POWER_OFF) {
523562306a36Sopenharmony_ci		pci_wake_from_d3(pdev, pf->wol_ena);
523662306a36Sopenharmony_ci		pci_set_power_state(pdev, PCI_D3hot);
523762306a36Sopenharmony_ci	}
523862306a36Sopenharmony_ci}
523962306a36Sopenharmony_ci
524062306a36Sopenharmony_ci#ifdef CONFIG_PM
524162306a36Sopenharmony_ci/**
524262306a36Sopenharmony_ci * ice_prepare_for_shutdown - prep for PCI shutdown
524362306a36Sopenharmony_ci * @pf: board private structure
524462306a36Sopenharmony_ci *
524562306a36Sopenharmony_ci * Inform or close all dependent features in prep for PCI device shutdown
524662306a36Sopenharmony_ci */
524762306a36Sopenharmony_cistatic void ice_prepare_for_shutdown(struct ice_pf *pf)
524862306a36Sopenharmony_ci{
524962306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
525062306a36Sopenharmony_ci	u32 v;
525162306a36Sopenharmony_ci
525262306a36Sopenharmony_ci	/* Notify VFs of impending reset */
525362306a36Sopenharmony_ci	if (ice_check_sq_alive(hw, &hw->mailboxq))
525462306a36Sopenharmony_ci		ice_vc_notify_reset(pf);
525562306a36Sopenharmony_ci
525662306a36Sopenharmony_ci	dev_dbg(ice_pf_to_dev(pf), "Tearing down internal switch for shutdown\n");
525762306a36Sopenharmony_ci
525862306a36Sopenharmony_ci	/* disable the VSIs and their queues that are not already DOWN */
525962306a36Sopenharmony_ci	ice_pf_dis_all_vsi(pf, false);
526062306a36Sopenharmony_ci
526162306a36Sopenharmony_ci	ice_for_each_vsi(pf, v)
526262306a36Sopenharmony_ci		if (pf->vsi[v])
526362306a36Sopenharmony_ci			pf->vsi[v]->vsi_num = 0;
526462306a36Sopenharmony_ci
526562306a36Sopenharmony_ci	ice_shutdown_all_ctrlq(hw);
526662306a36Sopenharmony_ci}
526762306a36Sopenharmony_ci
526862306a36Sopenharmony_ci/**
526962306a36Sopenharmony_ci * ice_reinit_interrupt_scheme - Reinitialize interrupt scheme
527062306a36Sopenharmony_ci * @pf: board private structure to reinitialize
527162306a36Sopenharmony_ci *
527262306a36Sopenharmony_ci * This routine reinitialize interrupt scheme that was cleared during
527362306a36Sopenharmony_ci * power management suspend callback.
527462306a36Sopenharmony_ci *
527562306a36Sopenharmony_ci * This should be called during resume routine to re-allocate the q_vectors
527662306a36Sopenharmony_ci * and reacquire interrupts.
527762306a36Sopenharmony_ci */
527862306a36Sopenharmony_cistatic int ice_reinit_interrupt_scheme(struct ice_pf *pf)
527962306a36Sopenharmony_ci{
528062306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
528162306a36Sopenharmony_ci	int ret, v;
528262306a36Sopenharmony_ci
528362306a36Sopenharmony_ci	/* Since we clear MSIX flag during suspend, we need to
528462306a36Sopenharmony_ci	 * set it back during resume...
528562306a36Sopenharmony_ci	 */
528662306a36Sopenharmony_ci
528762306a36Sopenharmony_ci	ret = ice_init_interrupt_scheme(pf);
528862306a36Sopenharmony_ci	if (ret) {
528962306a36Sopenharmony_ci		dev_err(dev, "Failed to re-initialize interrupt %d\n", ret);
529062306a36Sopenharmony_ci		return ret;
529162306a36Sopenharmony_ci	}
529262306a36Sopenharmony_ci
529362306a36Sopenharmony_ci	/* Remap vectors and rings, after successful re-init interrupts */
529462306a36Sopenharmony_ci	ice_for_each_vsi(pf, v) {
529562306a36Sopenharmony_ci		if (!pf->vsi[v])
529662306a36Sopenharmony_ci			continue;
529762306a36Sopenharmony_ci
529862306a36Sopenharmony_ci		ret = ice_vsi_alloc_q_vectors(pf->vsi[v]);
529962306a36Sopenharmony_ci		if (ret)
530062306a36Sopenharmony_ci			goto err_reinit;
530162306a36Sopenharmony_ci		ice_vsi_map_rings_to_vectors(pf->vsi[v]);
530262306a36Sopenharmony_ci	}
530362306a36Sopenharmony_ci
530462306a36Sopenharmony_ci	ret = ice_req_irq_msix_misc(pf);
530562306a36Sopenharmony_ci	if (ret) {
530662306a36Sopenharmony_ci		dev_err(dev, "Setting up misc vector failed after device suspend %d\n",
530762306a36Sopenharmony_ci			ret);
530862306a36Sopenharmony_ci		goto err_reinit;
530962306a36Sopenharmony_ci	}
531062306a36Sopenharmony_ci
531162306a36Sopenharmony_ci	return 0;
531262306a36Sopenharmony_ci
531362306a36Sopenharmony_cierr_reinit:
531462306a36Sopenharmony_ci	while (v--)
531562306a36Sopenharmony_ci		if (pf->vsi[v])
531662306a36Sopenharmony_ci			ice_vsi_free_q_vectors(pf->vsi[v]);
531762306a36Sopenharmony_ci
531862306a36Sopenharmony_ci	return ret;
531962306a36Sopenharmony_ci}
532062306a36Sopenharmony_ci
532162306a36Sopenharmony_ci/**
532262306a36Sopenharmony_ci * ice_suspend
532362306a36Sopenharmony_ci * @dev: generic device information structure
532462306a36Sopenharmony_ci *
532562306a36Sopenharmony_ci * Power Management callback to quiesce the device and prepare
532662306a36Sopenharmony_ci * for D3 transition.
532762306a36Sopenharmony_ci */
532862306a36Sopenharmony_cistatic int __maybe_unused ice_suspend(struct device *dev)
532962306a36Sopenharmony_ci{
533062306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
533162306a36Sopenharmony_ci	struct ice_pf *pf;
533262306a36Sopenharmony_ci	int disabled, v;
533362306a36Sopenharmony_ci
533462306a36Sopenharmony_ci	pf = pci_get_drvdata(pdev);
533562306a36Sopenharmony_ci
533662306a36Sopenharmony_ci	if (!ice_pf_state_is_nominal(pf)) {
533762306a36Sopenharmony_ci		dev_err(dev, "Device is not ready, no need to suspend it\n");
533862306a36Sopenharmony_ci		return -EBUSY;
533962306a36Sopenharmony_ci	}
534062306a36Sopenharmony_ci
534162306a36Sopenharmony_ci	/* Stop watchdog tasks until resume completion.
534262306a36Sopenharmony_ci	 * Even though it is most likely that the service task is
534362306a36Sopenharmony_ci	 * disabled if the device is suspended or down, the service task's
534462306a36Sopenharmony_ci	 * state is controlled by a different state bit, and we should
534562306a36Sopenharmony_ci	 * store and honor whatever state that bit is in at this point.
534662306a36Sopenharmony_ci	 */
534762306a36Sopenharmony_ci	disabled = ice_service_task_stop(pf);
534862306a36Sopenharmony_ci
534962306a36Sopenharmony_ci	ice_unplug_aux_dev(pf);
535062306a36Sopenharmony_ci
535162306a36Sopenharmony_ci	/* Already suspended?, then there is nothing to do */
535262306a36Sopenharmony_ci	if (test_and_set_bit(ICE_SUSPENDED, pf->state)) {
535362306a36Sopenharmony_ci		if (!disabled)
535462306a36Sopenharmony_ci			ice_service_task_restart(pf);
535562306a36Sopenharmony_ci		return 0;
535662306a36Sopenharmony_ci	}
535762306a36Sopenharmony_ci
535862306a36Sopenharmony_ci	if (test_bit(ICE_DOWN, pf->state) ||
535962306a36Sopenharmony_ci	    ice_is_reset_in_progress(pf->state)) {
536062306a36Sopenharmony_ci		dev_err(dev, "can't suspend device in reset or already down\n");
536162306a36Sopenharmony_ci		if (!disabled)
536262306a36Sopenharmony_ci			ice_service_task_restart(pf);
536362306a36Sopenharmony_ci		return 0;
536462306a36Sopenharmony_ci	}
536562306a36Sopenharmony_ci
536662306a36Sopenharmony_ci	ice_setup_mc_magic_wake(pf);
536762306a36Sopenharmony_ci
536862306a36Sopenharmony_ci	ice_prepare_for_shutdown(pf);
536962306a36Sopenharmony_ci
537062306a36Sopenharmony_ci	ice_set_wake(pf);
537162306a36Sopenharmony_ci
537262306a36Sopenharmony_ci	/* Free vectors, clear the interrupt scheme and release IRQs
537362306a36Sopenharmony_ci	 * for proper hibernation, especially with large number of CPUs.
537462306a36Sopenharmony_ci	 * Otherwise hibernation might fail when mapping all the vectors back
537562306a36Sopenharmony_ci	 * to CPU0.
537662306a36Sopenharmony_ci	 */
537762306a36Sopenharmony_ci	ice_free_irq_msix_misc(pf);
537862306a36Sopenharmony_ci	ice_for_each_vsi(pf, v) {
537962306a36Sopenharmony_ci		if (!pf->vsi[v])
538062306a36Sopenharmony_ci			continue;
538162306a36Sopenharmony_ci		ice_vsi_free_q_vectors(pf->vsi[v]);
538262306a36Sopenharmony_ci	}
538362306a36Sopenharmony_ci	ice_clear_interrupt_scheme(pf);
538462306a36Sopenharmony_ci
538562306a36Sopenharmony_ci	pci_save_state(pdev);
538662306a36Sopenharmony_ci	pci_wake_from_d3(pdev, pf->wol_ena);
538762306a36Sopenharmony_ci	pci_set_power_state(pdev, PCI_D3hot);
538862306a36Sopenharmony_ci	return 0;
538962306a36Sopenharmony_ci}
539062306a36Sopenharmony_ci
539162306a36Sopenharmony_ci/**
539262306a36Sopenharmony_ci * ice_resume - PM callback for waking up from D3
539362306a36Sopenharmony_ci * @dev: generic device information structure
539462306a36Sopenharmony_ci */
539562306a36Sopenharmony_cistatic int __maybe_unused ice_resume(struct device *dev)
539662306a36Sopenharmony_ci{
539762306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
539862306a36Sopenharmony_ci	enum ice_reset_req reset_type;
539962306a36Sopenharmony_ci	struct ice_pf *pf;
540062306a36Sopenharmony_ci	struct ice_hw *hw;
540162306a36Sopenharmony_ci	int ret;
540262306a36Sopenharmony_ci
540362306a36Sopenharmony_ci	pci_set_power_state(pdev, PCI_D0);
540462306a36Sopenharmony_ci	pci_restore_state(pdev);
540562306a36Sopenharmony_ci	pci_save_state(pdev);
540662306a36Sopenharmony_ci
540762306a36Sopenharmony_ci	if (!pci_device_is_present(pdev))
540862306a36Sopenharmony_ci		return -ENODEV;
540962306a36Sopenharmony_ci
541062306a36Sopenharmony_ci	ret = pci_enable_device_mem(pdev);
541162306a36Sopenharmony_ci	if (ret) {
541262306a36Sopenharmony_ci		dev_err(dev, "Cannot enable device after suspend\n");
541362306a36Sopenharmony_ci		return ret;
541462306a36Sopenharmony_ci	}
541562306a36Sopenharmony_ci
541662306a36Sopenharmony_ci	pf = pci_get_drvdata(pdev);
541762306a36Sopenharmony_ci	hw = &pf->hw;
541862306a36Sopenharmony_ci
541962306a36Sopenharmony_ci	pf->wakeup_reason = rd32(hw, PFPM_WUS);
542062306a36Sopenharmony_ci	ice_print_wake_reason(pf);
542162306a36Sopenharmony_ci
542262306a36Sopenharmony_ci	/* We cleared the interrupt scheme when we suspended, so we need to
542362306a36Sopenharmony_ci	 * restore it now to resume device functionality.
542462306a36Sopenharmony_ci	 */
542562306a36Sopenharmony_ci	ret = ice_reinit_interrupt_scheme(pf);
542662306a36Sopenharmony_ci	if (ret)
542762306a36Sopenharmony_ci		dev_err(dev, "Cannot restore interrupt scheme: %d\n", ret);
542862306a36Sopenharmony_ci
542962306a36Sopenharmony_ci	clear_bit(ICE_DOWN, pf->state);
543062306a36Sopenharmony_ci	/* Now perform PF reset and rebuild */
543162306a36Sopenharmony_ci	reset_type = ICE_RESET_PFR;
543262306a36Sopenharmony_ci	/* re-enable service task for reset, but allow reset to schedule it */
543362306a36Sopenharmony_ci	clear_bit(ICE_SERVICE_DIS, pf->state);
543462306a36Sopenharmony_ci
543562306a36Sopenharmony_ci	if (ice_schedule_reset(pf, reset_type))
543662306a36Sopenharmony_ci		dev_err(dev, "Reset during resume failed.\n");
543762306a36Sopenharmony_ci
543862306a36Sopenharmony_ci	clear_bit(ICE_SUSPENDED, pf->state);
543962306a36Sopenharmony_ci	ice_service_task_restart(pf);
544062306a36Sopenharmony_ci
544162306a36Sopenharmony_ci	/* Restart the service task */
544262306a36Sopenharmony_ci	mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
544362306a36Sopenharmony_ci
544462306a36Sopenharmony_ci	return 0;
544562306a36Sopenharmony_ci}
544662306a36Sopenharmony_ci#endif /* CONFIG_PM */
544762306a36Sopenharmony_ci
544862306a36Sopenharmony_ci/**
544962306a36Sopenharmony_ci * ice_pci_err_detected - warning that PCI error has been detected
545062306a36Sopenharmony_ci * @pdev: PCI device information struct
545162306a36Sopenharmony_ci * @err: the type of PCI error
545262306a36Sopenharmony_ci *
545362306a36Sopenharmony_ci * Called to warn that something happened on the PCI bus and the error handling
545462306a36Sopenharmony_ci * is in progress.  Allows the driver to gracefully prepare/handle PCI errors.
545562306a36Sopenharmony_ci */
545662306a36Sopenharmony_cistatic pci_ers_result_t
545762306a36Sopenharmony_ciice_pci_err_detected(struct pci_dev *pdev, pci_channel_state_t err)
545862306a36Sopenharmony_ci{
545962306a36Sopenharmony_ci	struct ice_pf *pf = pci_get_drvdata(pdev);
546062306a36Sopenharmony_ci
546162306a36Sopenharmony_ci	if (!pf) {
546262306a36Sopenharmony_ci		dev_err(&pdev->dev, "%s: unrecoverable device error %d\n",
546362306a36Sopenharmony_ci			__func__, err);
546462306a36Sopenharmony_ci		return PCI_ERS_RESULT_DISCONNECT;
546562306a36Sopenharmony_ci	}
546662306a36Sopenharmony_ci
546762306a36Sopenharmony_ci	if (!test_bit(ICE_SUSPENDED, pf->state)) {
546862306a36Sopenharmony_ci		ice_service_task_stop(pf);
546962306a36Sopenharmony_ci
547062306a36Sopenharmony_ci		if (!test_bit(ICE_PREPARED_FOR_RESET, pf->state)) {
547162306a36Sopenharmony_ci			set_bit(ICE_PFR_REQ, pf->state);
547262306a36Sopenharmony_ci			ice_prepare_for_reset(pf, ICE_RESET_PFR);
547362306a36Sopenharmony_ci		}
547462306a36Sopenharmony_ci	}
547562306a36Sopenharmony_ci
547662306a36Sopenharmony_ci	return PCI_ERS_RESULT_NEED_RESET;
547762306a36Sopenharmony_ci}
547862306a36Sopenharmony_ci
547962306a36Sopenharmony_ci/**
548062306a36Sopenharmony_ci * ice_pci_err_slot_reset - a PCI slot reset has just happened
548162306a36Sopenharmony_ci * @pdev: PCI device information struct
548262306a36Sopenharmony_ci *
548362306a36Sopenharmony_ci * Called to determine if the driver can recover from the PCI slot reset by
548462306a36Sopenharmony_ci * using a register read to determine if the device is recoverable.
548562306a36Sopenharmony_ci */
548662306a36Sopenharmony_cistatic pci_ers_result_t ice_pci_err_slot_reset(struct pci_dev *pdev)
548762306a36Sopenharmony_ci{
548862306a36Sopenharmony_ci	struct ice_pf *pf = pci_get_drvdata(pdev);
548962306a36Sopenharmony_ci	pci_ers_result_t result;
549062306a36Sopenharmony_ci	int err;
549162306a36Sopenharmony_ci	u32 reg;
549262306a36Sopenharmony_ci
549362306a36Sopenharmony_ci	err = pci_enable_device_mem(pdev);
549462306a36Sopenharmony_ci	if (err) {
549562306a36Sopenharmony_ci		dev_err(&pdev->dev, "Cannot re-enable PCI device after reset, error %d\n",
549662306a36Sopenharmony_ci			err);
549762306a36Sopenharmony_ci		result = PCI_ERS_RESULT_DISCONNECT;
549862306a36Sopenharmony_ci	} else {
549962306a36Sopenharmony_ci		pci_set_master(pdev);
550062306a36Sopenharmony_ci		pci_restore_state(pdev);
550162306a36Sopenharmony_ci		pci_save_state(pdev);
550262306a36Sopenharmony_ci		pci_wake_from_d3(pdev, false);
550362306a36Sopenharmony_ci
550462306a36Sopenharmony_ci		/* Check for life */
550562306a36Sopenharmony_ci		reg = rd32(&pf->hw, GLGEN_RTRIG);
550662306a36Sopenharmony_ci		if (!reg)
550762306a36Sopenharmony_ci			result = PCI_ERS_RESULT_RECOVERED;
550862306a36Sopenharmony_ci		else
550962306a36Sopenharmony_ci			result = PCI_ERS_RESULT_DISCONNECT;
551062306a36Sopenharmony_ci	}
551162306a36Sopenharmony_ci
551262306a36Sopenharmony_ci	return result;
551362306a36Sopenharmony_ci}
551462306a36Sopenharmony_ci
551562306a36Sopenharmony_ci/**
551662306a36Sopenharmony_ci * ice_pci_err_resume - restart operations after PCI error recovery
551762306a36Sopenharmony_ci * @pdev: PCI device information struct
551862306a36Sopenharmony_ci *
551962306a36Sopenharmony_ci * Called to allow the driver to bring things back up after PCI error and/or
552062306a36Sopenharmony_ci * reset recovery have finished
552162306a36Sopenharmony_ci */
552262306a36Sopenharmony_cistatic void ice_pci_err_resume(struct pci_dev *pdev)
552362306a36Sopenharmony_ci{
552462306a36Sopenharmony_ci	struct ice_pf *pf = pci_get_drvdata(pdev);
552562306a36Sopenharmony_ci
552662306a36Sopenharmony_ci	if (!pf) {
552762306a36Sopenharmony_ci		dev_err(&pdev->dev, "%s failed, device is unrecoverable\n",
552862306a36Sopenharmony_ci			__func__);
552962306a36Sopenharmony_ci		return;
553062306a36Sopenharmony_ci	}
553162306a36Sopenharmony_ci
553262306a36Sopenharmony_ci	if (test_bit(ICE_SUSPENDED, pf->state)) {
553362306a36Sopenharmony_ci		dev_dbg(&pdev->dev, "%s failed to resume normal operations!\n",
553462306a36Sopenharmony_ci			__func__);
553562306a36Sopenharmony_ci		return;
553662306a36Sopenharmony_ci	}
553762306a36Sopenharmony_ci
553862306a36Sopenharmony_ci	ice_restore_all_vfs_msi_state(pdev);
553962306a36Sopenharmony_ci
554062306a36Sopenharmony_ci	ice_do_reset(pf, ICE_RESET_PFR);
554162306a36Sopenharmony_ci	ice_service_task_restart(pf);
554262306a36Sopenharmony_ci	mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period));
554362306a36Sopenharmony_ci}
554462306a36Sopenharmony_ci
554562306a36Sopenharmony_ci/**
554662306a36Sopenharmony_ci * ice_pci_err_reset_prepare - prepare device driver for PCI reset
554762306a36Sopenharmony_ci * @pdev: PCI device information struct
554862306a36Sopenharmony_ci */
554962306a36Sopenharmony_cistatic void ice_pci_err_reset_prepare(struct pci_dev *pdev)
555062306a36Sopenharmony_ci{
555162306a36Sopenharmony_ci	struct ice_pf *pf = pci_get_drvdata(pdev);
555262306a36Sopenharmony_ci
555362306a36Sopenharmony_ci	if (!test_bit(ICE_SUSPENDED, pf->state)) {
555462306a36Sopenharmony_ci		ice_service_task_stop(pf);
555562306a36Sopenharmony_ci
555662306a36Sopenharmony_ci		if (!test_bit(ICE_PREPARED_FOR_RESET, pf->state)) {
555762306a36Sopenharmony_ci			set_bit(ICE_PFR_REQ, pf->state);
555862306a36Sopenharmony_ci			ice_prepare_for_reset(pf, ICE_RESET_PFR);
555962306a36Sopenharmony_ci		}
556062306a36Sopenharmony_ci	}
556162306a36Sopenharmony_ci}
556262306a36Sopenharmony_ci
556362306a36Sopenharmony_ci/**
556462306a36Sopenharmony_ci * ice_pci_err_reset_done - PCI reset done, device driver reset can begin
556562306a36Sopenharmony_ci * @pdev: PCI device information struct
556662306a36Sopenharmony_ci */
556762306a36Sopenharmony_cistatic void ice_pci_err_reset_done(struct pci_dev *pdev)
556862306a36Sopenharmony_ci{
556962306a36Sopenharmony_ci	ice_pci_err_resume(pdev);
557062306a36Sopenharmony_ci}
557162306a36Sopenharmony_ci
557262306a36Sopenharmony_ci/* ice_pci_tbl - PCI Device ID Table
557362306a36Sopenharmony_ci *
557462306a36Sopenharmony_ci * Wildcard entries (PCI_ANY_ID) should come last
557562306a36Sopenharmony_ci * Last entry must be all 0s
557662306a36Sopenharmony_ci *
557762306a36Sopenharmony_ci * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
557862306a36Sopenharmony_ci *   Class, Class Mask, private data (not used) }
557962306a36Sopenharmony_ci */
558062306a36Sopenharmony_cistatic const struct pci_device_id ice_pci_tbl[] = {
558162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E810C_BACKPLANE), 0 },
558262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E810C_QSFP), 0 },
558362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E810C_SFP), 0 },
558462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E810_XXV_BACKPLANE), 0 },
558562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E810_XXV_QSFP), 0 },
558662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E810_XXV_SFP), 0 },
558762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_BACKPLANE), 0 },
558862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_QSFP), 0 },
558962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_SFP), 0 },
559062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_10G_BASE_T), 0 },
559162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_SGMII), 0 },
559262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_BACKPLANE), 0 },
559362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_QSFP), 0 },
559462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_SFP), 0 },
559562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_10G_BASE_T), 0 },
559662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_SGMII), 0 },
559762306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822L_BACKPLANE), 0 },
559862306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822L_SFP), 0 },
559962306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822L_10G_BASE_T), 0 },
560062306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822L_SGMII), 0 },
560162306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_BACKPLANE), 0 },
560262306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_SFP), 0 },
560362306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_10G_BASE_T), 0 },
560462306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_1GBE), 0 },
560562306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_QSFP), 0 },
560662306a36Sopenharmony_ci	{ PCI_VDEVICE(INTEL, ICE_DEV_ID_E822_SI_DFLT), 0 },
560762306a36Sopenharmony_ci	/* required last entry */
560862306a36Sopenharmony_ci	{ 0, }
560962306a36Sopenharmony_ci};
561062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, ice_pci_tbl);
561162306a36Sopenharmony_ci
561262306a36Sopenharmony_cistatic __maybe_unused SIMPLE_DEV_PM_OPS(ice_pm_ops, ice_suspend, ice_resume);
561362306a36Sopenharmony_ci
561462306a36Sopenharmony_cistatic const struct pci_error_handlers ice_pci_err_handler = {
561562306a36Sopenharmony_ci	.error_detected = ice_pci_err_detected,
561662306a36Sopenharmony_ci	.slot_reset = ice_pci_err_slot_reset,
561762306a36Sopenharmony_ci	.reset_prepare = ice_pci_err_reset_prepare,
561862306a36Sopenharmony_ci	.reset_done = ice_pci_err_reset_done,
561962306a36Sopenharmony_ci	.resume = ice_pci_err_resume
562062306a36Sopenharmony_ci};
562162306a36Sopenharmony_ci
562262306a36Sopenharmony_cistatic struct pci_driver ice_driver = {
562362306a36Sopenharmony_ci	.name = KBUILD_MODNAME,
562462306a36Sopenharmony_ci	.id_table = ice_pci_tbl,
562562306a36Sopenharmony_ci	.probe = ice_probe,
562662306a36Sopenharmony_ci	.remove = ice_remove,
562762306a36Sopenharmony_ci#ifdef CONFIG_PM
562862306a36Sopenharmony_ci	.driver.pm = &ice_pm_ops,
562962306a36Sopenharmony_ci#endif /* CONFIG_PM */
563062306a36Sopenharmony_ci	.shutdown = ice_shutdown,
563162306a36Sopenharmony_ci	.sriov_configure = ice_sriov_configure,
563262306a36Sopenharmony_ci	.err_handler = &ice_pci_err_handler
563362306a36Sopenharmony_ci};
563462306a36Sopenharmony_ci
563562306a36Sopenharmony_ci/**
563662306a36Sopenharmony_ci * ice_module_init - Driver registration routine
563762306a36Sopenharmony_ci *
563862306a36Sopenharmony_ci * ice_module_init is the first routine called when the driver is
563962306a36Sopenharmony_ci * loaded. All it does is register with the PCI subsystem.
564062306a36Sopenharmony_ci */
564162306a36Sopenharmony_cistatic int __init ice_module_init(void)
564262306a36Sopenharmony_ci{
564362306a36Sopenharmony_ci	int status = -ENOMEM;
564462306a36Sopenharmony_ci
564562306a36Sopenharmony_ci	pr_info("%s\n", ice_driver_string);
564662306a36Sopenharmony_ci	pr_info("%s\n", ice_copyright);
564762306a36Sopenharmony_ci
564862306a36Sopenharmony_ci	ice_wq = alloc_workqueue("%s", 0, 0, KBUILD_MODNAME);
564962306a36Sopenharmony_ci	if (!ice_wq) {
565062306a36Sopenharmony_ci		pr_err("Failed to create workqueue\n");
565162306a36Sopenharmony_ci		return status;
565262306a36Sopenharmony_ci	}
565362306a36Sopenharmony_ci
565462306a36Sopenharmony_ci	ice_lag_wq = alloc_ordered_workqueue("ice_lag_wq", 0);
565562306a36Sopenharmony_ci	if (!ice_lag_wq) {
565662306a36Sopenharmony_ci		pr_err("Failed to create LAG workqueue\n");
565762306a36Sopenharmony_ci		goto err_dest_wq;
565862306a36Sopenharmony_ci	}
565962306a36Sopenharmony_ci
566062306a36Sopenharmony_ci	status = pci_register_driver(&ice_driver);
566162306a36Sopenharmony_ci	if (status) {
566262306a36Sopenharmony_ci		pr_err("failed to register PCI driver, err %d\n", status);
566362306a36Sopenharmony_ci		goto err_dest_lag_wq;
566462306a36Sopenharmony_ci	}
566562306a36Sopenharmony_ci
566662306a36Sopenharmony_ci	return 0;
566762306a36Sopenharmony_ci
566862306a36Sopenharmony_cierr_dest_lag_wq:
566962306a36Sopenharmony_ci	destroy_workqueue(ice_lag_wq);
567062306a36Sopenharmony_cierr_dest_wq:
567162306a36Sopenharmony_ci	destroy_workqueue(ice_wq);
567262306a36Sopenharmony_ci	return status;
567362306a36Sopenharmony_ci}
567462306a36Sopenharmony_cimodule_init(ice_module_init);
567562306a36Sopenharmony_ci
567662306a36Sopenharmony_ci/**
567762306a36Sopenharmony_ci * ice_module_exit - Driver exit cleanup routine
567862306a36Sopenharmony_ci *
567962306a36Sopenharmony_ci * ice_module_exit is called just before the driver is removed
568062306a36Sopenharmony_ci * from memory.
568162306a36Sopenharmony_ci */
568262306a36Sopenharmony_cistatic void __exit ice_module_exit(void)
568362306a36Sopenharmony_ci{
568462306a36Sopenharmony_ci	pci_unregister_driver(&ice_driver);
568562306a36Sopenharmony_ci	destroy_workqueue(ice_wq);
568662306a36Sopenharmony_ci	destroy_workqueue(ice_lag_wq);
568762306a36Sopenharmony_ci	pr_info("module unloaded\n");
568862306a36Sopenharmony_ci}
568962306a36Sopenharmony_cimodule_exit(ice_module_exit);
569062306a36Sopenharmony_ci
569162306a36Sopenharmony_ci/**
569262306a36Sopenharmony_ci * ice_set_mac_address - NDO callback to set MAC address
569362306a36Sopenharmony_ci * @netdev: network interface device structure
569462306a36Sopenharmony_ci * @pi: pointer to an address structure
569562306a36Sopenharmony_ci *
569662306a36Sopenharmony_ci * Returns 0 on success, negative on failure
569762306a36Sopenharmony_ci */
569862306a36Sopenharmony_cistatic int ice_set_mac_address(struct net_device *netdev, void *pi)
569962306a36Sopenharmony_ci{
570062306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
570162306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
570262306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
570362306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
570462306a36Sopenharmony_ci	struct sockaddr *addr = pi;
570562306a36Sopenharmony_ci	u8 old_mac[ETH_ALEN];
570662306a36Sopenharmony_ci	u8 flags = 0;
570762306a36Sopenharmony_ci	u8 *mac;
570862306a36Sopenharmony_ci	int err;
570962306a36Sopenharmony_ci
571062306a36Sopenharmony_ci	mac = (u8 *)addr->sa_data;
571162306a36Sopenharmony_ci
571262306a36Sopenharmony_ci	if (!is_valid_ether_addr(mac))
571362306a36Sopenharmony_ci		return -EADDRNOTAVAIL;
571462306a36Sopenharmony_ci
571562306a36Sopenharmony_ci	if (test_bit(ICE_DOWN, pf->state) ||
571662306a36Sopenharmony_ci	    ice_is_reset_in_progress(pf->state)) {
571762306a36Sopenharmony_ci		netdev_err(netdev, "can't set mac %pM. device not ready\n",
571862306a36Sopenharmony_ci			   mac);
571962306a36Sopenharmony_ci		return -EBUSY;
572062306a36Sopenharmony_ci	}
572162306a36Sopenharmony_ci
572262306a36Sopenharmony_ci	if (ice_chnl_dmac_fltr_cnt(pf)) {
572362306a36Sopenharmony_ci		netdev_err(netdev, "can't set mac %pM. Device has tc-flower filters, delete all of them and try again\n",
572462306a36Sopenharmony_ci			   mac);
572562306a36Sopenharmony_ci		return -EAGAIN;
572662306a36Sopenharmony_ci	}
572762306a36Sopenharmony_ci
572862306a36Sopenharmony_ci	netif_addr_lock_bh(netdev);
572962306a36Sopenharmony_ci	ether_addr_copy(old_mac, netdev->dev_addr);
573062306a36Sopenharmony_ci	/* change the netdev's MAC address */
573162306a36Sopenharmony_ci	eth_hw_addr_set(netdev, mac);
573262306a36Sopenharmony_ci	netif_addr_unlock_bh(netdev);
573362306a36Sopenharmony_ci
573462306a36Sopenharmony_ci	/* Clean up old MAC filter. Not an error if old filter doesn't exist */
573562306a36Sopenharmony_ci	err = ice_fltr_remove_mac(vsi, old_mac, ICE_FWD_TO_VSI);
573662306a36Sopenharmony_ci	if (err && err != -ENOENT) {
573762306a36Sopenharmony_ci		err = -EADDRNOTAVAIL;
573862306a36Sopenharmony_ci		goto err_update_filters;
573962306a36Sopenharmony_ci	}
574062306a36Sopenharmony_ci
574162306a36Sopenharmony_ci	/* Add filter for new MAC. If filter exists, return success */
574262306a36Sopenharmony_ci	err = ice_fltr_add_mac(vsi, mac, ICE_FWD_TO_VSI);
574362306a36Sopenharmony_ci	if (err == -EEXIST) {
574462306a36Sopenharmony_ci		/* Although this MAC filter is already present in hardware it's
574562306a36Sopenharmony_ci		 * possible in some cases (e.g. bonding) that dev_addr was
574662306a36Sopenharmony_ci		 * modified outside of the driver and needs to be restored back
574762306a36Sopenharmony_ci		 * to this value.
574862306a36Sopenharmony_ci		 */
574962306a36Sopenharmony_ci		netdev_dbg(netdev, "filter for MAC %pM already exists\n", mac);
575062306a36Sopenharmony_ci
575162306a36Sopenharmony_ci		return 0;
575262306a36Sopenharmony_ci	} else if (err) {
575362306a36Sopenharmony_ci		/* error if the new filter addition failed */
575462306a36Sopenharmony_ci		err = -EADDRNOTAVAIL;
575562306a36Sopenharmony_ci	}
575662306a36Sopenharmony_ci
575762306a36Sopenharmony_cierr_update_filters:
575862306a36Sopenharmony_ci	if (err) {
575962306a36Sopenharmony_ci		netdev_err(netdev, "can't set MAC %pM. filter update failed\n",
576062306a36Sopenharmony_ci			   mac);
576162306a36Sopenharmony_ci		netif_addr_lock_bh(netdev);
576262306a36Sopenharmony_ci		eth_hw_addr_set(netdev, old_mac);
576362306a36Sopenharmony_ci		netif_addr_unlock_bh(netdev);
576462306a36Sopenharmony_ci		return err;
576562306a36Sopenharmony_ci	}
576662306a36Sopenharmony_ci
576762306a36Sopenharmony_ci	netdev_dbg(vsi->netdev, "updated MAC address to %pM\n",
576862306a36Sopenharmony_ci		   netdev->dev_addr);
576962306a36Sopenharmony_ci
577062306a36Sopenharmony_ci	/* write new MAC address to the firmware */
577162306a36Sopenharmony_ci	flags = ICE_AQC_MAN_MAC_UPDATE_LAA_WOL;
577262306a36Sopenharmony_ci	err = ice_aq_manage_mac_write(hw, mac, flags, NULL);
577362306a36Sopenharmony_ci	if (err) {
577462306a36Sopenharmony_ci		netdev_err(netdev, "can't set MAC %pM. write to firmware failed error %d\n",
577562306a36Sopenharmony_ci			   mac, err);
577662306a36Sopenharmony_ci	}
577762306a36Sopenharmony_ci	return 0;
577862306a36Sopenharmony_ci}
577962306a36Sopenharmony_ci
578062306a36Sopenharmony_ci/**
578162306a36Sopenharmony_ci * ice_set_rx_mode - NDO callback to set the netdev filters
578262306a36Sopenharmony_ci * @netdev: network interface device structure
578362306a36Sopenharmony_ci */
578462306a36Sopenharmony_cistatic void ice_set_rx_mode(struct net_device *netdev)
578562306a36Sopenharmony_ci{
578662306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
578762306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
578862306a36Sopenharmony_ci
578962306a36Sopenharmony_ci	if (!vsi || ice_is_switchdev_running(vsi->back))
579062306a36Sopenharmony_ci		return;
579162306a36Sopenharmony_ci
579262306a36Sopenharmony_ci	/* Set the flags to synchronize filters
579362306a36Sopenharmony_ci	 * ndo_set_rx_mode may be triggered even without a change in netdev
579462306a36Sopenharmony_ci	 * flags
579562306a36Sopenharmony_ci	 */
579662306a36Sopenharmony_ci	set_bit(ICE_VSI_UMAC_FLTR_CHANGED, vsi->state);
579762306a36Sopenharmony_ci	set_bit(ICE_VSI_MMAC_FLTR_CHANGED, vsi->state);
579862306a36Sopenharmony_ci	set_bit(ICE_FLAG_FLTR_SYNC, vsi->back->flags);
579962306a36Sopenharmony_ci
580062306a36Sopenharmony_ci	/* schedule our worker thread which will take care of
580162306a36Sopenharmony_ci	 * applying the new filter changes
580262306a36Sopenharmony_ci	 */
580362306a36Sopenharmony_ci	ice_service_task_schedule(vsi->back);
580462306a36Sopenharmony_ci}
580562306a36Sopenharmony_ci
580662306a36Sopenharmony_ci/**
580762306a36Sopenharmony_ci * ice_set_tx_maxrate - NDO callback to set the maximum per-queue bitrate
580862306a36Sopenharmony_ci * @netdev: network interface device structure
580962306a36Sopenharmony_ci * @queue_index: Queue ID
581062306a36Sopenharmony_ci * @maxrate: maximum bandwidth in Mbps
581162306a36Sopenharmony_ci */
581262306a36Sopenharmony_cistatic int
581362306a36Sopenharmony_ciice_set_tx_maxrate(struct net_device *netdev, int queue_index, u32 maxrate)
581462306a36Sopenharmony_ci{
581562306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
581662306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
581762306a36Sopenharmony_ci	u16 q_handle;
581862306a36Sopenharmony_ci	int status;
581962306a36Sopenharmony_ci	u8 tc;
582062306a36Sopenharmony_ci
582162306a36Sopenharmony_ci	/* Validate maxrate requested is within permitted range */
582262306a36Sopenharmony_ci	if (maxrate && (maxrate > (ICE_SCHED_MAX_BW / 1000))) {
582362306a36Sopenharmony_ci		netdev_err(netdev, "Invalid max rate %d specified for the queue %d\n",
582462306a36Sopenharmony_ci			   maxrate, queue_index);
582562306a36Sopenharmony_ci		return -EINVAL;
582662306a36Sopenharmony_ci	}
582762306a36Sopenharmony_ci
582862306a36Sopenharmony_ci	q_handle = vsi->tx_rings[queue_index]->q_handle;
582962306a36Sopenharmony_ci	tc = ice_dcb_get_tc(vsi, queue_index);
583062306a36Sopenharmony_ci
583162306a36Sopenharmony_ci	vsi = ice_locate_vsi_using_queue(vsi, queue_index);
583262306a36Sopenharmony_ci	if (!vsi) {
583362306a36Sopenharmony_ci		netdev_err(netdev, "Invalid VSI for given queue %d\n",
583462306a36Sopenharmony_ci			   queue_index);
583562306a36Sopenharmony_ci		return -EINVAL;
583662306a36Sopenharmony_ci	}
583762306a36Sopenharmony_ci
583862306a36Sopenharmony_ci	/* Set BW back to default, when user set maxrate to 0 */
583962306a36Sopenharmony_ci	if (!maxrate)
584062306a36Sopenharmony_ci		status = ice_cfg_q_bw_dflt_lmt(vsi->port_info, vsi->idx, tc,
584162306a36Sopenharmony_ci					       q_handle, ICE_MAX_BW);
584262306a36Sopenharmony_ci	else
584362306a36Sopenharmony_ci		status = ice_cfg_q_bw_lmt(vsi->port_info, vsi->idx, tc,
584462306a36Sopenharmony_ci					  q_handle, ICE_MAX_BW, maxrate * 1000);
584562306a36Sopenharmony_ci	if (status)
584662306a36Sopenharmony_ci		netdev_err(netdev, "Unable to set Tx max rate, error %d\n",
584762306a36Sopenharmony_ci			   status);
584862306a36Sopenharmony_ci
584962306a36Sopenharmony_ci	return status;
585062306a36Sopenharmony_ci}
585162306a36Sopenharmony_ci
585262306a36Sopenharmony_ci/**
585362306a36Sopenharmony_ci * ice_fdb_add - add an entry to the hardware database
585462306a36Sopenharmony_ci * @ndm: the input from the stack
585562306a36Sopenharmony_ci * @tb: pointer to array of nladdr (unused)
585662306a36Sopenharmony_ci * @dev: the net device pointer
585762306a36Sopenharmony_ci * @addr: the MAC address entry being added
585862306a36Sopenharmony_ci * @vid: VLAN ID
585962306a36Sopenharmony_ci * @flags: instructions from stack about fdb operation
586062306a36Sopenharmony_ci * @extack: netlink extended ack
586162306a36Sopenharmony_ci */
586262306a36Sopenharmony_cistatic int
586362306a36Sopenharmony_ciice_fdb_add(struct ndmsg *ndm, struct nlattr __always_unused *tb[],
586462306a36Sopenharmony_ci	    struct net_device *dev, const unsigned char *addr, u16 vid,
586562306a36Sopenharmony_ci	    u16 flags, struct netlink_ext_ack __always_unused *extack)
586662306a36Sopenharmony_ci{
586762306a36Sopenharmony_ci	int err;
586862306a36Sopenharmony_ci
586962306a36Sopenharmony_ci	if (vid) {
587062306a36Sopenharmony_ci		netdev_err(dev, "VLANs aren't supported yet for dev_uc|mc_add()\n");
587162306a36Sopenharmony_ci		return -EINVAL;
587262306a36Sopenharmony_ci	}
587362306a36Sopenharmony_ci	if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
587462306a36Sopenharmony_ci		netdev_err(dev, "FDB only supports static addresses\n");
587562306a36Sopenharmony_ci		return -EINVAL;
587662306a36Sopenharmony_ci	}
587762306a36Sopenharmony_ci
587862306a36Sopenharmony_ci	if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
587962306a36Sopenharmony_ci		err = dev_uc_add_excl(dev, addr);
588062306a36Sopenharmony_ci	else if (is_multicast_ether_addr(addr))
588162306a36Sopenharmony_ci		err = dev_mc_add_excl(dev, addr);
588262306a36Sopenharmony_ci	else
588362306a36Sopenharmony_ci		err = -EINVAL;
588462306a36Sopenharmony_ci
588562306a36Sopenharmony_ci	/* Only return duplicate errors if NLM_F_EXCL is set */
588662306a36Sopenharmony_ci	if (err == -EEXIST && !(flags & NLM_F_EXCL))
588762306a36Sopenharmony_ci		err = 0;
588862306a36Sopenharmony_ci
588962306a36Sopenharmony_ci	return err;
589062306a36Sopenharmony_ci}
589162306a36Sopenharmony_ci
589262306a36Sopenharmony_ci/**
589362306a36Sopenharmony_ci * ice_fdb_del - delete an entry from the hardware database
589462306a36Sopenharmony_ci * @ndm: the input from the stack
589562306a36Sopenharmony_ci * @tb: pointer to array of nladdr (unused)
589662306a36Sopenharmony_ci * @dev: the net device pointer
589762306a36Sopenharmony_ci * @addr: the MAC address entry being added
589862306a36Sopenharmony_ci * @vid: VLAN ID
589962306a36Sopenharmony_ci * @extack: netlink extended ack
590062306a36Sopenharmony_ci */
590162306a36Sopenharmony_cistatic int
590262306a36Sopenharmony_ciice_fdb_del(struct ndmsg *ndm, __always_unused struct nlattr *tb[],
590362306a36Sopenharmony_ci	    struct net_device *dev, const unsigned char *addr,
590462306a36Sopenharmony_ci	    __always_unused u16 vid, struct netlink_ext_ack *extack)
590562306a36Sopenharmony_ci{
590662306a36Sopenharmony_ci	int err;
590762306a36Sopenharmony_ci
590862306a36Sopenharmony_ci	if (ndm->ndm_state & NUD_PERMANENT) {
590962306a36Sopenharmony_ci		netdev_err(dev, "FDB only supports static addresses\n");
591062306a36Sopenharmony_ci		return -EINVAL;
591162306a36Sopenharmony_ci	}
591262306a36Sopenharmony_ci
591362306a36Sopenharmony_ci	if (is_unicast_ether_addr(addr))
591462306a36Sopenharmony_ci		err = dev_uc_del(dev, addr);
591562306a36Sopenharmony_ci	else if (is_multicast_ether_addr(addr))
591662306a36Sopenharmony_ci		err = dev_mc_del(dev, addr);
591762306a36Sopenharmony_ci	else
591862306a36Sopenharmony_ci		err = -EINVAL;
591962306a36Sopenharmony_ci
592062306a36Sopenharmony_ci	return err;
592162306a36Sopenharmony_ci}
592262306a36Sopenharmony_ci
592362306a36Sopenharmony_ci#define NETIF_VLAN_OFFLOAD_FEATURES	(NETIF_F_HW_VLAN_CTAG_RX | \
592462306a36Sopenharmony_ci					 NETIF_F_HW_VLAN_CTAG_TX | \
592562306a36Sopenharmony_ci					 NETIF_F_HW_VLAN_STAG_RX | \
592662306a36Sopenharmony_ci					 NETIF_F_HW_VLAN_STAG_TX)
592762306a36Sopenharmony_ci
592862306a36Sopenharmony_ci#define NETIF_VLAN_STRIPPING_FEATURES	(NETIF_F_HW_VLAN_CTAG_RX | \
592962306a36Sopenharmony_ci					 NETIF_F_HW_VLAN_STAG_RX)
593062306a36Sopenharmony_ci
593162306a36Sopenharmony_ci#define NETIF_VLAN_FILTERING_FEATURES	(NETIF_F_HW_VLAN_CTAG_FILTER | \
593262306a36Sopenharmony_ci					 NETIF_F_HW_VLAN_STAG_FILTER)
593362306a36Sopenharmony_ci
593462306a36Sopenharmony_ci/**
593562306a36Sopenharmony_ci * ice_fix_features - fix the netdev features flags based on device limitations
593662306a36Sopenharmony_ci * @netdev: ptr to the netdev that flags are being fixed on
593762306a36Sopenharmony_ci * @features: features that need to be checked and possibly fixed
593862306a36Sopenharmony_ci *
593962306a36Sopenharmony_ci * Make sure any fixups are made to features in this callback. This enables the
594062306a36Sopenharmony_ci * driver to not have to check unsupported configurations throughout the driver
594162306a36Sopenharmony_ci * because that's the responsiblity of this callback.
594262306a36Sopenharmony_ci *
594362306a36Sopenharmony_ci * Single VLAN Mode (SVM) Supported Features:
594462306a36Sopenharmony_ci *	NETIF_F_HW_VLAN_CTAG_FILTER
594562306a36Sopenharmony_ci *	NETIF_F_HW_VLAN_CTAG_RX
594662306a36Sopenharmony_ci *	NETIF_F_HW_VLAN_CTAG_TX
594762306a36Sopenharmony_ci *
594862306a36Sopenharmony_ci * Double VLAN Mode (DVM) Supported Features:
594962306a36Sopenharmony_ci *	NETIF_F_HW_VLAN_CTAG_FILTER
595062306a36Sopenharmony_ci *	NETIF_F_HW_VLAN_CTAG_RX
595162306a36Sopenharmony_ci *	NETIF_F_HW_VLAN_CTAG_TX
595262306a36Sopenharmony_ci *
595362306a36Sopenharmony_ci *	NETIF_F_HW_VLAN_STAG_FILTER
595462306a36Sopenharmony_ci *	NETIF_HW_VLAN_STAG_RX
595562306a36Sopenharmony_ci *	NETIF_HW_VLAN_STAG_TX
595662306a36Sopenharmony_ci *
595762306a36Sopenharmony_ci * Features that need fixing:
595862306a36Sopenharmony_ci *	Cannot simultaneously enable CTAG and STAG stripping and/or insertion.
595962306a36Sopenharmony_ci *	These are mutually exlusive as the VSI context cannot support multiple
596062306a36Sopenharmony_ci *	VLAN ethertypes simultaneously for stripping and/or insertion. If this
596162306a36Sopenharmony_ci *	is not done, then default to clearing the requested STAG offload
596262306a36Sopenharmony_ci *	settings.
596362306a36Sopenharmony_ci *
596462306a36Sopenharmony_ci *	All supported filtering has to be enabled or disabled together. For
596562306a36Sopenharmony_ci *	example, in DVM, CTAG and STAG filtering have to be enabled and disabled
596662306a36Sopenharmony_ci *	together. If this is not done, then default to VLAN filtering disabled.
596762306a36Sopenharmony_ci *	These are mutually exclusive as there is currently no way to
596862306a36Sopenharmony_ci *	enable/disable VLAN filtering based on VLAN ethertype when using VLAN
596962306a36Sopenharmony_ci *	prune rules.
597062306a36Sopenharmony_ci */
597162306a36Sopenharmony_cistatic netdev_features_t
597262306a36Sopenharmony_ciice_fix_features(struct net_device *netdev, netdev_features_t features)
597362306a36Sopenharmony_ci{
597462306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
597562306a36Sopenharmony_ci	netdev_features_t req_vlan_fltr, cur_vlan_fltr;
597662306a36Sopenharmony_ci	bool cur_ctag, cur_stag, req_ctag, req_stag;
597762306a36Sopenharmony_ci
597862306a36Sopenharmony_ci	cur_vlan_fltr = netdev->features & NETIF_VLAN_FILTERING_FEATURES;
597962306a36Sopenharmony_ci	cur_ctag = cur_vlan_fltr & NETIF_F_HW_VLAN_CTAG_FILTER;
598062306a36Sopenharmony_ci	cur_stag = cur_vlan_fltr & NETIF_F_HW_VLAN_STAG_FILTER;
598162306a36Sopenharmony_ci
598262306a36Sopenharmony_ci	req_vlan_fltr = features & NETIF_VLAN_FILTERING_FEATURES;
598362306a36Sopenharmony_ci	req_ctag = req_vlan_fltr & NETIF_F_HW_VLAN_CTAG_FILTER;
598462306a36Sopenharmony_ci	req_stag = req_vlan_fltr & NETIF_F_HW_VLAN_STAG_FILTER;
598562306a36Sopenharmony_ci
598662306a36Sopenharmony_ci	if (req_vlan_fltr != cur_vlan_fltr) {
598762306a36Sopenharmony_ci		if (ice_is_dvm_ena(&np->vsi->back->hw)) {
598862306a36Sopenharmony_ci			if (req_ctag && req_stag) {
598962306a36Sopenharmony_ci				features |= NETIF_VLAN_FILTERING_FEATURES;
599062306a36Sopenharmony_ci			} else if (!req_ctag && !req_stag) {
599162306a36Sopenharmony_ci				features &= ~NETIF_VLAN_FILTERING_FEATURES;
599262306a36Sopenharmony_ci			} else if ((!cur_ctag && req_ctag && !cur_stag) ||
599362306a36Sopenharmony_ci				   (!cur_stag && req_stag && !cur_ctag)) {
599462306a36Sopenharmony_ci				features |= NETIF_VLAN_FILTERING_FEATURES;
599562306a36Sopenharmony_ci				netdev_warn(netdev,  "802.1Q and 802.1ad VLAN filtering must be either both on or both off. VLAN filtering has been enabled for both types.\n");
599662306a36Sopenharmony_ci			} else if ((cur_ctag && !req_ctag && cur_stag) ||
599762306a36Sopenharmony_ci				   (cur_stag && !req_stag && cur_ctag)) {
599862306a36Sopenharmony_ci				features &= ~NETIF_VLAN_FILTERING_FEATURES;
599962306a36Sopenharmony_ci				netdev_warn(netdev,  "802.1Q and 802.1ad VLAN filtering must be either both on or both off. VLAN filtering has been disabled for both types.\n");
600062306a36Sopenharmony_ci			}
600162306a36Sopenharmony_ci		} else {
600262306a36Sopenharmony_ci			if (req_vlan_fltr & NETIF_F_HW_VLAN_STAG_FILTER)
600362306a36Sopenharmony_ci				netdev_warn(netdev, "cannot support requested 802.1ad filtering setting in SVM mode\n");
600462306a36Sopenharmony_ci
600562306a36Sopenharmony_ci			if (req_vlan_fltr & NETIF_F_HW_VLAN_CTAG_FILTER)
600662306a36Sopenharmony_ci				features |= NETIF_F_HW_VLAN_CTAG_FILTER;
600762306a36Sopenharmony_ci		}
600862306a36Sopenharmony_ci	}
600962306a36Sopenharmony_ci
601062306a36Sopenharmony_ci	if ((features & (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX)) &&
601162306a36Sopenharmony_ci	    (features & (NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_STAG_TX))) {
601262306a36Sopenharmony_ci		netdev_warn(netdev, "cannot support CTAG and STAG VLAN stripping and/or insertion simultaneously since CTAG and STAG offloads are mutually exclusive, clearing STAG offload settings\n");
601362306a36Sopenharmony_ci		features &= ~(NETIF_F_HW_VLAN_STAG_RX |
601462306a36Sopenharmony_ci			      NETIF_F_HW_VLAN_STAG_TX);
601562306a36Sopenharmony_ci	}
601662306a36Sopenharmony_ci
601762306a36Sopenharmony_ci	if (!(netdev->features & NETIF_F_RXFCS) &&
601862306a36Sopenharmony_ci	    (features & NETIF_F_RXFCS) &&
601962306a36Sopenharmony_ci	    (features & NETIF_VLAN_STRIPPING_FEATURES) &&
602062306a36Sopenharmony_ci	    !ice_vsi_has_non_zero_vlans(np->vsi)) {
602162306a36Sopenharmony_ci		netdev_warn(netdev, "Disabling VLAN stripping as FCS/CRC stripping is also disabled and there is no VLAN configured\n");
602262306a36Sopenharmony_ci		features &= ~NETIF_VLAN_STRIPPING_FEATURES;
602362306a36Sopenharmony_ci	}
602462306a36Sopenharmony_ci
602562306a36Sopenharmony_ci	return features;
602662306a36Sopenharmony_ci}
602762306a36Sopenharmony_ci
602862306a36Sopenharmony_ci/**
602962306a36Sopenharmony_ci * ice_set_vlan_offload_features - set VLAN offload features for the PF VSI
603062306a36Sopenharmony_ci * @vsi: PF's VSI
603162306a36Sopenharmony_ci * @features: features used to determine VLAN offload settings
603262306a36Sopenharmony_ci *
603362306a36Sopenharmony_ci * First, determine the vlan_ethertype based on the VLAN offload bits in
603462306a36Sopenharmony_ci * features. Then determine if stripping and insertion should be enabled or
603562306a36Sopenharmony_ci * disabled. Finally enable or disable VLAN stripping and insertion.
603662306a36Sopenharmony_ci */
603762306a36Sopenharmony_cistatic int
603862306a36Sopenharmony_ciice_set_vlan_offload_features(struct ice_vsi *vsi, netdev_features_t features)
603962306a36Sopenharmony_ci{
604062306a36Sopenharmony_ci	bool enable_stripping = true, enable_insertion = true;
604162306a36Sopenharmony_ci	struct ice_vsi_vlan_ops *vlan_ops;
604262306a36Sopenharmony_ci	int strip_err = 0, insert_err = 0;
604362306a36Sopenharmony_ci	u16 vlan_ethertype = 0;
604462306a36Sopenharmony_ci
604562306a36Sopenharmony_ci	vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
604662306a36Sopenharmony_ci
604762306a36Sopenharmony_ci	if (features & (NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_STAG_TX))
604862306a36Sopenharmony_ci		vlan_ethertype = ETH_P_8021AD;
604962306a36Sopenharmony_ci	else if (features & (NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX))
605062306a36Sopenharmony_ci		vlan_ethertype = ETH_P_8021Q;
605162306a36Sopenharmony_ci
605262306a36Sopenharmony_ci	if (!(features & (NETIF_F_HW_VLAN_STAG_RX | NETIF_F_HW_VLAN_CTAG_RX)))
605362306a36Sopenharmony_ci		enable_stripping = false;
605462306a36Sopenharmony_ci	if (!(features & (NETIF_F_HW_VLAN_STAG_TX | NETIF_F_HW_VLAN_CTAG_TX)))
605562306a36Sopenharmony_ci		enable_insertion = false;
605662306a36Sopenharmony_ci
605762306a36Sopenharmony_ci	if (enable_stripping)
605862306a36Sopenharmony_ci		strip_err = vlan_ops->ena_stripping(vsi, vlan_ethertype);
605962306a36Sopenharmony_ci	else
606062306a36Sopenharmony_ci		strip_err = vlan_ops->dis_stripping(vsi);
606162306a36Sopenharmony_ci
606262306a36Sopenharmony_ci	if (enable_insertion)
606362306a36Sopenharmony_ci		insert_err = vlan_ops->ena_insertion(vsi, vlan_ethertype);
606462306a36Sopenharmony_ci	else
606562306a36Sopenharmony_ci		insert_err = vlan_ops->dis_insertion(vsi);
606662306a36Sopenharmony_ci
606762306a36Sopenharmony_ci	if (strip_err || insert_err)
606862306a36Sopenharmony_ci		return -EIO;
606962306a36Sopenharmony_ci
607062306a36Sopenharmony_ci	return 0;
607162306a36Sopenharmony_ci}
607262306a36Sopenharmony_ci
607362306a36Sopenharmony_ci/**
607462306a36Sopenharmony_ci * ice_set_vlan_filtering_features - set VLAN filtering features for the PF VSI
607562306a36Sopenharmony_ci * @vsi: PF's VSI
607662306a36Sopenharmony_ci * @features: features used to determine VLAN filtering settings
607762306a36Sopenharmony_ci *
607862306a36Sopenharmony_ci * Enable or disable Rx VLAN filtering based on the VLAN filtering bits in the
607962306a36Sopenharmony_ci * features.
608062306a36Sopenharmony_ci */
608162306a36Sopenharmony_cistatic int
608262306a36Sopenharmony_ciice_set_vlan_filtering_features(struct ice_vsi *vsi, netdev_features_t features)
608362306a36Sopenharmony_ci{
608462306a36Sopenharmony_ci	struct ice_vsi_vlan_ops *vlan_ops = ice_get_compat_vsi_vlan_ops(vsi);
608562306a36Sopenharmony_ci	int err = 0;
608662306a36Sopenharmony_ci
608762306a36Sopenharmony_ci	/* support Single VLAN Mode (SVM) and Double VLAN Mode (DVM) by checking
608862306a36Sopenharmony_ci	 * if either bit is set
608962306a36Sopenharmony_ci	 */
609062306a36Sopenharmony_ci	if (features &
609162306a36Sopenharmony_ci	    (NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_STAG_FILTER))
609262306a36Sopenharmony_ci		err = vlan_ops->ena_rx_filtering(vsi);
609362306a36Sopenharmony_ci	else
609462306a36Sopenharmony_ci		err = vlan_ops->dis_rx_filtering(vsi);
609562306a36Sopenharmony_ci
609662306a36Sopenharmony_ci	return err;
609762306a36Sopenharmony_ci}
609862306a36Sopenharmony_ci
609962306a36Sopenharmony_ci/**
610062306a36Sopenharmony_ci * ice_set_vlan_features - set VLAN settings based on suggested feature set
610162306a36Sopenharmony_ci * @netdev: ptr to the netdev being adjusted
610262306a36Sopenharmony_ci * @features: the feature set that the stack is suggesting
610362306a36Sopenharmony_ci *
610462306a36Sopenharmony_ci * Only update VLAN settings if the requested_vlan_features are different than
610562306a36Sopenharmony_ci * the current_vlan_features.
610662306a36Sopenharmony_ci */
610762306a36Sopenharmony_cistatic int
610862306a36Sopenharmony_ciice_set_vlan_features(struct net_device *netdev, netdev_features_t features)
610962306a36Sopenharmony_ci{
611062306a36Sopenharmony_ci	netdev_features_t current_vlan_features, requested_vlan_features;
611162306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
611262306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
611362306a36Sopenharmony_ci	int err;
611462306a36Sopenharmony_ci
611562306a36Sopenharmony_ci	current_vlan_features = netdev->features & NETIF_VLAN_OFFLOAD_FEATURES;
611662306a36Sopenharmony_ci	requested_vlan_features = features & NETIF_VLAN_OFFLOAD_FEATURES;
611762306a36Sopenharmony_ci	if (current_vlan_features ^ requested_vlan_features) {
611862306a36Sopenharmony_ci		if ((features & NETIF_F_RXFCS) &&
611962306a36Sopenharmony_ci		    (features & NETIF_VLAN_STRIPPING_FEATURES)) {
612062306a36Sopenharmony_ci			dev_err(ice_pf_to_dev(vsi->back),
612162306a36Sopenharmony_ci				"To enable VLAN stripping, you must first enable FCS/CRC stripping\n");
612262306a36Sopenharmony_ci			return -EIO;
612362306a36Sopenharmony_ci		}
612462306a36Sopenharmony_ci
612562306a36Sopenharmony_ci		err = ice_set_vlan_offload_features(vsi, features);
612662306a36Sopenharmony_ci		if (err)
612762306a36Sopenharmony_ci			return err;
612862306a36Sopenharmony_ci	}
612962306a36Sopenharmony_ci
613062306a36Sopenharmony_ci	current_vlan_features = netdev->features &
613162306a36Sopenharmony_ci		NETIF_VLAN_FILTERING_FEATURES;
613262306a36Sopenharmony_ci	requested_vlan_features = features & NETIF_VLAN_FILTERING_FEATURES;
613362306a36Sopenharmony_ci	if (current_vlan_features ^ requested_vlan_features) {
613462306a36Sopenharmony_ci		err = ice_set_vlan_filtering_features(vsi, features);
613562306a36Sopenharmony_ci		if (err)
613662306a36Sopenharmony_ci			return err;
613762306a36Sopenharmony_ci	}
613862306a36Sopenharmony_ci
613962306a36Sopenharmony_ci	return 0;
614062306a36Sopenharmony_ci}
614162306a36Sopenharmony_ci
614262306a36Sopenharmony_ci/**
614362306a36Sopenharmony_ci * ice_set_loopback - turn on/off loopback mode on underlying PF
614462306a36Sopenharmony_ci * @vsi: ptr to VSI
614562306a36Sopenharmony_ci * @ena: flag to indicate the on/off setting
614662306a36Sopenharmony_ci */
614762306a36Sopenharmony_cistatic int ice_set_loopback(struct ice_vsi *vsi, bool ena)
614862306a36Sopenharmony_ci{
614962306a36Sopenharmony_ci	bool if_running = netif_running(vsi->netdev);
615062306a36Sopenharmony_ci	int ret;
615162306a36Sopenharmony_ci
615262306a36Sopenharmony_ci	if (if_running && !test_and_set_bit(ICE_VSI_DOWN, vsi->state)) {
615362306a36Sopenharmony_ci		ret = ice_down(vsi);
615462306a36Sopenharmony_ci		if (ret) {
615562306a36Sopenharmony_ci			netdev_err(vsi->netdev, "Preparing device to toggle loopback failed\n");
615662306a36Sopenharmony_ci			return ret;
615762306a36Sopenharmony_ci		}
615862306a36Sopenharmony_ci	}
615962306a36Sopenharmony_ci	ret = ice_aq_set_mac_loopback(&vsi->back->hw, ena, NULL);
616062306a36Sopenharmony_ci	if (ret)
616162306a36Sopenharmony_ci		netdev_err(vsi->netdev, "Failed to toggle loopback state\n");
616262306a36Sopenharmony_ci	if (if_running)
616362306a36Sopenharmony_ci		ret = ice_up(vsi);
616462306a36Sopenharmony_ci
616562306a36Sopenharmony_ci	return ret;
616662306a36Sopenharmony_ci}
616762306a36Sopenharmony_ci
616862306a36Sopenharmony_ci/**
616962306a36Sopenharmony_ci * ice_set_features - set the netdev feature flags
617062306a36Sopenharmony_ci * @netdev: ptr to the netdev being adjusted
617162306a36Sopenharmony_ci * @features: the feature set that the stack is suggesting
617262306a36Sopenharmony_ci */
617362306a36Sopenharmony_cistatic int
617462306a36Sopenharmony_ciice_set_features(struct net_device *netdev, netdev_features_t features)
617562306a36Sopenharmony_ci{
617662306a36Sopenharmony_ci	netdev_features_t changed = netdev->features ^ features;
617762306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
617862306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
617962306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
618062306a36Sopenharmony_ci	int ret = 0;
618162306a36Sopenharmony_ci
618262306a36Sopenharmony_ci	/* Don't set any netdev advanced features with device in Safe Mode */
618362306a36Sopenharmony_ci	if (ice_is_safe_mode(pf)) {
618462306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf),
618562306a36Sopenharmony_ci			"Device is in Safe Mode - not enabling advanced netdev features\n");
618662306a36Sopenharmony_ci		return ret;
618762306a36Sopenharmony_ci	}
618862306a36Sopenharmony_ci
618962306a36Sopenharmony_ci	/* Do not change setting during reset */
619062306a36Sopenharmony_ci	if (ice_is_reset_in_progress(pf->state)) {
619162306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf),
619262306a36Sopenharmony_ci			"Device is resetting, changing advanced netdev features temporarily unavailable.\n");
619362306a36Sopenharmony_ci		return -EBUSY;
619462306a36Sopenharmony_ci	}
619562306a36Sopenharmony_ci
619662306a36Sopenharmony_ci	/* Multiple features can be changed in one call so keep features in
619762306a36Sopenharmony_ci	 * separate if/else statements to guarantee each feature is checked
619862306a36Sopenharmony_ci	 */
619962306a36Sopenharmony_ci	if (changed & NETIF_F_RXHASH)
620062306a36Sopenharmony_ci		ice_vsi_manage_rss_lut(vsi, !!(features & NETIF_F_RXHASH));
620162306a36Sopenharmony_ci
620262306a36Sopenharmony_ci	ret = ice_set_vlan_features(netdev, features);
620362306a36Sopenharmony_ci	if (ret)
620462306a36Sopenharmony_ci		return ret;
620562306a36Sopenharmony_ci
620662306a36Sopenharmony_ci	/* Turn on receive of FCS aka CRC, and after setting this
620762306a36Sopenharmony_ci	 * flag the packet data will have the 4 byte CRC appended
620862306a36Sopenharmony_ci	 */
620962306a36Sopenharmony_ci	if (changed & NETIF_F_RXFCS) {
621062306a36Sopenharmony_ci		if ((features & NETIF_F_RXFCS) &&
621162306a36Sopenharmony_ci		    (features & NETIF_VLAN_STRIPPING_FEATURES)) {
621262306a36Sopenharmony_ci			dev_err(ice_pf_to_dev(vsi->back),
621362306a36Sopenharmony_ci				"To disable FCS/CRC stripping, you must first disable VLAN stripping\n");
621462306a36Sopenharmony_ci			return -EIO;
621562306a36Sopenharmony_ci		}
621662306a36Sopenharmony_ci
621762306a36Sopenharmony_ci		ice_vsi_cfg_crc_strip(vsi, !!(features & NETIF_F_RXFCS));
621862306a36Sopenharmony_ci		ret = ice_down_up(vsi);
621962306a36Sopenharmony_ci		if (ret)
622062306a36Sopenharmony_ci			return ret;
622162306a36Sopenharmony_ci	}
622262306a36Sopenharmony_ci
622362306a36Sopenharmony_ci	if (changed & NETIF_F_NTUPLE) {
622462306a36Sopenharmony_ci		bool ena = !!(features & NETIF_F_NTUPLE);
622562306a36Sopenharmony_ci
622662306a36Sopenharmony_ci		ice_vsi_manage_fdir(vsi, ena);
622762306a36Sopenharmony_ci		ena ? ice_init_arfs(vsi) : ice_clear_arfs(vsi);
622862306a36Sopenharmony_ci	}
622962306a36Sopenharmony_ci
623062306a36Sopenharmony_ci	/* don't turn off hw_tc_offload when ADQ is already enabled */
623162306a36Sopenharmony_ci	if (!(features & NETIF_F_HW_TC) && ice_is_adq_active(pf)) {
623262306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(pf), "ADQ is active, can't turn hw_tc_offload off\n");
623362306a36Sopenharmony_ci		return -EACCES;
623462306a36Sopenharmony_ci	}
623562306a36Sopenharmony_ci
623662306a36Sopenharmony_ci	if (changed & NETIF_F_HW_TC) {
623762306a36Sopenharmony_ci		bool ena = !!(features & NETIF_F_HW_TC);
623862306a36Sopenharmony_ci
623962306a36Sopenharmony_ci		ena ? set_bit(ICE_FLAG_CLS_FLOWER, pf->flags) :
624062306a36Sopenharmony_ci		      clear_bit(ICE_FLAG_CLS_FLOWER, pf->flags);
624162306a36Sopenharmony_ci	}
624262306a36Sopenharmony_ci
624362306a36Sopenharmony_ci	if (changed & NETIF_F_LOOPBACK)
624462306a36Sopenharmony_ci		ret = ice_set_loopback(vsi, !!(features & NETIF_F_LOOPBACK));
624562306a36Sopenharmony_ci
624662306a36Sopenharmony_ci	return ret;
624762306a36Sopenharmony_ci}
624862306a36Sopenharmony_ci
624962306a36Sopenharmony_ci/**
625062306a36Sopenharmony_ci * ice_vsi_vlan_setup - Setup VLAN offload properties on a PF VSI
625162306a36Sopenharmony_ci * @vsi: VSI to setup VLAN properties for
625262306a36Sopenharmony_ci */
625362306a36Sopenharmony_cistatic int ice_vsi_vlan_setup(struct ice_vsi *vsi)
625462306a36Sopenharmony_ci{
625562306a36Sopenharmony_ci	int err;
625662306a36Sopenharmony_ci
625762306a36Sopenharmony_ci	err = ice_set_vlan_offload_features(vsi, vsi->netdev->features);
625862306a36Sopenharmony_ci	if (err)
625962306a36Sopenharmony_ci		return err;
626062306a36Sopenharmony_ci
626162306a36Sopenharmony_ci	err = ice_set_vlan_filtering_features(vsi, vsi->netdev->features);
626262306a36Sopenharmony_ci	if (err)
626362306a36Sopenharmony_ci		return err;
626462306a36Sopenharmony_ci
626562306a36Sopenharmony_ci	return ice_vsi_add_vlan_zero(vsi);
626662306a36Sopenharmony_ci}
626762306a36Sopenharmony_ci
626862306a36Sopenharmony_ci/**
626962306a36Sopenharmony_ci * ice_vsi_cfg_lan - Setup the VSI lan related config
627062306a36Sopenharmony_ci * @vsi: the VSI being configured
627162306a36Sopenharmony_ci *
627262306a36Sopenharmony_ci * Return 0 on success and negative value on error
627362306a36Sopenharmony_ci */
627462306a36Sopenharmony_ciint ice_vsi_cfg_lan(struct ice_vsi *vsi)
627562306a36Sopenharmony_ci{
627662306a36Sopenharmony_ci	int err;
627762306a36Sopenharmony_ci
627862306a36Sopenharmony_ci	if (vsi->netdev && vsi->type == ICE_VSI_PF) {
627962306a36Sopenharmony_ci		ice_set_rx_mode(vsi->netdev);
628062306a36Sopenharmony_ci
628162306a36Sopenharmony_ci		err = ice_vsi_vlan_setup(vsi);
628262306a36Sopenharmony_ci		if (err)
628362306a36Sopenharmony_ci			return err;
628462306a36Sopenharmony_ci	}
628562306a36Sopenharmony_ci	ice_vsi_cfg_dcb_rings(vsi);
628662306a36Sopenharmony_ci
628762306a36Sopenharmony_ci	err = ice_vsi_cfg_lan_txqs(vsi);
628862306a36Sopenharmony_ci	if (!err && ice_is_xdp_ena_vsi(vsi))
628962306a36Sopenharmony_ci		err = ice_vsi_cfg_xdp_txqs(vsi);
629062306a36Sopenharmony_ci	if (!err)
629162306a36Sopenharmony_ci		err = ice_vsi_cfg_rxqs(vsi);
629262306a36Sopenharmony_ci
629362306a36Sopenharmony_ci	return err;
629462306a36Sopenharmony_ci}
629562306a36Sopenharmony_ci
629662306a36Sopenharmony_ci/* THEORY OF MODERATION:
629762306a36Sopenharmony_ci * The ice driver hardware works differently than the hardware that DIMLIB was
629862306a36Sopenharmony_ci * originally made for. ice hardware doesn't have packet count limits that
629962306a36Sopenharmony_ci * can trigger an interrupt, but it *does* have interrupt rate limit support,
630062306a36Sopenharmony_ci * which is hard-coded to a limit of 250,000 ints/second.
630162306a36Sopenharmony_ci * If not using dynamic moderation, the INTRL value can be modified
630262306a36Sopenharmony_ci * by ethtool rx-usecs-high.
630362306a36Sopenharmony_ci */
630462306a36Sopenharmony_cistruct ice_dim {
630562306a36Sopenharmony_ci	/* the throttle rate for interrupts, basically worst case delay before
630662306a36Sopenharmony_ci	 * an initial interrupt fires, value is stored in microseconds.
630762306a36Sopenharmony_ci	 */
630862306a36Sopenharmony_ci	u16 itr;
630962306a36Sopenharmony_ci};
631062306a36Sopenharmony_ci
631162306a36Sopenharmony_ci/* Make a different profile for Rx that doesn't allow quite so aggressive
631262306a36Sopenharmony_ci * moderation at the high end (it maxes out at 126us or about 8k interrupts a
631362306a36Sopenharmony_ci * second.
631462306a36Sopenharmony_ci */
631562306a36Sopenharmony_cistatic const struct ice_dim rx_profile[] = {
631662306a36Sopenharmony_ci	{2},    /* 500,000 ints/s, capped at 250K by INTRL */
631762306a36Sopenharmony_ci	{8},    /* 125,000 ints/s */
631862306a36Sopenharmony_ci	{16},   /*  62,500 ints/s */
631962306a36Sopenharmony_ci	{62},   /*  16,129 ints/s */
632062306a36Sopenharmony_ci	{126}   /*   7,936 ints/s */
632162306a36Sopenharmony_ci};
632262306a36Sopenharmony_ci
632362306a36Sopenharmony_ci/* The transmit profile, which has the same sorts of values
632462306a36Sopenharmony_ci * as the previous struct
632562306a36Sopenharmony_ci */
632662306a36Sopenharmony_cistatic const struct ice_dim tx_profile[] = {
632762306a36Sopenharmony_ci	{2},    /* 500,000 ints/s, capped at 250K by INTRL */
632862306a36Sopenharmony_ci	{8},    /* 125,000 ints/s */
632962306a36Sopenharmony_ci	{40},   /*  16,125 ints/s */
633062306a36Sopenharmony_ci	{128},  /*   7,812 ints/s */
633162306a36Sopenharmony_ci	{256}   /*   3,906 ints/s */
633262306a36Sopenharmony_ci};
633362306a36Sopenharmony_ci
633462306a36Sopenharmony_cistatic void ice_tx_dim_work(struct work_struct *work)
633562306a36Sopenharmony_ci{
633662306a36Sopenharmony_ci	struct ice_ring_container *rc;
633762306a36Sopenharmony_ci	struct dim *dim;
633862306a36Sopenharmony_ci	u16 itr;
633962306a36Sopenharmony_ci
634062306a36Sopenharmony_ci	dim = container_of(work, struct dim, work);
634162306a36Sopenharmony_ci	rc = dim->priv;
634262306a36Sopenharmony_ci
634362306a36Sopenharmony_ci	WARN_ON(dim->profile_ix >= ARRAY_SIZE(tx_profile));
634462306a36Sopenharmony_ci
634562306a36Sopenharmony_ci	/* look up the values in our local table */
634662306a36Sopenharmony_ci	itr = tx_profile[dim->profile_ix].itr;
634762306a36Sopenharmony_ci
634862306a36Sopenharmony_ci	ice_trace(tx_dim_work, container_of(rc, struct ice_q_vector, tx), dim);
634962306a36Sopenharmony_ci	ice_write_itr(rc, itr);
635062306a36Sopenharmony_ci
635162306a36Sopenharmony_ci	dim->state = DIM_START_MEASURE;
635262306a36Sopenharmony_ci}
635362306a36Sopenharmony_ci
635462306a36Sopenharmony_cistatic void ice_rx_dim_work(struct work_struct *work)
635562306a36Sopenharmony_ci{
635662306a36Sopenharmony_ci	struct ice_ring_container *rc;
635762306a36Sopenharmony_ci	struct dim *dim;
635862306a36Sopenharmony_ci	u16 itr;
635962306a36Sopenharmony_ci
636062306a36Sopenharmony_ci	dim = container_of(work, struct dim, work);
636162306a36Sopenharmony_ci	rc = dim->priv;
636262306a36Sopenharmony_ci
636362306a36Sopenharmony_ci	WARN_ON(dim->profile_ix >= ARRAY_SIZE(rx_profile));
636462306a36Sopenharmony_ci
636562306a36Sopenharmony_ci	/* look up the values in our local table */
636662306a36Sopenharmony_ci	itr = rx_profile[dim->profile_ix].itr;
636762306a36Sopenharmony_ci
636862306a36Sopenharmony_ci	ice_trace(rx_dim_work, container_of(rc, struct ice_q_vector, rx), dim);
636962306a36Sopenharmony_ci	ice_write_itr(rc, itr);
637062306a36Sopenharmony_ci
637162306a36Sopenharmony_ci	dim->state = DIM_START_MEASURE;
637262306a36Sopenharmony_ci}
637362306a36Sopenharmony_ci
637462306a36Sopenharmony_ci#define ICE_DIM_DEFAULT_PROFILE_IX 1
637562306a36Sopenharmony_ci
637662306a36Sopenharmony_ci/**
637762306a36Sopenharmony_ci * ice_init_moderation - set up interrupt moderation
637862306a36Sopenharmony_ci * @q_vector: the vector containing rings to be configured
637962306a36Sopenharmony_ci *
638062306a36Sopenharmony_ci * Set up interrupt moderation registers, with the intent to do the right thing
638162306a36Sopenharmony_ci * when called from reset or from probe, and whether or not dynamic moderation
638262306a36Sopenharmony_ci * is enabled or not. Take special care to write all the registers in both
638362306a36Sopenharmony_ci * dynamic moderation mode or not in order to make sure hardware is in a known
638462306a36Sopenharmony_ci * state.
638562306a36Sopenharmony_ci */
638662306a36Sopenharmony_cistatic void ice_init_moderation(struct ice_q_vector *q_vector)
638762306a36Sopenharmony_ci{
638862306a36Sopenharmony_ci	struct ice_ring_container *rc;
638962306a36Sopenharmony_ci	bool tx_dynamic, rx_dynamic;
639062306a36Sopenharmony_ci
639162306a36Sopenharmony_ci	rc = &q_vector->tx;
639262306a36Sopenharmony_ci	INIT_WORK(&rc->dim.work, ice_tx_dim_work);
639362306a36Sopenharmony_ci	rc->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
639462306a36Sopenharmony_ci	rc->dim.profile_ix = ICE_DIM_DEFAULT_PROFILE_IX;
639562306a36Sopenharmony_ci	rc->dim.priv = rc;
639662306a36Sopenharmony_ci	tx_dynamic = ITR_IS_DYNAMIC(rc);
639762306a36Sopenharmony_ci
639862306a36Sopenharmony_ci	/* set the initial TX ITR to match the above */
639962306a36Sopenharmony_ci	ice_write_itr(rc, tx_dynamic ?
640062306a36Sopenharmony_ci		      tx_profile[rc->dim.profile_ix].itr : rc->itr_setting);
640162306a36Sopenharmony_ci
640262306a36Sopenharmony_ci	rc = &q_vector->rx;
640362306a36Sopenharmony_ci	INIT_WORK(&rc->dim.work, ice_rx_dim_work);
640462306a36Sopenharmony_ci	rc->dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
640562306a36Sopenharmony_ci	rc->dim.profile_ix = ICE_DIM_DEFAULT_PROFILE_IX;
640662306a36Sopenharmony_ci	rc->dim.priv = rc;
640762306a36Sopenharmony_ci	rx_dynamic = ITR_IS_DYNAMIC(rc);
640862306a36Sopenharmony_ci
640962306a36Sopenharmony_ci	/* set the initial RX ITR to match the above */
641062306a36Sopenharmony_ci	ice_write_itr(rc, rx_dynamic ? rx_profile[rc->dim.profile_ix].itr :
641162306a36Sopenharmony_ci				       rc->itr_setting);
641262306a36Sopenharmony_ci
641362306a36Sopenharmony_ci	ice_set_q_vector_intrl(q_vector);
641462306a36Sopenharmony_ci}
641562306a36Sopenharmony_ci
641662306a36Sopenharmony_ci/**
641762306a36Sopenharmony_ci * ice_napi_enable_all - Enable NAPI for all q_vectors in the VSI
641862306a36Sopenharmony_ci * @vsi: the VSI being configured
641962306a36Sopenharmony_ci */
642062306a36Sopenharmony_cistatic void ice_napi_enable_all(struct ice_vsi *vsi)
642162306a36Sopenharmony_ci{
642262306a36Sopenharmony_ci	int q_idx;
642362306a36Sopenharmony_ci
642462306a36Sopenharmony_ci	if (!vsi->netdev)
642562306a36Sopenharmony_ci		return;
642662306a36Sopenharmony_ci
642762306a36Sopenharmony_ci	ice_for_each_q_vector(vsi, q_idx) {
642862306a36Sopenharmony_ci		struct ice_q_vector *q_vector = vsi->q_vectors[q_idx];
642962306a36Sopenharmony_ci
643062306a36Sopenharmony_ci		ice_init_moderation(q_vector);
643162306a36Sopenharmony_ci
643262306a36Sopenharmony_ci		if (q_vector->rx.rx_ring || q_vector->tx.tx_ring)
643362306a36Sopenharmony_ci			napi_enable(&q_vector->napi);
643462306a36Sopenharmony_ci	}
643562306a36Sopenharmony_ci}
643662306a36Sopenharmony_ci
643762306a36Sopenharmony_ci/**
643862306a36Sopenharmony_ci * ice_up_complete - Finish the last steps of bringing up a connection
643962306a36Sopenharmony_ci * @vsi: The VSI being configured
644062306a36Sopenharmony_ci *
644162306a36Sopenharmony_ci * Return 0 on success and negative value on error
644262306a36Sopenharmony_ci */
644362306a36Sopenharmony_cistatic int ice_up_complete(struct ice_vsi *vsi)
644462306a36Sopenharmony_ci{
644562306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
644662306a36Sopenharmony_ci	int err;
644762306a36Sopenharmony_ci
644862306a36Sopenharmony_ci	ice_vsi_cfg_msix(vsi);
644962306a36Sopenharmony_ci
645062306a36Sopenharmony_ci	/* Enable only Rx rings, Tx rings were enabled by the FW when the
645162306a36Sopenharmony_ci	 * Tx queue group list was configured and the context bits were
645262306a36Sopenharmony_ci	 * programmed using ice_vsi_cfg_txqs
645362306a36Sopenharmony_ci	 */
645462306a36Sopenharmony_ci	err = ice_vsi_start_all_rx_rings(vsi);
645562306a36Sopenharmony_ci	if (err)
645662306a36Sopenharmony_ci		return err;
645762306a36Sopenharmony_ci
645862306a36Sopenharmony_ci	clear_bit(ICE_VSI_DOWN, vsi->state);
645962306a36Sopenharmony_ci	ice_napi_enable_all(vsi);
646062306a36Sopenharmony_ci	ice_vsi_ena_irq(vsi);
646162306a36Sopenharmony_ci
646262306a36Sopenharmony_ci	if (vsi->port_info &&
646362306a36Sopenharmony_ci	    (vsi->port_info->phy.link_info.link_info & ICE_AQ_LINK_UP) &&
646462306a36Sopenharmony_ci	    vsi->netdev && vsi->type == ICE_VSI_PF) {
646562306a36Sopenharmony_ci		ice_print_link_msg(vsi, true);
646662306a36Sopenharmony_ci		netif_tx_start_all_queues(vsi->netdev);
646762306a36Sopenharmony_ci		netif_carrier_on(vsi->netdev);
646862306a36Sopenharmony_ci		ice_ptp_link_change(pf, pf->hw.pf_id, true);
646962306a36Sopenharmony_ci	}
647062306a36Sopenharmony_ci
647162306a36Sopenharmony_ci	/* Perform an initial read of the statistics registers now to
647262306a36Sopenharmony_ci	 * set the baseline so counters are ready when interface is up
647362306a36Sopenharmony_ci	 */
647462306a36Sopenharmony_ci	ice_update_eth_stats(vsi);
647562306a36Sopenharmony_ci
647662306a36Sopenharmony_ci	if (vsi->type == ICE_VSI_PF)
647762306a36Sopenharmony_ci		ice_service_task_schedule(pf);
647862306a36Sopenharmony_ci
647962306a36Sopenharmony_ci	return 0;
648062306a36Sopenharmony_ci}
648162306a36Sopenharmony_ci
648262306a36Sopenharmony_ci/**
648362306a36Sopenharmony_ci * ice_up - Bring the connection back up after being down
648462306a36Sopenharmony_ci * @vsi: VSI being configured
648562306a36Sopenharmony_ci */
648662306a36Sopenharmony_ciint ice_up(struct ice_vsi *vsi)
648762306a36Sopenharmony_ci{
648862306a36Sopenharmony_ci	int err;
648962306a36Sopenharmony_ci
649062306a36Sopenharmony_ci	err = ice_vsi_cfg_lan(vsi);
649162306a36Sopenharmony_ci	if (!err)
649262306a36Sopenharmony_ci		err = ice_up_complete(vsi);
649362306a36Sopenharmony_ci
649462306a36Sopenharmony_ci	return err;
649562306a36Sopenharmony_ci}
649662306a36Sopenharmony_ci
649762306a36Sopenharmony_ci/**
649862306a36Sopenharmony_ci * ice_fetch_u64_stats_per_ring - get packets and bytes stats per ring
649962306a36Sopenharmony_ci * @syncp: pointer to u64_stats_sync
650062306a36Sopenharmony_ci * @stats: stats that pkts and bytes count will be taken from
650162306a36Sopenharmony_ci * @pkts: packets stats counter
650262306a36Sopenharmony_ci * @bytes: bytes stats counter
650362306a36Sopenharmony_ci *
650462306a36Sopenharmony_ci * This function fetches stats from the ring considering the atomic operations
650562306a36Sopenharmony_ci * that needs to be performed to read u64 values in 32 bit machine.
650662306a36Sopenharmony_ci */
650762306a36Sopenharmony_civoid
650862306a36Sopenharmony_ciice_fetch_u64_stats_per_ring(struct u64_stats_sync *syncp,
650962306a36Sopenharmony_ci			     struct ice_q_stats stats, u64 *pkts, u64 *bytes)
651062306a36Sopenharmony_ci{
651162306a36Sopenharmony_ci	unsigned int start;
651262306a36Sopenharmony_ci
651362306a36Sopenharmony_ci	do {
651462306a36Sopenharmony_ci		start = u64_stats_fetch_begin(syncp);
651562306a36Sopenharmony_ci		*pkts = stats.pkts;
651662306a36Sopenharmony_ci		*bytes = stats.bytes;
651762306a36Sopenharmony_ci	} while (u64_stats_fetch_retry(syncp, start));
651862306a36Sopenharmony_ci}
651962306a36Sopenharmony_ci
652062306a36Sopenharmony_ci/**
652162306a36Sopenharmony_ci * ice_update_vsi_tx_ring_stats - Update VSI Tx ring stats counters
652262306a36Sopenharmony_ci * @vsi: the VSI to be updated
652362306a36Sopenharmony_ci * @vsi_stats: the stats struct to be updated
652462306a36Sopenharmony_ci * @rings: rings to work on
652562306a36Sopenharmony_ci * @count: number of rings
652662306a36Sopenharmony_ci */
652762306a36Sopenharmony_cistatic void
652862306a36Sopenharmony_ciice_update_vsi_tx_ring_stats(struct ice_vsi *vsi,
652962306a36Sopenharmony_ci			     struct rtnl_link_stats64 *vsi_stats,
653062306a36Sopenharmony_ci			     struct ice_tx_ring **rings, u16 count)
653162306a36Sopenharmony_ci{
653262306a36Sopenharmony_ci	u16 i;
653362306a36Sopenharmony_ci
653462306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
653562306a36Sopenharmony_ci		struct ice_tx_ring *ring;
653662306a36Sopenharmony_ci		u64 pkts = 0, bytes = 0;
653762306a36Sopenharmony_ci
653862306a36Sopenharmony_ci		ring = READ_ONCE(rings[i]);
653962306a36Sopenharmony_ci		if (!ring || !ring->ring_stats)
654062306a36Sopenharmony_ci			continue;
654162306a36Sopenharmony_ci		ice_fetch_u64_stats_per_ring(&ring->ring_stats->syncp,
654262306a36Sopenharmony_ci					     ring->ring_stats->stats, &pkts,
654362306a36Sopenharmony_ci					     &bytes);
654462306a36Sopenharmony_ci		vsi_stats->tx_packets += pkts;
654562306a36Sopenharmony_ci		vsi_stats->tx_bytes += bytes;
654662306a36Sopenharmony_ci		vsi->tx_restart += ring->ring_stats->tx_stats.restart_q;
654762306a36Sopenharmony_ci		vsi->tx_busy += ring->ring_stats->tx_stats.tx_busy;
654862306a36Sopenharmony_ci		vsi->tx_linearize += ring->ring_stats->tx_stats.tx_linearize;
654962306a36Sopenharmony_ci	}
655062306a36Sopenharmony_ci}
655162306a36Sopenharmony_ci
655262306a36Sopenharmony_ci/**
655362306a36Sopenharmony_ci * ice_update_vsi_ring_stats - Update VSI stats counters
655462306a36Sopenharmony_ci * @vsi: the VSI to be updated
655562306a36Sopenharmony_ci */
655662306a36Sopenharmony_cistatic void ice_update_vsi_ring_stats(struct ice_vsi *vsi)
655762306a36Sopenharmony_ci{
655862306a36Sopenharmony_ci	struct rtnl_link_stats64 *net_stats, *stats_prev;
655962306a36Sopenharmony_ci	struct rtnl_link_stats64 *vsi_stats;
656062306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
656162306a36Sopenharmony_ci	u64 pkts, bytes;
656262306a36Sopenharmony_ci	int i;
656362306a36Sopenharmony_ci
656462306a36Sopenharmony_ci	vsi_stats = kzalloc(sizeof(*vsi_stats), GFP_ATOMIC);
656562306a36Sopenharmony_ci	if (!vsi_stats)
656662306a36Sopenharmony_ci		return;
656762306a36Sopenharmony_ci
656862306a36Sopenharmony_ci	/* reset non-netdev (extended) stats */
656962306a36Sopenharmony_ci	vsi->tx_restart = 0;
657062306a36Sopenharmony_ci	vsi->tx_busy = 0;
657162306a36Sopenharmony_ci	vsi->tx_linearize = 0;
657262306a36Sopenharmony_ci	vsi->rx_buf_failed = 0;
657362306a36Sopenharmony_ci	vsi->rx_page_failed = 0;
657462306a36Sopenharmony_ci
657562306a36Sopenharmony_ci	rcu_read_lock();
657662306a36Sopenharmony_ci
657762306a36Sopenharmony_ci	/* update Tx rings counters */
657862306a36Sopenharmony_ci	ice_update_vsi_tx_ring_stats(vsi, vsi_stats, vsi->tx_rings,
657962306a36Sopenharmony_ci				     vsi->num_txq);
658062306a36Sopenharmony_ci
658162306a36Sopenharmony_ci	/* update Rx rings counters */
658262306a36Sopenharmony_ci	ice_for_each_rxq(vsi, i) {
658362306a36Sopenharmony_ci		struct ice_rx_ring *ring = READ_ONCE(vsi->rx_rings[i]);
658462306a36Sopenharmony_ci		struct ice_ring_stats *ring_stats;
658562306a36Sopenharmony_ci
658662306a36Sopenharmony_ci		ring_stats = ring->ring_stats;
658762306a36Sopenharmony_ci		ice_fetch_u64_stats_per_ring(&ring_stats->syncp,
658862306a36Sopenharmony_ci					     ring_stats->stats, &pkts,
658962306a36Sopenharmony_ci					     &bytes);
659062306a36Sopenharmony_ci		vsi_stats->rx_packets += pkts;
659162306a36Sopenharmony_ci		vsi_stats->rx_bytes += bytes;
659262306a36Sopenharmony_ci		vsi->rx_buf_failed += ring_stats->rx_stats.alloc_buf_failed;
659362306a36Sopenharmony_ci		vsi->rx_page_failed += ring_stats->rx_stats.alloc_page_failed;
659462306a36Sopenharmony_ci	}
659562306a36Sopenharmony_ci
659662306a36Sopenharmony_ci	/* update XDP Tx rings counters */
659762306a36Sopenharmony_ci	if (ice_is_xdp_ena_vsi(vsi))
659862306a36Sopenharmony_ci		ice_update_vsi_tx_ring_stats(vsi, vsi_stats, vsi->xdp_rings,
659962306a36Sopenharmony_ci					     vsi->num_xdp_txq);
660062306a36Sopenharmony_ci
660162306a36Sopenharmony_ci	rcu_read_unlock();
660262306a36Sopenharmony_ci
660362306a36Sopenharmony_ci	net_stats = &vsi->net_stats;
660462306a36Sopenharmony_ci	stats_prev = &vsi->net_stats_prev;
660562306a36Sopenharmony_ci
660662306a36Sopenharmony_ci	/* Update netdev counters, but keep in mind that values could start at
660762306a36Sopenharmony_ci	 * random value after PF reset. And as we increase the reported stat by
660862306a36Sopenharmony_ci	 * diff of Prev-Cur, we need to be sure that Prev is valid. If it's not,
660962306a36Sopenharmony_ci	 * let's skip this round.
661062306a36Sopenharmony_ci	 */
661162306a36Sopenharmony_ci	if (likely(pf->stat_prev_loaded)) {
661262306a36Sopenharmony_ci		net_stats->tx_packets += vsi_stats->tx_packets - stats_prev->tx_packets;
661362306a36Sopenharmony_ci		net_stats->tx_bytes += vsi_stats->tx_bytes - stats_prev->tx_bytes;
661462306a36Sopenharmony_ci		net_stats->rx_packets += vsi_stats->rx_packets - stats_prev->rx_packets;
661562306a36Sopenharmony_ci		net_stats->rx_bytes += vsi_stats->rx_bytes - stats_prev->rx_bytes;
661662306a36Sopenharmony_ci	}
661762306a36Sopenharmony_ci
661862306a36Sopenharmony_ci	stats_prev->tx_packets = vsi_stats->tx_packets;
661962306a36Sopenharmony_ci	stats_prev->tx_bytes = vsi_stats->tx_bytes;
662062306a36Sopenharmony_ci	stats_prev->rx_packets = vsi_stats->rx_packets;
662162306a36Sopenharmony_ci	stats_prev->rx_bytes = vsi_stats->rx_bytes;
662262306a36Sopenharmony_ci
662362306a36Sopenharmony_ci	kfree(vsi_stats);
662462306a36Sopenharmony_ci}
662562306a36Sopenharmony_ci
662662306a36Sopenharmony_ci/**
662762306a36Sopenharmony_ci * ice_update_vsi_stats - Update VSI stats counters
662862306a36Sopenharmony_ci * @vsi: the VSI to be updated
662962306a36Sopenharmony_ci */
663062306a36Sopenharmony_civoid ice_update_vsi_stats(struct ice_vsi *vsi)
663162306a36Sopenharmony_ci{
663262306a36Sopenharmony_ci	struct rtnl_link_stats64 *cur_ns = &vsi->net_stats;
663362306a36Sopenharmony_ci	struct ice_eth_stats *cur_es = &vsi->eth_stats;
663462306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
663562306a36Sopenharmony_ci
663662306a36Sopenharmony_ci	if (test_bit(ICE_VSI_DOWN, vsi->state) ||
663762306a36Sopenharmony_ci	    test_bit(ICE_CFG_BUSY, pf->state))
663862306a36Sopenharmony_ci		return;
663962306a36Sopenharmony_ci
664062306a36Sopenharmony_ci	/* get stats as recorded by Tx/Rx rings */
664162306a36Sopenharmony_ci	ice_update_vsi_ring_stats(vsi);
664262306a36Sopenharmony_ci
664362306a36Sopenharmony_ci	/* get VSI stats as recorded by the hardware */
664462306a36Sopenharmony_ci	ice_update_eth_stats(vsi);
664562306a36Sopenharmony_ci
664662306a36Sopenharmony_ci	cur_ns->tx_errors = cur_es->tx_errors;
664762306a36Sopenharmony_ci	cur_ns->rx_dropped = cur_es->rx_discards;
664862306a36Sopenharmony_ci	cur_ns->tx_dropped = cur_es->tx_discards;
664962306a36Sopenharmony_ci	cur_ns->multicast = cur_es->rx_multicast;
665062306a36Sopenharmony_ci
665162306a36Sopenharmony_ci	/* update some more netdev stats if this is main VSI */
665262306a36Sopenharmony_ci	if (vsi->type == ICE_VSI_PF) {
665362306a36Sopenharmony_ci		cur_ns->rx_crc_errors = pf->stats.crc_errors;
665462306a36Sopenharmony_ci		cur_ns->rx_errors = pf->stats.crc_errors +
665562306a36Sopenharmony_ci				    pf->stats.illegal_bytes +
665662306a36Sopenharmony_ci				    pf->stats.rx_len_errors +
665762306a36Sopenharmony_ci				    pf->stats.rx_undersize +
665862306a36Sopenharmony_ci				    pf->hw_csum_rx_error +
665962306a36Sopenharmony_ci				    pf->stats.rx_jabber +
666062306a36Sopenharmony_ci				    pf->stats.rx_fragments +
666162306a36Sopenharmony_ci				    pf->stats.rx_oversize;
666262306a36Sopenharmony_ci		cur_ns->rx_length_errors = pf->stats.rx_len_errors;
666362306a36Sopenharmony_ci		/* record drops from the port level */
666462306a36Sopenharmony_ci		cur_ns->rx_missed_errors = pf->stats.eth.rx_discards;
666562306a36Sopenharmony_ci	}
666662306a36Sopenharmony_ci}
666762306a36Sopenharmony_ci
666862306a36Sopenharmony_ci/**
666962306a36Sopenharmony_ci * ice_update_pf_stats - Update PF port stats counters
667062306a36Sopenharmony_ci * @pf: PF whose stats needs to be updated
667162306a36Sopenharmony_ci */
667262306a36Sopenharmony_civoid ice_update_pf_stats(struct ice_pf *pf)
667362306a36Sopenharmony_ci{
667462306a36Sopenharmony_ci	struct ice_hw_port_stats *prev_ps, *cur_ps;
667562306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
667662306a36Sopenharmony_ci	u16 fd_ctr_base;
667762306a36Sopenharmony_ci	u8 port;
667862306a36Sopenharmony_ci
667962306a36Sopenharmony_ci	port = hw->port_info->lport;
668062306a36Sopenharmony_ci	prev_ps = &pf->stats_prev;
668162306a36Sopenharmony_ci	cur_ps = &pf->stats;
668262306a36Sopenharmony_ci
668362306a36Sopenharmony_ci	if (ice_is_reset_in_progress(pf->state))
668462306a36Sopenharmony_ci		pf->stat_prev_loaded = false;
668562306a36Sopenharmony_ci
668662306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_GORCL(port), pf->stat_prev_loaded,
668762306a36Sopenharmony_ci			  &prev_ps->eth.rx_bytes,
668862306a36Sopenharmony_ci			  &cur_ps->eth.rx_bytes);
668962306a36Sopenharmony_ci
669062306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_UPRCL(port), pf->stat_prev_loaded,
669162306a36Sopenharmony_ci			  &prev_ps->eth.rx_unicast,
669262306a36Sopenharmony_ci			  &cur_ps->eth.rx_unicast);
669362306a36Sopenharmony_ci
669462306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_MPRCL(port), pf->stat_prev_loaded,
669562306a36Sopenharmony_ci			  &prev_ps->eth.rx_multicast,
669662306a36Sopenharmony_ci			  &cur_ps->eth.rx_multicast);
669762306a36Sopenharmony_ci
669862306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_BPRCL(port), pf->stat_prev_loaded,
669962306a36Sopenharmony_ci			  &prev_ps->eth.rx_broadcast,
670062306a36Sopenharmony_ci			  &cur_ps->eth.rx_broadcast);
670162306a36Sopenharmony_ci
670262306a36Sopenharmony_ci	ice_stat_update32(hw, PRTRPB_RDPC, pf->stat_prev_loaded,
670362306a36Sopenharmony_ci			  &prev_ps->eth.rx_discards,
670462306a36Sopenharmony_ci			  &cur_ps->eth.rx_discards);
670562306a36Sopenharmony_ci
670662306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_GOTCL(port), pf->stat_prev_loaded,
670762306a36Sopenharmony_ci			  &prev_ps->eth.tx_bytes,
670862306a36Sopenharmony_ci			  &cur_ps->eth.tx_bytes);
670962306a36Sopenharmony_ci
671062306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_UPTCL(port), pf->stat_prev_loaded,
671162306a36Sopenharmony_ci			  &prev_ps->eth.tx_unicast,
671262306a36Sopenharmony_ci			  &cur_ps->eth.tx_unicast);
671362306a36Sopenharmony_ci
671462306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_MPTCL(port), pf->stat_prev_loaded,
671562306a36Sopenharmony_ci			  &prev_ps->eth.tx_multicast,
671662306a36Sopenharmony_ci			  &cur_ps->eth.tx_multicast);
671762306a36Sopenharmony_ci
671862306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_BPTCL(port), pf->stat_prev_loaded,
671962306a36Sopenharmony_ci			  &prev_ps->eth.tx_broadcast,
672062306a36Sopenharmony_ci			  &cur_ps->eth.tx_broadcast);
672162306a36Sopenharmony_ci
672262306a36Sopenharmony_ci	ice_stat_update32(hw, GLPRT_TDOLD(port), pf->stat_prev_loaded,
672362306a36Sopenharmony_ci			  &prev_ps->tx_dropped_link_down,
672462306a36Sopenharmony_ci			  &cur_ps->tx_dropped_link_down);
672562306a36Sopenharmony_ci
672662306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_PRC64L(port), pf->stat_prev_loaded,
672762306a36Sopenharmony_ci			  &prev_ps->rx_size_64, &cur_ps->rx_size_64);
672862306a36Sopenharmony_ci
672962306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_PRC127L(port), pf->stat_prev_loaded,
673062306a36Sopenharmony_ci			  &prev_ps->rx_size_127, &cur_ps->rx_size_127);
673162306a36Sopenharmony_ci
673262306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_PRC255L(port), pf->stat_prev_loaded,
673362306a36Sopenharmony_ci			  &prev_ps->rx_size_255, &cur_ps->rx_size_255);
673462306a36Sopenharmony_ci
673562306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_PRC511L(port), pf->stat_prev_loaded,
673662306a36Sopenharmony_ci			  &prev_ps->rx_size_511, &cur_ps->rx_size_511);
673762306a36Sopenharmony_ci
673862306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_PRC1023L(port), pf->stat_prev_loaded,
673962306a36Sopenharmony_ci			  &prev_ps->rx_size_1023, &cur_ps->rx_size_1023);
674062306a36Sopenharmony_ci
674162306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_PRC1522L(port), pf->stat_prev_loaded,
674262306a36Sopenharmony_ci			  &prev_ps->rx_size_1522, &cur_ps->rx_size_1522);
674362306a36Sopenharmony_ci
674462306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_PRC9522L(port), pf->stat_prev_loaded,
674562306a36Sopenharmony_ci			  &prev_ps->rx_size_big, &cur_ps->rx_size_big);
674662306a36Sopenharmony_ci
674762306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_PTC64L(port), pf->stat_prev_loaded,
674862306a36Sopenharmony_ci			  &prev_ps->tx_size_64, &cur_ps->tx_size_64);
674962306a36Sopenharmony_ci
675062306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_PTC127L(port), pf->stat_prev_loaded,
675162306a36Sopenharmony_ci			  &prev_ps->tx_size_127, &cur_ps->tx_size_127);
675262306a36Sopenharmony_ci
675362306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_PTC255L(port), pf->stat_prev_loaded,
675462306a36Sopenharmony_ci			  &prev_ps->tx_size_255, &cur_ps->tx_size_255);
675562306a36Sopenharmony_ci
675662306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_PTC511L(port), pf->stat_prev_loaded,
675762306a36Sopenharmony_ci			  &prev_ps->tx_size_511, &cur_ps->tx_size_511);
675862306a36Sopenharmony_ci
675962306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_PTC1023L(port), pf->stat_prev_loaded,
676062306a36Sopenharmony_ci			  &prev_ps->tx_size_1023, &cur_ps->tx_size_1023);
676162306a36Sopenharmony_ci
676262306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_PTC1522L(port), pf->stat_prev_loaded,
676362306a36Sopenharmony_ci			  &prev_ps->tx_size_1522, &cur_ps->tx_size_1522);
676462306a36Sopenharmony_ci
676562306a36Sopenharmony_ci	ice_stat_update40(hw, GLPRT_PTC9522L(port), pf->stat_prev_loaded,
676662306a36Sopenharmony_ci			  &prev_ps->tx_size_big, &cur_ps->tx_size_big);
676762306a36Sopenharmony_ci
676862306a36Sopenharmony_ci	fd_ctr_base = hw->fd_ctr_base;
676962306a36Sopenharmony_ci
677062306a36Sopenharmony_ci	ice_stat_update40(hw,
677162306a36Sopenharmony_ci			  GLSTAT_FD_CNT0L(ICE_FD_SB_STAT_IDX(fd_ctr_base)),
677262306a36Sopenharmony_ci			  pf->stat_prev_loaded, &prev_ps->fd_sb_match,
677362306a36Sopenharmony_ci			  &cur_ps->fd_sb_match);
677462306a36Sopenharmony_ci	ice_stat_update32(hw, GLPRT_LXONRXC(port), pf->stat_prev_loaded,
677562306a36Sopenharmony_ci			  &prev_ps->link_xon_rx, &cur_ps->link_xon_rx);
677662306a36Sopenharmony_ci
677762306a36Sopenharmony_ci	ice_stat_update32(hw, GLPRT_LXOFFRXC(port), pf->stat_prev_loaded,
677862306a36Sopenharmony_ci			  &prev_ps->link_xoff_rx, &cur_ps->link_xoff_rx);
677962306a36Sopenharmony_ci
678062306a36Sopenharmony_ci	ice_stat_update32(hw, GLPRT_LXONTXC(port), pf->stat_prev_loaded,
678162306a36Sopenharmony_ci			  &prev_ps->link_xon_tx, &cur_ps->link_xon_tx);
678262306a36Sopenharmony_ci
678362306a36Sopenharmony_ci	ice_stat_update32(hw, GLPRT_LXOFFTXC(port), pf->stat_prev_loaded,
678462306a36Sopenharmony_ci			  &prev_ps->link_xoff_tx, &cur_ps->link_xoff_tx);
678562306a36Sopenharmony_ci
678662306a36Sopenharmony_ci	ice_update_dcb_stats(pf);
678762306a36Sopenharmony_ci
678862306a36Sopenharmony_ci	ice_stat_update32(hw, GLPRT_CRCERRS(port), pf->stat_prev_loaded,
678962306a36Sopenharmony_ci			  &prev_ps->crc_errors, &cur_ps->crc_errors);
679062306a36Sopenharmony_ci
679162306a36Sopenharmony_ci	ice_stat_update32(hw, GLPRT_ILLERRC(port), pf->stat_prev_loaded,
679262306a36Sopenharmony_ci			  &prev_ps->illegal_bytes, &cur_ps->illegal_bytes);
679362306a36Sopenharmony_ci
679462306a36Sopenharmony_ci	ice_stat_update32(hw, GLPRT_MLFC(port), pf->stat_prev_loaded,
679562306a36Sopenharmony_ci			  &prev_ps->mac_local_faults,
679662306a36Sopenharmony_ci			  &cur_ps->mac_local_faults);
679762306a36Sopenharmony_ci
679862306a36Sopenharmony_ci	ice_stat_update32(hw, GLPRT_MRFC(port), pf->stat_prev_loaded,
679962306a36Sopenharmony_ci			  &prev_ps->mac_remote_faults,
680062306a36Sopenharmony_ci			  &cur_ps->mac_remote_faults);
680162306a36Sopenharmony_ci
680262306a36Sopenharmony_ci	ice_stat_update32(hw, GLPRT_RLEC(port), pf->stat_prev_loaded,
680362306a36Sopenharmony_ci			  &prev_ps->rx_len_errors, &cur_ps->rx_len_errors);
680462306a36Sopenharmony_ci
680562306a36Sopenharmony_ci	ice_stat_update32(hw, GLPRT_RUC(port), pf->stat_prev_loaded,
680662306a36Sopenharmony_ci			  &prev_ps->rx_undersize, &cur_ps->rx_undersize);
680762306a36Sopenharmony_ci
680862306a36Sopenharmony_ci	ice_stat_update32(hw, GLPRT_RFC(port), pf->stat_prev_loaded,
680962306a36Sopenharmony_ci			  &prev_ps->rx_fragments, &cur_ps->rx_fragments);
681062306a36Sopenharmony_ci
681162306a36Sopenharmony_ci	ice_stat_update32(hw, GLPRT_ROC(port), pf->stat_prev_loaded,
681262306a36Sopenharmony_ci			  &prev_ps->rx_oversize, &cur_ps->rx_oversize);
681362306a36Sopenharmony_ci
681462306a36Sopenharmony_ci	ice_stat_update32(hw, GLPRT_RJC(port), pf->stat_prev_loaded,
681562306a36Sopenharmony_ci			  &prev_ps->rx_jabber, &cur_ps->rx_jabber);
681662306a36Sopenharmony_ci
681762306a36Sopenharmony_ci	cur_ps->fd_sb_status = test_bit(ICE_FLAG_FD_ENA, pf->flags) ? 1 : 0;
681862306a36Sopenharmony_ci
681962306a36Sopenharmony_ci	pf->stat_prev_loaded = true;
682062306a36Sopenharmony_ci}
682162306a36Sopenharmony_ci
682262306a36Sopenharmony_ci/**
682362306a36Sopenharmony_ci * ice_get_stats64 - get statistics for network device structure
682462306a36Sopenharmony_ci * @netdev: network interface device structure
682562306a36Sopenharmony_ci * @stats: main device statistics structure
682662306a36Sopenharmony_ci */
682762306a36Sopenharmony_cistatic
682862306a36Sopenharmony_civoid ice_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats)
682962306a36Sopenharmony_ci{
683062306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
683162306a36Sopenharmony_ci	struct rtnl_link_stats64 *vsi_stats;
683262306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
683362306a36Sopenharmony_ci
683462306a36Sopenharmony_ci	vsi_stats = &vsi->net_stats;
683562306a36Sopenharmony_ci
683662306a36Sopenharmony_ci	if (!vsi->num_txq || !vsi->num_rxq)
683762306a36Sopenharmony_ci		return;
683862306a36Sopenharmony_ci
683962306a36Sopenharmony_ci	/* netdev packet/byte stats come from ring counter. These are obtained
684062306a36Sopenharmony_ci	 * by summing up ring counters (done by ice_update_vsi_ring_stats).
684162306a36Sopenharmony_ci	 * But, only call the update routine and read the registers if VSI is
684262306a36Sopenharmony_ci	 * not down.
684362306a36Sopenharmony_ci	 */
684462306a36Sopenharmony_ci	if (!test_bit(ICE_VSI_DOWN, vsi->state))
684562306a36Sopenharmony_ci		ice_update_vsi_ring_stats(vsi);
684662306a36Sopenharmony_ci	stats->tx_packets = vsi_stats->tx_packets;
684762306a36Sopenharmony_ci	stats->tx_bytes = vsi_stats->tx_bytes;
684862306a36Sopenharmony_ci	stats->rx_packets = vsi_stats->rx_packets;
684962306a36Sopenharmony_ci	stats->rx_bytes = vsi_stats->rx_bytes;
685062306a36Sopenharmony_ci
685162306a36Sopenharmony_ci	/* The rest of the stats can be read from the hardware but instead we
685262306a36Sopenharmony_ci	 * just return values that the watchdog task has already obtained from
685362306a36Sopenharmony_ci	 * the hardware.
685462306a36Sopenharmony_ci	 */
685562306a36Sopenharmony_ci	stats->multicast = vsi_stats->multicast;
685662306a36Sopenharmony_ci	stats->tx_errors = vsi_stats->tx_errors;
685762306a36Sopenharmony_ci	stats->tx_dropped = vsi_stats->tx_dropped;
685862306a36Sopenharmony_ci	stats->rx_errors = vsi_stats->rx_errors;
685962306a36Sopenharmony_ci	stats->rx_dropped = vsi_stats->rx_dropped;
686062306a36Sopenharmony_ci	stats->rx_crc_errors = vsi_stats->rx_crc_errors;
686162306a36Sopenharmony_ci	stats->rx_length_errors = vsi_stats->rx_length_errors;
686262306a36Sopenharmony_ci}
686362306a36Sopenharmony_ci
686462306a36Sopenharmony_ci/**
686562306a36Sopenharmony_ci * ice_napi_disable_all - Disable NAPI for all q_vectors in the VSI
686662306a36Sopenharmony_ci * @vsi: VSI having NAPI disabled
686762306a36Sopenharmony_ci */
686862306a36Sopenharmony_cistatic void ice_napi_disable_all(struct ice_vsi *vsi)
686962306a36Sopenharmony_ci{
687062306a36Sopenharmony_ci	int q_idx;
687162306a36Sopenharmony_ci
687262306a36Sopenharmony_ci	if (!vsi->netdev)
687362306a36Sopenharmony_ci		return;
687462306a36Sopenharmony_ci
687562306a36Sopenharmony_ci	ice_for_each_q_vector(vsi, q_idx) {
687662306a36Sopenharmony_ci		struct ice_q_vector *q_vector = vsi->q_vectors[q_idx];
687762306a36Sopenharmony_ci
687862306a36Sopenharmony_ci		if (q_vector->rx.rx_ring || q_vector->tx.tx_ring)
687962306a36Sopenharmony_ci			napi_disable(&q_vector->napi);
688062306a36Sopenharmony_ci
688162306a36Sopenharmony_ci		cancel_work_sync(&q_vector->tx.dim.work);
688262306a36Sopenharmony_ci		cancel_work_sync(&q_vector->rx.dim.work);
688362306a36Sopenharmony_ci	}
688462306a36Sopenharmony_ci}
688562306a36Sopenharmony_ci
688662306a36Sopenharmony_ci/**
688762306a36Sopenharmony_ci * ice_down - Shutdown the connection
688862306a36Sopenharmony_ci * @vsi: The VSI being stopped
688962306a36Sopenharmony_ci *
689062306a36Sopenharmony_ci * Caller of this function is expected to set the vsi->state ICE_DOWN bit
689162306a36Sopenharmony_ci */
689262306a36Sopenharmony_ciint ice_down(struct ice_vsi *vsi)
689362306a36Sopenharmony_ci{
689462306a36Sopenharmony_ci	int i, tx_err, rx_err, vlan_err = 0;
689562306a36Sopenharmony_ci
689662306a36Sopenharmony_ci	WARN_ON(!test_bit(ICE_VSI_DOWN, vsi->state));
689762306a36Sopenharmony_ci
689862306a36Sopenharmony_ci	if (vsi->netdev && vsi->type == ICE_VSI_PF) {
689962306a36Sopenharmony_ci		vlan_err = ice_vsi_del_vlan_zero(vsi);
690062306a36Sopenharmony_ci		ice_ptp_link_change(vsi->back, vsi->back->hw.pf_id, false);
690162306a36Sopenharmony_ci		netif_carrier_off(vsi->netdev);
690262306a36Sopenharmony_ci		netif_tx_disable(vsi->netdev);
690362306a36Sopenharmony_ci	} else if (vsi->type == ICE_VSI_SWITCHDEV_CTRL) {
690462306a36Sopenharmony_ci		ice_eswitch_stop_all_tx_queues(vsi->back);
690562306a36Sopenharmony_ci	}
690662306a36Sopenharmony_ci
690762306a36Sopenharmony_ci	ice_vsi_dis_irq(vsi);
690862306a36Sopenharmony_ci
690962306a36Sopenharmony_ci	tx_err = ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, 0);
691062306a36Sopenharmony_ci	if (tx_err)
691162306a36Sopenharmony_ci		netdev_err(vsi->netdev, "Failed stop Tx rings, VSI %d error %d\n",
691262306a36Sopenharmony_ci			   vsi->vsi_num, tx_err);
691362306a36Sopenharmony_ci	if (!tx_err && ice_is_xdp_ena_vsi(vsi)) {
691462306a36Sopenharmony_ci		tx_err = ice_vsi_stop_xdp_tx_rings(vsi);
691562306a36Sopenharmony_ci		if (tx_err)
691662306a36Sopenharmony_ci			netdev_err(vsi->netdev, "Failed stop XDP rings, VSI %d error %d\n",
691762306a36Sopenharmony_ci				   vsi->vsi_num, tx_err);
691862306a36Sopenharmony_ci	}
691962306a36Sopenharmony_ci
692062306a36Sopenharmony_ci	rx_err = ice_vsi_stop_all_rx_rings(vsi);
692162306a36Sopenharmony_ci	if (rx_err)
692262306a36Sopenharmony_ci		netdev_err(vsi->netdev, "Failed stop Rx rings, VSI %d error %d\n",
692362306a36Sopenharmony_ci			   vsi->vsi_num, rx_err);
692462306a36Sopenharmony_ci
692562306a36Sopenharmony_ci	ice_napi_disable_all(vsi);
692662306a36Sopenharmony_ci
692762306a36Sopenharmony_ci	ice_for_each_txq(vsi, i)
692862306a36Sopenharmony_ci		ice_clean_tx_ring(vsi->tx_rings[i]);
692962306a36Sopenharmony_ci
693062306a36Sopenharmony_ci	if (ice_is_xdp_ena_vsi(vsi))
693162306a36Sopenharmony_ci		ice_for_each_xdp_txq(vsi, i)
693262306a36Sopenharmony_ci			ice_clean_tx_ring(vsi->xdp_rings[i]);
693362306a36Sopenharmony_ci
693462306a36Sopenharmony_ci	ice_for_each_rxq(vsi, i)
693562306a36Sopenharmony_ci		ice_clean_rx_ring(vsi->rx_rings[i]);
693662306a36Sopenharmony_ci
693762306a36Sopenharmony_ci	if (tx_err || rx_err || vlan_err) {
693862306a36Sopenharmony_ci		netdev_err(vsi->netdev, "Failed to close VSI 0x%04X on switch 0x%04X\n",
693962306a36Sopenharmony_ci			   vsi->vsi_num, vsi->vsw->sw_id);
694062306a36Sopenharmony_ci		return -EIO;
694162306a36Sopenharmony_ci	}
694262306a36Sopenharmony_ci
694362306a36Sopenharmony_ci	return 0;
694462306a36Sopenharmony_ci}
694562306a36Sopenharmony_ci
694662306a36Sopenharmony_ci/**
694762306a36Sopenharmony_ci * ice_down_up - shutdown the VSI connection and bring it up
694862306a36Sopenharmony_ci * @vsi: the VSI to be reconnected
694962306a36Sopenharmony_ci */
695062306a36Sopenharmony_ciint ice_down_up(struct ice_vsi *vsi)
695162306a36Sopenharmony_ci{
695262306a36Sopenharmony_ci	int ret;
695362306a36Sopenharmony_ci
695462306a36Sopenharmony_ci	/* if DOWN already set, nothing to do */
695562306a36Sopenharmony_ci	if (test_and_set_bit(ICE_VSI_DOWN, vsi->state))
695662306a36Sopenharmony_ci		return 0;
695762306a36Sopenharmony_ci
695862306a36Sopenharmony_ci	ret = ice_down(vsi);
695962306a36Sopenharmony_ci	if (ret)
696062306a36Sopenharmony_ci		return ret;
696162306a36Sopenharmony_ci
696262306a36Sopenharmony_ci	ret = ice_up(vsi);
696362306a36Sopenharmony_ci	if (ret) {
696462306a36Sopenharmony_ci		netdev_err(vsi->netdev, "reallocating resources failed during netdev features change, may need to reload driver\n");
696562306a36Sopenharmony_ci		return ret;
696662306a36Sopenharmony_ci	}
696762306a36Sopenharmony_ci
696862306a36Sopenharmony_ci	return 0;
696962306a36Sopenharmony_ci}
697062306a36Sopenharmony_ci
697162306a36Sopenharmony_ci/**
697262306a36Sopenharmony_ci * ice_vsi_setup_tx_rings - Allocate VSI Tx queue resources
697362306a36Sopenharmony_ci * @vsi: VSI having resources allocated
697462306a36Sopenharmony_ci *
697562306a36Sopenharmony_ci * Return 0 on success, negative on failure
697662306a36Sopenharmony_ci */
697762306a36Sopenharmony_ciint ice_vsi_setup_tx_rings(struct ice_vsi *vsi)
697862306a36Sopenharmony_ci{
697962306a36Sopenharmony_ci	int i, err = 0;
698062306a36Sopenharmony_ci
698162306a36Sopenharmony_ci	if (!vsi->num_txq) {
698262306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(vsi->back), "VSI %d has 0 Tx queues\n",
698362306a36Sopenharmony_ci			vsi->vsi_num);
698462306a36Sopenharmony_ci		return -EINVAL;
698562306a36Sopenharmony_ci	}
698662306a36Sopenharmony_ci
698762306a36Sopenharmony_ci	ice_for_each_txq(vsi, i) {
698862306a36Sopenharmony_ci		struct ice_tx_ring *ring = vsi->tx_rings[i];
698962306a36Sopenharmony_ci
699062306a36Sopenharmony_ci		if (!ring)
699162306a36Sopenharmony_ci			return -EINVAL;
699262306a36Sopenharmony_ci
699362306a36Sopenharmony_ci		if (vsi->netdev)
699462306a36Sopenharmony_ci			ring->netdev = vsi->netdev;
699562306a36Sopenharmony_ci		err = ice_setup_tx_ring(ring);
699662306a36Sopenharmony_ci		if (err)
699762306a36Sopenharmony_ci			break;
699862306a36Sopenharmony_ci	}
699962306a36Sopenharmony_ci
700062306a36Sopenharmony_ci	return err;
700162306a36Sopenharmony_ci}
700262306a36Sopenharmony_ci
700362306a36Sopenharmony_ci/**
700462306a36Sopenharmony_ci * ice_vsi_setup_rx_rings - Allocate VSI Rx queue resources
700562306a36Sopenharmony_ci * @vsi: VSI having resources allocated
700662306a36Sopenharmony_ci *
700762306a36Sopenharmony_ci * Return 0 on success, negative on failure
700862306a36Sopenharmony_ci */
700962306a36Sopenharmony_ciint ice_vsi_setup_rx_rings(struct ice_vsi *vsi)
701062306a36Sopenharmony_ci{
701162306a36Sopenharmony_ci	int i, err = 0;
701262306a36Sopenharmony_ci
701362306a36Sopenharmony_ci	if (!vsi->num_rxq) {
701462306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(vsi->back), "VSI %d has 0 Rx queues\n",
701562306a36Sopenharmony_ci			vsi->vsi_num);
701662306a36Sopenharmony_ci		return -EINVAL;
701762306a36Sopenharmony_ci	}
701862306a36Sopenharmony_ci
701962306a36Sopenharmony_ci	ice_for_each_rxq(vsi, i) {
702062306a36Sopenharmony_ci		struct ice_rx_ring *ring = vsi->rx_rings[i];
702162306a36Sopenharmony_ci
702262306a36Sopenharmony_ci		if (!ring)
702362306a36Sopenharmony_ci			return -EINVAL;
702462306a36Sopenharmony_ci
702562306a36Sopenharmony_ci		if (vsi->netdev)
702662306a36Sopenharmony_ci			ring->netdev = vsi->netdev;
702762306a36Sopenharmony_ci		err = ice_setup_rx_ring(ring);
702862306a36Sopenharmony_ci		if (err)
702962306a36Sopenharmony_ci			break;
703062306a36Sopenharmony_ci	}
703162306a36Sopenharmony_ci
703262306a36Sopenharmony_ci	return err;
703362306a36Sopenharmony_ci}
703462306a36Sopenharmony_ci
703562306a36Sopenharmony_ci/**
703662306a36Sopenharmony_ci * ice_vsi_open_ctrl - open control VSI for use
703762306a36Sopenharmony_ci * @vsi: the VSI to open
703862306a36Sopenharmony_ci *
703962306a36Sopenharmony_ci * Initialization of the Control VSI
704062306a36Sopenharmony_ci *
704162306a36Sopenharmony_ci * Returns 0 on success, negative value on error
704262306a36Sopenharmony_ci */
704362306a36Sopenharmony_ciint ice_vsi_open_ctrl(struct ice_vsi *vsi)
704462306a36Sopenharmony_ci{
704562306a36Sopenharmony_ci	char int_name[ICE_INT_NAME_STR_LEN];
704662306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
704762306a36Sopenharmony_ci	struct device *dev;
704862306a36Sopenharmony_ci	int err;
704962306a36Sopenharmony_ci
705062306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
705162306a36Sopenharmony_ci	/* allocate descriptors */
705262306a36Sopenharmony_ci	err = ice_vsi_setup_tx_rings(vsi);
705362306a36Sopenharmony_ci	if (err)
705462306a36Sopenharmony_ci		goto err_setup_tx;
705562306a36Sopenharmony_ci
705662306a36Sopenharmony_ci	err = ice_vsi_setup_rx_rings(vsi);
705762306a36Sopenharmony_ci	if (err)
705862306a36Sopenharmony_ci		goto err_setup_rx;
705962306a36Sopenharmony_ci
706062306a36Sopenharmony_ci	err = ice_vsi_cfg_lan(vsi);
706162306a36Sopenharmony_ci	if (err)
706262306a36Sopenharmony_ci		goto err_setup_rx;
706362306a36Sopenharmony_ci
706462306a36Sopenharmony_ci	snprintf(int_name, sizeof(int_name) - 1, "%s-%s:ctrl",
706562306a36Sopenharmony_ci		 dev_driver_string(dev), dev_name(dev));
706662306a36Sopenharmony_ci	err = ice_vsi_req_irq_msix(vsi, int_name);
706762306a36Sopenharmony_ci	if (err)
706862306a36Sopenharmony_ci		goto err_setup_rx;
706962306a36Sopenharmony_ci
707062306a36Sopenharmony_ci	ice_vsi_cfg_msix(vsi);
707162306a36Sopenharmony_ci
707262306a36Sopenharmony_ci	err = ice_vsi_start_all_rx_rings(vsi);
707362306a36Sopenharmony_ci	if (err)
707462306a36Sopenharmony_ci		goto err_up_complete;
707562306a36Sopenharmony_ci
707662306a36Sopenharmony_ci	clear_bit(ICE_VSI_DOWN, vsi->state);
707762306a36Sopenharmony_ci	ice_vsi_ena_irq(vsi);
707862306a36Sopenharmony_ci
707962306a36Sopenharmony_ci	return 0;
708062306a36Sopenharmony_ci
708162306a36Sopenharmony_cierr_up_complete:
708262306a36Sopenharmony_ci	ice_down(vsi);
708362306a36Sopenharmony_cierr_setup_rx:
708462306a36Sopenharmony_ci	ice_vsi_free_rx_rings(vsi);
708562306a36Sopenharmony_cierr_setup_tx:
708662306a36Sopenharmony_ci	ice_vsi_free_tx_rings(vsi);
708762306a36Sopenharmony_ci
708862306a36Sopenharmony_ci	return err;
708962306a36Sopenharmony_ci}
709062306a36Sopenharmony_ci
709162306a36Sopenharmony_ci/**
709262306a36Sopenharmony_ci * ice_vsi_open - Called when a network interface is made active
709362306a36Sopenharmony_ci * @vsi: the VSI to open
709462306a36Sopenharmony_ci *
709562306a36Sopenharmony_ci * Initialization of the VSI
709662306a36Sopenharmony_ci *
709762306a36Sopenharmony_ci * Returns 0 on success, negative value on error
709862306a36Sopenharmony_ci */
709962306a36Sopenharmony_ciint ice_vsi_open(struct ice_vsi *vsi)
710062306a36Sopenharmony_ci{
710162306a36Sopenharmony_ci	char int_name[ICE_INT_NAME_STR_LEN];
710262306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
710362306a36Sopenharmony_ci	int err;
710462306a36Sopenharmony_ci
710562306a36Sopenharmony_ci	/* allocate descriptors */
710662306a36Sopenharmony_ci	err = ice_vsi_setup_tx_rings(vsi);
710762306a36Sopenharmony_ci	if (err)
710862306a36Sopenharmony_ci		goto err_setup_tx;
710962306a36Sopenharmony_ci
711062306a36Sopenharmony_ci	err = ice_vsi_setup_rx_rings(vsi);
711162306a36Sopenharmony_ci	if (err)
711262306a36Sopenharmony_ci		goto err_setup_rx;
711362306a36Sopenharmony_ci
711462306a36Sopenharmony_ci	err = ice_vsi_cfg_lan(vsi);
711562306a36Sopenharmony_ci	if (err)
711662306a36Sopenharmony_ci		goto err_setup_rx;
711762306a36Sopenharmony_ci
711862306a36Sopenharmony_ci	snprintf(int_name, sizeof(int_name) - 1, "%s-%s",
711962306a36Sopenharmony_ci		 dev_driver_string(ice_pf_to_dev(pf)), vsi->netdev->name);
712062306a36Sopenharmony_ci	err = ice_vsi_req_irq_msix(vsi, int_name);
712162306a36Sopenharmony_ci	if (err)
712262306a36Sopenharmony_ci		goto err_setup_rx;
712362306a36Sopenharmony_ci
712462306a36Sopenharmony_ci	ice_vsi_cfg_netdev_tc(vsi, vsi->tc_cfg.ena_tc);
712562306a36Sopenharmony_ci
712662306a36Sopenharmony_ci	if (vsi->type == ICE_VSI_PF) {
712762306a36Sopenharmony_ci		/* Notify the stack of the actual queue counts. */
712862306a36Sopenharmony_ci		err = netif_set_real_num_tx_queues(vsi->netdev, vsi->num_txq);
712962306a36Sopenharmony_ci		if (err)
713062306a36Sopenharmony_ci			goto err_set_qs;
713162306a36Sopenharmony_ci
713262306a36Sopenharmony_ci		err = netif_set_real_num_rx_queues(vsi->netdev, vsi->num_rxq);
713362306a36Sopenharmony_ci		if (err)
713462306a36Sopenharmony_ci			goto err_set_qs;
713562306a36Sopenharmony_ci	}
713662306a36Sopenharmony_ci
713762306a36Sopenharmony_ci	err = ice_up_complete(vsi);
713862306a36Sopenharmony_ci	if (err)
713962306a36Sopenharmony_ci		goto err_up_complete;
714062306a36Sopenharmony_ci
714162306a36Sopenharmony_ci	return 0;
714262306a36Sopenharmony_ci
714362306a36Sopenharmony_cierr_up_complete:
714462306a36Sopenharmony_ci	ice_down(vsi);
714562306a36Sopenharmony_cierr_set_qs:
714662306a36Sopenharmony_ci	ice_vsi_free_irq(vsi);
714762306a36Sopenharmony_cierr_setup_rx:
714862306a36Sopenharmony_ci	ice_vsi_free_rx_rings(vsi);
714962306a36Sopenharmony_cierr_setup_tx:
715062306a36Sopenharmony_ci	ice_vsi_free_tx_rings(vsi);
715162306a36Sopenharmony_ci
715262306a36Sopenharmony_ci	return err;
715362306a36Sopenharmony_ci}
715462306a36Sopenharmony_ci
715562306a36Sopenharmony_ci/**
715662306a36Sopenharmony_ci * ice_vsi_release_all - Delete all VSIs
715762306a36Sopenharmony_ci * @pf: PF from which all VSIs are being removed
715862306a36Sopenharmony_ci */
715962306a36Sopenharmony_cistatic void ice_vsi_release_all(struct ice_pf *pf)
716062306a36Sopenharmony_ci{
716162306a36Sopenharmony_ci	int err, i;
716262306a36Sopenharmony_ci
716362306a36Sopenharmony_ci	if (!pf->vsi)
716462306a36Sopenharmony_ci		return;
716562306a36Sopenharmony_ci
716662306a36Sopenharmony_ci	ice_for_each_vsi(pf, i) {
716762306a36Sopenharmony_ci		if (!pf->vsi[i])
716862306a36Sopenharmony_ci			continue;
716962306a36Sopenharmony_ci
717062306a36Sopenharmony_ci		if (pf->vsi[i]->type == ICE_VSI_CHNL)
717162306a36Sopenharmony_ci			continue;
717262306a36Sopenharmony_ci
717362306a36Sopenharmony_ci		err = ice_vsi_release(pf->vsi[i]);
717462306a36Sopenharmony_ci		if (err)
717562306a36Sopenharmony_ci			dev_dbg(ice_pf_to_dev(pf), "Failed to release pf->vsi[%d], err %d, vsi_num = %d\n",
717662306a36Sopenharmony_ci				i, err, pf->vsi[i]->vsi_num);
717762306a36Sopenharmony_ci	}
717862306a36Sopenharmony_ci}
717962306a36Sopenharmony_ci
718062306a36Sopenharmony_ci/**
718162306a36Sopenharmony_ci * ice_vsi_rebuild_by_type - Rebuild VSI of a given type
718262306a36Sopenharmony_ci * @pf: pointer to the PF instance
718362306a36Sopenharmony_ci * @type: VSI type to rebuild
718462306a36Sopenharmony_ci *
718562306a36Sopenharmony_ci * Iterates through the pf->vsi array and rebuilds VSIs of the requested type
718662306a36Sopenharmony_ci */
718762306a36Sopenharmony_cistatic int ice_vsi_rebuild_by_type(struct ice_pf *pf, enum ice_vsi_type type)
718862306a36Sopenharmony_ci{
718962306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
719062306a36Sopenharmony_ci	int i, err;
719162306a36Sopenharmony_ci
719262306a36Sopenharmony_ci	ice_for_each_vsi(pf, i) {
719362306a36Sopenharmony_ci		struct ice_vsi *vsi = pf->vsi[i];
719462306a36Sopenharmony_ci
719562306a36Sopenharmony_ci		if (!vsi || vsi->type != type)
719662306a36Sopenharmony_ci			continue;
719762306a36Sopenharmony_ci
719862306a36Sopenharmony_ci		/* rebuild the VSI */
719962306a36Sopenharmony_ci		err = ice_vsi_rebuild(vsi, ICE_VSI_FLAG_INIT);
720062306a36Sopenharmony_ci		if (err) {
720162306a36Sopenharmony_ci			dev_err(dev, "rebuild VSI failed, err %d, VSI index %d, type %s\n",
720262306a36Sopenharmony_ci				err, vsi->idx, ice_vsi_type_str(type));
720362306a36Sopenharmony_ci			return err;
720462306a36Sopenharmony_ci		}
720562306a36Sopenharmony_ci
720662306a36Sopenharmony_ci		/* replay filters for the VSI */
720762306a36Sopenharmony_ci		err = ice_replay_vsi(&pf->hw, vsi->idx);
720862306a36Sopenharmony_ci		if (err) {
720962306a36Sopenharmony_ci			dev_err(dev, "replay VSI failed, error %d, VSI index %d, type %s\n",
721062306a36Sopenharmony_ci				err, vsi->idx, ice_vsi_type_str(type));
721162306a36Sopenharmony_ci			return err;
721262306a36Sopenharmony_ci		}
721362306a36Sopenharmony_ci
721462306a36Sopenharmony_ci		/* Re-map HW VSI number, using VSI handle that has been
721562306a36Sopenharmony_ci		 * previously validated in ice_replay_vsi() call above
721662306a36Sopenharmony_ci		 */
721762306a36Sopenharmony_ci		vsi->vsi_num = ice_get_hw_vsi_num(&pf->hw, vsi->idx);
721862306a36Sopenharmony_ci
721962306a36Sopenharmony_ci		/* enable the VSI */
722062306a36Sopenharmony_ci		err = ice_ena_vsi(vsi, false);
722162306a36Sopenharmony_ci		if (err) {
722262306a36Sopenharmony_ci			dev_err(dev, "enable VSI failed, err %d, VSI index %d, type %s\n",
722362306a36Sopenharmony_ci				err, vsi->idx, ice_vsi_type_str(type));
722462306a36Sopenharmony_ci			return err;
722562306a36Sopenharmony_ci		}
722662306a36Sopenharmony_ci
722762306a36Sopenharmony_ci		dev_info(dev, "VSI rebuilt. VSI index %d, type %s\n", vsi->idx,
722862306a36Sopenharmony_ci			 ice_vsi_type_str(type));
722962306a36Sopenharmony_ci	}
723062306a36Sopenharmony_ci
723162306a36Sopenharmony_ci	return 0;
723262306a36Sopenharmony_ci}
723362306a36Sopenharmony_ci
723462306a36Sopenharmony_ci/**
723562306a36Sopenharmony_ci * ice_update_pf_netdev_link - Update PF netdev link status
723662306a36Sopenharmony_ci * @pf: pointer to the PF instance
723762306a36Sopenharmony_ci */
723862306a36Sopenharmony_cistatic void ice_update_pf_netdev_link(struct ice_pf *pf)
723962306a36Sopenharmony_ci{
724062306a36Sopenharmony_ci	bool link_up;
724162306a36Sopenharmony_ci	int i;
724262306a36Sopenharmony_ci
724362306a36Sopenharmony_ci	ice_for_each_vsi(pf, i) {
724462306a36Sopenharmony_ci		struct ice_vsi *vsi = pf->vsi[i];
724562306a36Sopenharmony_ci
724662306a36Sopenharmony_ci		if (!vsi || vsi->type != ICE_VSI_PF)
724762306a36Sopenharmony_ci			return;
724862306a36Sopenharmony_ci
724962306a36Sopenharmony_ci		ice_get_link_status(pf->vsi[i]->port_info, &link_up);
725062306a36Sopenharmony_ci		if (link_up) {
725162306a36Sopenharmony_ci			netif_carrier_on(pf->vsi[i]->netdev);
725262306a36Sopenharmony_ci			netif_tx_wake_all_queues(pf->vsi[i]->netdev);
725362306a36Sopenharmony_ci		} else {
725462306a36Sopenharmony_ci			netif_carrier_off(pf->vsi[i]->netdev);
725562306a36Sopenharmony_ci			netif_tx_stop_all_queues(pf->vsi[i]->netdev);
725662306a36Sopenharmony_ci		}
725762306a36Sopenharmony_ci	}
725862306a36Sopenharmony_ci}
725962306a36Sopenharmony_ci
726062306a36Sopenharmony_ci/**
726162306a36Sopenharmony_ci * ice_rebuild - rebuild after reset
726262306a36Sopenharmony_ci * @pf: PF to rebuild
726362306a36Sopenharmony_ci * @reset_type: type of reset
726462306a36Sopenharmony_ci *
726562306a36Sopenharmony_ci * Do not rebuild VF VSI in this flow because that is already handled via
726662306a36Sopenharmony_ci * ice_reset_all_vfs(). This is because requirements for resetting a VF after a
726762306a36Sopenharmony_ci * PFR/CORER/GLOBER/etc. are different than the normal flow. Also, we don't want
726862306a36Sopenharmony_ci * to reset/rebuild all the VF VSI twice.
726962306a36Sopenharmony_ci */
727062306a36Sopenharmony_cistatic void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)
727162306a36Sopenharmony_ci{
727262306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
727362306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
727462306a36Sopenharmony_ci	bool dvm;
727562306a36Sopenharmony_ci	int err;
727662306a36Sopenharmony_ci
727762306a36Sopenharmony_ci	if (test_bit(ICE_DOWN, pf->state))
727862306a36Sopenharmony_ci		goto clear_recovery;
727962306a36Sopenharmony_ci
728062306a36Sopenharmony_ci	dev_dbg(dev, "rebuilding PF after reset_type=%d\n", reset_type);
728162306a36Sopenharmony_ci
728262306a36Sopenharmony_ci#define ICE_EMP_RESET_SLEEP_MS 5000
728362306a36Sopenharmony_ci	if (reset_type == ICE_RESET_EMPR) {
728462306a36Sopenharmony_ci		/* If an EMP reset has occurred, any previously pending flash
728562306a36Sopenharmony_ci		 * update will have completed. We no longer know whether or
728662306a36Sopenharmony_ci		 * not the NVM update EMP reset is restricted.
728762306a36Sopenharmony_ci		 */
728862306a36Sopenharmony_ci		pf->fw_emp_reset_disabled = false;
728962306a36Sopenharmony_ci
729062306a36Sopenharmony_ci		msleep(ICE_EMP_RESET_SLEEP_MS);
729162306a36Sopenharmony_ci	}
729262306a36Sopenharmony_ci
729362306a36Sopenharmony_ci	err = ice_init_all_ctrlq(hw);
729462306a36Sopenharmony_ci	if (err) {
729562306a36Sopenharmony_ci		dev_err(dev, "control queues init failed %d\n", err);
729662306a36Sopenharmony_ci		goto err_init_ctrlq;
729762306a36Sopenharmony_ci	}
729862306a36Sopenharmony_ci
729962306a36Sopenharmony_ci	/* if DDP was previously loaded successfully */
730062306a36Sopenharmony_ci	if (!ice_is_safe_mode(pf)) {
730162306a36Sopenharmony_ci		/* reload the SW DB of filter tables */
730262306a36Sopenharmony_ci		if (reset_type == ICE_RESET_PFR)
730362306a36Sopenharmony_ci			ice_fill_blk_tbls(hw);
730462306a36Sopenharmony_ci		else
730562306a36Sopenharmony_ci			/* Reload DDP Package after CORER/GLOBR reset */
730662306a36Sopenharmony_ci			ice_load_pkg(NULL, pf);
730762306a36Sopenharmony_ci	}
730862306a36Sopenharmony_ci
730962306a36Sopenharmony_ci	err = ice_clear_pf_cfg(hw);
731062306a36Sopenharmony_ci	if (err) {
731162306a36Sopenharmony_ci		dev_err(dev, "clear PF configuration failed %d\n", err);
731262306a36Sopenharmony_ci		goto err_init_ctrlq;
731362306a36Sopenharmony_ci	}
731462306a36Sopenharmony_ci
731562306a36Sopenharmony_ci	ice_clear_pxe_mode(hw);
731662306a36Sopenharmony_ci
731762306a36Sopenharmony_ci	err = ice_init_nvm(hw);
731862306a36Sopenharmony_ci	if (err) {
731962306a36Sopenharmony_ci		dev_err(dev, "ice_init_nvm failed %d\n", err);
732062306a36Sopenharmony_ci		goto err_init_ctrlq;
732162306a36Sopenharmony_ci	}
732262306a36Sopenharmony_ci
732362306a36Sopenharmony_ci	err = ice_get_caps(hw);
732462306a36Sopenharmony_ci	if (err) {
732562306a36Sopenharmony_ci		dev_err(dev, "ice_get_caps failed %d\n", err);
732662306a36Sopenharmony_ci		goto err_init_ctrlq;
732762306a36Sopenharmony_ci	}
732862306a36Sopenharmony_ci
732962306a36Sopenharmony_ci	err = ice_aq_set_mac_cfg(hw, ICE_AQ_SET_MAC_FRAME_SIZE_MAX, NULL);
733062306a36Sopenharmony_ci	if (err) {
733162306a36Sopenharmony_ci		dev_err(dev, "set_mac_cfg failed %d\n", err);
733262306a36Sopenharmony_ci		goto err_init_ctrlq;
733362306a36Sopenharmony_ci	}
733462306a36Sopenharmony_ci
733562306a36Sopenharmony_ci	dvm = ice_is_dvm_ena(hw);
733662306a36Sopenharmony_ci
733762306a36Sopenharmony_ci	err = ice_aq_set_port_params(pf->hw.port_info, dvm, NULL);
733862306a36Sopenharmony_ci	if (err)
733962306a36Sopenharmony_ci		goto err_init_ctrlq;
734062306a36Sopenharmony_ci
734162306a36Sopenharmony_ci	err = ice_sched_init_port(hw->port_info);
734262306a36Sopenharmony_ci	if (err)
734362306a36Sopenharmony_ci		goto err_sched_init_port;
734462306a36Sopenharmony_ci
734562306a36Sopenharmony_ci	/* start misc vector */
734662306a36Sopenharmony_ci	err = ice_req_irq_msix_misc(pf);
734762306a36Sopenharmony_ci	if (err) {
734862306a36Sopenharmony_ci		dev_err(dev, "misc vector setup failed: %d\n", err);
734962306a36Sopenharmony_ci		goto err_sched_init_port;
735062306a36Sopenharmony_ci	}
735162306a36Sopenharmony_ci
735262306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_FD_ENA, pf->flags)) {
735362306a36Sopenharmony_ci		wr32(hw, PFQF_FD_ENA, PFQF_FD_ENA_FD_ENA_M);
735462306a36Sopenharmony_ci		if (!rd32(hw, PFQF_FD_SIZE)) {
735562306a36Sopenharmony_ci			u16 unused, guar, b_effort;
735662306a36Sopenharmony_ci
735762306a36Sopenharmony_ci			guar = hw->func_caps.fd_fltr_guar;
735862306a36Sopenharmony_ci			b_effort = hw->func_caps.fd_fltr_best_effort;
735962306a36Sopenharmony_ci
736062306a36Sopenharmony_ci			/* force guaranteed filter pool for PF */
736162306a36Sopenharmony_ci			ice_alloc_fd_guar_item(hw, &unused, guar);
736262306a36Sopenharmony_ci			/* force shared filter pool for PF */
736362306a36Sopenharmony_ci			ice_alloc_fd_shrd_item(hw, &unused, b_effort);
736462306a36Sopenharmony_ci		}
736562306a36Sopenharmony_ci	}
736662306a36Sopenharmony_ci
736762306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_DCB_ENA, pf->flags))
736862306a36Sopenharmony_ci		ice_dcb_rebuild(pf);
736962306a36Sopenharmony_ci
737062306a36Sopenharmony_ci	/* If the PF previously had enabled PTP, PTP init needs to happen before
737162306a36Sopenharmony_ci	 * the VSI rebuild. If not, this causes the PTP link status events to
737262306a36Sopenharmony_ci	 * fail.
737362306a36Sopenharmony_ci	 */
737462306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags))
737562306a36Sopenharmony_ci		ice_ptp_reset(pf);
737662306a36Sopenharmony_ci
737762306a36Sopenharmony_ci	if (ice_is_feature_supported(pf, ICE_F_GNSS))
737862306a36Sopenharmony_ci		ice_gnss_init(pf);
737962306a36Sopenharmony_ci
738062306a36Sopenharmony_ci	/* rebuild PF VSI */
738162306a36Sopenharmony_ci	err = ice_vsi_rebuild_by_type(pf, ICE_VSI_PF);
738262306a36Sopenharmony_ci	if (err) {
738362306a36Sopenharmony_ci		dev_err(dev, "PF VSI rebuild failed: %d\n", err);
738462306a36Sopenharmony_ci		goto err_vsi_rebuild;
738562306a36Sopenharmony_ci	}
738662306a36Sopenharmony_ci
738762306a36Sopenharmony_ci	/* configure PTP timestamping after VSI rebuild */
738862306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_PTP_SUPPORTED, pf->flags))
738962306a36Sopenharmony_ci		ice_ptp_cfg_timestamp(pf, false);
739062306a36Sopenharmony_ci
739162306a36Sopenharmony_ci	err = ice_vsi_rebuild_by_type(pf, ICE_VSI_SWITCHDEV_CTRL);
739262306a36Sopenharmony_ci	if (err) {
739362306a36Sopenharmony_ci		dev_err(dev, "Switchdev CTRL VSI rebuild failed: %d\n", err);
739462306a36Sopenharmony_ci		goto err_vsi_rebuild;
739562306a36Sopenharmony_ci	}
739662306a36Sopenharmony_ci
739762306a36Sopenharmony_ci	if (reset_type == ICE_RESET_PFR) {
739862306a36Sopenharmony_ci		err = ice_rebuild_channels(pf);
739962306a36Sopenharmony_ci		if (err) {
740062306a36Sopenharmony_ci			dev_err(dev, "failed to rebuild and replay ADQ VSIs, err %d\n",
740162306a36Sopenharmony_ci				err);
740262306a36Sopenharmony_ci			goto err_vsi_rebuild;
740362306a36Sopenharmony_ci		}
740462306a36Sopenharmony_ci	}
740562306a36Sopenharmony_ci
740662306a36Sopenharmony_ci	/* If Flow Director is active */
740762306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_FD_ENA, pf->flags)) {
740862306a36Sopenharmony_ci		err = ice_vsi_rebuild_by_type(pf, ICE_VSI_CTRL);
740962306a36Sopenharmony_ci		if (err) {
741062306a36Sopenharmony_ci			dev_err(dev, "control VSI rebuild failed: %d\n", err);
741162306a36Sopenharmony_ci			goto err_vsi_rebuild;
741262306a36Sopenharmony_ci		}
741362306a36Sopenharmony_ci
741462306a36Sopenharmony_ci		/* replay HW Flow Director recipes */
741562306a36Sopenharmony_ci		if (hw->fdir_prof)
741662306a36Sopenharmony_ci			ice_fdir_replay_flows(hw);
741762306a36Sopenharmony_ci
741862306a36Sopenharmony_ci		/* replay Flow Director filters */
741962306a36Sopenharmony_ci		ice_fdir_replay_fltrs(pf);
742062306a36Sopenharmony_ci
742162306a36Sopenharmony_ci		ice_rebuild_arfs(pf);
742262306a36Sopenharmony_ci	}
742362306a36Sopenharmony_ci
742462306a36Sopenharmony_ci	ice_update_pf_netdev_link(pf);
742562306a36Sopenharmony_ci
742662306a36Sopenharmony_ci	/* tell the firmware we are up */
742762306a36Sopenharmony_ci	err = ice_send_version(pf);
742862306a36Sopenharmony_ci	if (err) {
742962306a36Sopenharmony_ci		dev_err(dev, "Rebuild failed due to error sending driver version: %d\n",
743062306a36Sopenharmony_ci			err);
743162306a36Sopenharmony_ci		goto err_vsi_rebuild;
743262306a36Sopenharmony_ci	}
743362306a36Sopenharmony_ci
743462306a36Sopenharmony_ci	ice_replay_post(hw);
743562306a36Sopenharmony_ci
743662306a36Sopenharmony_ci	/* if we get here, reset flow is successful */
743762306a36Sopenharmony_ci	clear_bit(ICE_RESET_FAILED, pf->state);
743862306a36Sopenharmony_ci
743962306a36Sopenharmony_ci	ice_plug_aux_dev(pf);
744062306a36Sopenharmony_ci	if (ice_is_feature_supported(pf, ICE_F_SRIOV_LAG))
744162306a36Sopenharmony_ci		ice_lag_rebuild(pf);
744262306a36Sopenharmony_ci	return;
744362306a36Sopenharmony_ci
744462306a36Sopenharmony_cierr_vsi_rebuild:
744562306a36Sopenharmony_cierr_sched_init_port:
744662306a36Sopenharmony_ci	ice_sched_cleanup_all(hw);
744762306a36Sopenharmony_cierr_init_ctrlq:
744862306a36Sopenharmony_ci	ice_shutdown_all_ctrlq(hw);
744962306a36Sopenharmony_ci	set_bit(ICE_RESET_FAILED, pf->state);
745062306a36Sopenharmony_ciclear_recovery:
745162306a36Sopenharmony_ci	/* set this bit in PF state to control service task scheduling */
745262306a36Sopenharmony_ci	set_bit(ICE_NEEDS_RESTART, pf->state);
745362306a36Sopenharmony_ci	dev_err(dev, "Rebuild failed, unload and reload driver\n");
745462306a36Sopenharmony_ci}
745562306a36Sopenharmony_ci
745662306a36Sopenharmony_ci/**
745762306a36Sopenharmony_ci * ice_change_mtu - NDO callback to change the MTU
745862306a36Sopenharmony_ci * @netdev: network interface device structure
745962306a36Sopenharmony_ci * @new_mtu: new value for maximum frame size
746062306a36Sopenharmony_ci *
746162306a36Sopenharmony_ci * Returns 0 on success, negative on failure
746262306a36Sopenharmony_ci */
746362306a36Sopenharmony_cistatic int ice_change_mtu(struct net_device *netdev, int new_mtu)
746462306a36Sopenharmony_ci{
746562306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
746662306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
746762306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
746862306a36Sopenharmony_ci	struct bpf_prog *prog;
746962306a36Sopenharmony_ci	u8 count = 0;
747062306a36Sopenharmony_ci	int err = 0;
747162306a36Sopenharmony_ci
747262306a36Sopenharmony_ci	if (new_mtu == (int)netdev->mtu) {
747362306a36Sopenharmony_ci		netdev_warn(netdev, "MTU is already %u\n", netdev->mtu);
747462306a36Sopenharmony_ci		return 0;
747562306a36Sopenharmony_ci	}
747662306a36Sopenharmony_ci
747762306a36Sopenharmony_ci	prog = vsi->xdp_prog;
747862306a36Sopenharmony_ci	if (prog && !prog->aux->xdp_has_frags) {
747962306a36Sopenharmony_ci		int frame_size = ice_max_xdp_frame_size(vsi);
748062306a36Sopenharmony_ci
748162306a36Sopenharmony_ci		if (new_mtu + ICE_ETH_PKT_HDR_PAD > frame_size) {
748262306a36Sopenharmony_ci			netdev_err(netdev, "max MTU for XDP usage is %d\n",
748362306a36Sopenharmony_ci				   frame_size - ICE_ETH_PKT_HDR_PAD);
748462306a36Sopenharmony_ci			return -EINVAL;
748562306a36Sopenharmony_ci		}
748662306a36Sopenharmony_ci	} else if (test_bit(ICE_FLAG_LEGACY_RX, pf->flags)) {
748762306a36Sopenharmony_ci		if (new_mtu + ICE_ETH_PKT_HDR_PAD > ICE_MAX_FRAME_LEGACY_RX) {
748862306a36Sopenharmony_ci			netdev_err(netdev, "Too big MTU for legacy-rx; Max is %d\n",
748962306a36Sopenharmony_ci				   ICE_MAX_FRAME_LEGACY_RX - ICE_ETH_PKT_HDR_PAD);
749062306a36Sopenharmony_ci			return -EINVAL;
749162306a36Sopenharmony_ci		}
749262306a36Sopenharmony_ci	}
749362306a36Sopenharmony_ci
749462306a36Sopenharmony_ci	/* if a reset is in progress, wait for some time for it to complete */
749562306a36Sopenharmony_ci	do {
749662306a36Sopenharmony_ci		if (ice_is_reset_in_progress(pf->state)) {
749762306a36Sopenharmony_ci			count++;
749862306a36Sopenharmony_ci			usleep_range(1000, 2000);
749962306a36Sopenharmony_ci		} else {
750062306a36Sopenharmony_ci			break;
750162306a36Sopenharmony_ci		}
750262306a36Sopenharmony_ci
750362306a36Sopenharmony_ci	} while (count < 100);
750462306a36Sopenharmony_ci
750562306a36Sopenharmony_ci	if (count == 100) {
750662306a36Sopenharmony_ci		netdev_err(netdev, "can't change MTU. Device is busy\n");
750762306a36Sopenharmony_ci		return -EBUSY;
750862306a36Sopenharmony_ci	}
750962306a36Sopenharmony_ci
751062306a36Sopenharmony_ci	netdev->mtu = (unsigned int)new_mtu;
751162306a36Sopenharmony_ci	err = ice_down_up(vsi);
751262306a36Sopenharmony_ci	if (err)
751362306a36Sopenharmony_ci		return err;
751462306a36Sopenharmony_ci
751562306a36Sopenharmony_ci	netdev_dbg(netdev, "changed MTU to %d\n", new_mtu);
751662306a36Sopenharmony_ci	set_bit(ICE_FLAG_MTU_CHANGED, pf->flags);
751762306a36Sopenharmony_ci
751862306a36Sopenharmony_ci	return err;
751962306a36Sopenharmony_ci}
752062306a36Sopenharmony_ci
752162306a36Sopenharmony_ci/**
752262306a36Sopenharmony_ci * ice_eth_ioctl - Access the hwtstamp interface
752362306a36Sopenharmony_ci * @netdev: network interface device structure
752462306a36Sopenharmony_ci * @ifr: interface request data
752562306a36Sopenharmony_ci * @cmd: ioctl command
752662306a36Sopenharmony_ci */
752762306a36Sopenharmony_cistatic int ice_eth_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
752862306a36Sopenharmony_ci{
752962306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
753062306a36Sopenharmony_ci	struct ice_pf *pf = np->vsi->back;
753162306a36Sopenharmony_ci
753262306a36Sopenharmony_ci	switch (cmd) {
753362306a36Sopenharmony_ci	case SIOCGHWTSTAMP:
753462306a36Sopenharmony_ci		return ice_ptp_get_ts_config(pf, ifr);
753562306a36Sopenharmony_ci	case SIOCSHWTSTAMP:
753662306a36Sopenharmony_ci		return ice_ptp_set_ts_config(pf, ifr);
753762306a36Sopenharmony_ci	default:
753862306a36Sopenharmony_ci		return -EOPNOTSUPP;
753962306a36Sopenharmony_ci	}
754062306a36Sopenharmony_ci}
754162306a36Sopenharmony_ci
754262306a36Sopenharmony_ci/**
754362306a36Sopenharmony_ci * ice_aq_str - convert AQ err code to a string
754462306a36Sopenharmony_ci * @aq_err: the AQ error code to convert
754562306a36Sopenharmony_ci */
754662306a36Sopenharmony_ciconst char *ice_aq_str(enum ice_aq_err aq_err)
754762306a36Sopenharmony_ci{
754862306a36Sopenharmony_ci	switch (aq_err) {
754962306a36Sopenharmony_ci	case ICE_AQ_RC_OK:
755062306a36Sopenharmony_ci		return "OK";
755162306a36Sopenharmony_ci	case ICE_AQ_RC_EPERM:
755262306a36Sopenharmony_ci		return "ICE_AQ_RC_EPERM";
755362306a36Sopenharmony_ci	case ICE_AQ_RC_ENOENT:
755462306a36Sopenharmony_ci		return "ICE_AQ_RC_ENOENT";
755562306a36Sopenharmony_ci	case ICE_AQ_RC_ENOMEM:
755662306a36Sopenharmony_ci		return "ICE_AQ_RC_ENOMEM";
755762306a36Sopenharmony_ci	case ICE_AQ_RC_EBUSY:
755862306a36Sopenharmony_ci		return "ICE_AQ_RC_EBUSY";
755962306a36Sopenharmony_ci	case ICE_AQ_RC_EEXIST:
756062306a36Sopenharmony_ci		return "ICE_AQ_RC_EEXIST";
756162306a36Sopenharmony_ci	case ICE_AQ_RC_EINVAL:
756262306a36Sopenharmony_ci		return "ICE_AQ_RC_EINVAL";
756362306a36Sopenharmony_ci	case ICE_AQ_RC_ENOSPC:
756462306a36Sopenharmony_ci		return "ICE_AQ_RC_ENOSPC";
756562306a36Sopenharmony_ci	case ICE_AQ_RC_ENOSYS:
756662306a36Sopenharmony_ci		return "ICE_AQ_RC_ENOSYS";
756762306a36Sopenharmony_ci	case ICE_AQ_RC_EMODE:
756862306a36Sopenharmony_ci		return "ICE_AQ_RC_EMODE";
756962306a36Sopenharmony_ci	case ICE_AQ_RC_ENOSEC:
757062306a36Sopenharmony_ci		return "ICE_AQ_RC_ENOSEC";
757162306a36Sopenharmony_ci	case ICE_AQ_RC_EBADSIG:
757262306a36Sopenharmony_ci		return "ICE_AQ_RC_EBADSIG";
757362306a36Sopenharmony_ci	case ICE_AQ_RC_ESVN:
757462306a36Sopenharmony_ci		return "ICE_AQ_RC_ESVN";
757562306a36Sopenharmony_ci	case ICE_AQ_RC_EBADMAN:
757662306a36Sopenharmony_ci		return "ICE_AQ_RC_EBADMAN";
757762306a36Sopenharmony_ci	case ICE_AQ_RC_EBADBUF:
757862306a36Sopenharmony_ci		return "ICE_AQ_RC_EBADBUF";
757962306a36Sopenharmony_ci	}
758062306a36Sopenharmony_ci
758162306a36Sopenharmony_ci	return "ICE_AQ_RC_UNKNOWN";
758262306a36Sopenharmony_ci}
758362306a36Sopenharmony_ci
758462306a36Sopenharmony_ci/**
758562306a36Sopenharmony_ci * ice_set_rss_lut - Set RSS LUT
758662306a36Sopenharmony_ci * @vsi: Pointer to VSI structure
758762306a36Sopenharmony_ci * @lut: Lookup table
758862306a36Sopenharmony_ci * @lut_size: Lookup table size
758962306a36Sopenharmony_ci *
759062306a36Sopenharmony_ci * Returns 0 on success, negative on failure
759162306a36Sopenharmony_ci */
759262306a36Sopenharmony_ciint ice_set_rss_lut(struct ice_vsi *vsi, u8 *lut, u16 lut_size)
759362306a36Sopenharmony_ci{
759462306a36Sopenharmony_ci	struct ice_aq_get_set_rss_lut_params params = {};
759562306a36Sopenharmony_ci	struct ice_hw *hw = &vsi->back->hw;
759662306a36Sopenharmony_ci	int status;
759762306a36Sopenharmony_ci
759862306a36Sopenharmony_ci	if (!lut)
759962306a36Sopenharmony_ci		return -EINVAL;
760062306a36Sopenharmony_ci
760162306a36Sopenharmony_ci	params.vsi_handle = vsi->idx;
760262306a36Sopenharmony_ci	params.lut_size = lut_size;
760362306a36Sopenharmony_ci	params.lut_type = vsi->rss_lut_type;
760462306a36Sopenharmony_ci	params.lut = lut;
760562306a36Sopenharmony_ci
760662306a36Sopenharmony_ci	status = ice_aq_set_rss_lut(hw, &params);
760762306a36Sopenharmony_ci	if (status)
760862306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(vsi->back), "Cannot set RSS lut, err %d aq_err %s\n",
760962306a36Sopenharmony_ci			status, ice_aq_str(hw->adminq.sq_last_status));
761062306a36Sopenharmony_ci
761162306a36Sopenharmony_ci	return status;
761262306a36Sopenharmony_ci}
761362306a36Sopenharmony_ci
761462306a36Sopenharmony_ci/**
761562306a36Sopenharmony_ci * ice_set_rss_key - Set RSS key
761662306a36Sopenharmony_ci * @vsi: Pointer to the VSI structure
761762306a36Sopenharmony_ci * @seed: RSS hash seed
761862306a36Sopenharmony_ci *
761962306a36Sopenharmony_ci * Returns 0 on success, negative on failure
762062306a36Sopenharmony_ci */
762162306a36Sopenharmony_ciint ice_set_rss_key(struct ice_vsi *vsi, u8 *seed)
762262306a36Sopenharmony_ci{
762362306a36Sopenharmony_ci	struct ice_hw *hw = &vsi->back->hw;
762462306a36Sopenharmony_ci	int status;
762562306a36Sopenharmony_ci
762662306a36Sopenharmony_ci	if (!seed)
762762306a36Sopenharmony_ci		return -EINVAL;
762862306a36Sopenharmony_ci
762962306a36Sopenharmony_ci	status = ice_aq_set_rss_key(hw, vsi->idx, (struct ice_aqc_get_set_rss_keys *)seed);
763062306a36Sopenharmony_ci	if (status)
763162306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(vsi->back), "Cannot set RSS key, err %d aq_err %s\n",
763262306a36Sopenharmony_ci			status, ice_aq_str(hw->adminq.sq_last_status));
763362306a36Sopenharmony_ci
763462306a36Sopenharmony_ci	return status;
763562306a36Sopenharmony_ci}
763662306a36Sopenharmony_ci
763762306a36Sopenharmony_ci/**
763862306a36Sopenharmony_ci * ice_get_rss_lut - Get RSS LUT
763962306a36Sopenharmony_ci * @vsi: Pointer to VSI structure
764062306a36Sopenharmony_ci * @lut: Buffer to store the lookup table entries
764162306a36Sopenharmony_ci * @lut_size: Size of buffer to store the lookup table entries
764262306a36Sopenharmony_ci *
764362306a36Sopenharmony_ci * Returns 0 on success, negative on failure
764462306a36Sopenharmony_ci */
764562306a36Sopenharmony_ciint ice_get_rss_lut(struct ice_vsi *vsi, u8 *lut, u16 lut_size)
764662306a36Sopenharmony_ci{
764762306a36Sopenharmony_ci	struct ice_aq_get_set_rss_lut_params params = {};
764862306a36Sopenharmony_ci	struct ice_hw *hw = &vsi->back->hw;
764962306a36Sopenharmony_ci	int status;
765062306a36Sopenharmony_ci
765162306a36Sopenharmony_ci	if (!lut)
765262306a36Sopenharmony_ci		return -EINVAL;
765362306a36Sopenharmony_ci
765462306a36Sopenharmony_ci	params.vsi_handle = vsi->idx;
765562306a36Sopenharmony_ci	params.lut_size = lut_size;
765662306a36Sopenharmony_ci	params.lut_type = vsi->rss_lut_type;
765762306a36Sopenharmony_ci	params.lut = lut;
765862306a36Sopenharmony_ci
765962306a36Sopenharmony_ci	status = ice_aq_get_rss_lut(hw, &params);
766062306a36Sopenharmony_ci	if (status)
766162306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(vsi->back), "Cannot get RSS lut, err %d aq_err %s\n",
766262306a36Sopenharmony_ci			status, ice_aq_str(hw->adminq.sq_last_status));
766362306a36Sopenharmony_ci
766462306a36Sopenharmony_ci	return status;
766562306a36Sopenharmony_ci}
766662306a36Sopenharmony_ci
766762306a36Sopenharmony_ci/**
766862306a36Sopenharmony_ci * ice_get_rss_key - Get RSS key
766962306a36Sopenharmony_ci * @vsi: Pointer to VSI structure
767062306a36Sopenharmony_ci * @seed: Buffer to store the key in
767162306a36Sopenharmony_ci *
767262306a36Sopenharmony_ci * Returns 0 on success, negative on failure
767362306a36Sopenharmony_ci */
767462306a36Sopenharmony_ciint ice_get_rss_key(struct ice_vsi *vsi, u8 *seed)
767562306a36Sopenharmony_ci{
767662306a36Sopenharmony_ci	struct ice_hw *hw = &vsi->back->hw;
767762306a36Sopenharmony_ci	int status;
767862306a36Sopenharmony_ci
767962306a36Sopenharmony_ci	if (!seed)
768062306a36Sopenharmony_ci		return -EINVAL;
768162306a36Sopenharmony_ci
768262306a36Sopenharmony_ci	status = ice_aq_get_rss_key(hw, vsi->idx, (struct ice_aqc_get_set_rss_keys *)seed);
768362306a36Sopenharmony_ci	if (status)
768462306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(vsi->back), "Cannot get RSS key, err %d aq_err %s\n",
768562306a36Sopenharmony_ci			status, ice_aq_str(hw->adminq.sq_last_status));
768662306a36Sopenharmony_ci
768762306a36Sopenharmony_ci	return status;
768862306a36Sopenharmony_ci}
768962306a36Sopenharmony_ci
769062306a36Sopenharmony_ci/**
769162306a36Sopenharmony_ci * ice_bridge_getlink - Get the hardware bridge mode
769262306a36Sopenharmony_ci * @skb: skb buff
769362306a36Sopenharmony_ci * @pid: process ID
769462306a36Sopenharmony_ci * @seq: RTNL message seq
769562306a36Sopenharmony_ci * @dev: the netdev being configured
769662306a36Sopenharmony_ci * @filter_mask: filter mask passed in
769762306a36Sopenharmony_ci * @nlflags: netlink flags passed in
769862306a36Sopenharmony_ci *
769962306a36Sopenharmony_ci * Return the bridge mode (VEB/VEPA)
770062306a36Sopenharmony_ci */
770162306a36Sopenharmony_cistatic int
770262306a36Sopenharmony_ciice_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
770362306a36Sopenharmony_ci		   struct net_device *dev, u32 filter_mask, int nlflags)
770462306a36Sopenharmony_ci{
770562306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(dev);
770662306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
770762306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
770862306a36Sopenharmony_ci	u16 bmode;
770962306a36Sopenharmony_ci
771062306a36Sopenharmony_ci	bmode = pf->first_sw->bridge_mode;
771162306a36Sopenharmony_ci
771262306a36Sopenharmony_ci	return ndo_dflt_bridge_getlink(skb, pid, seq, dev, bmode, 0, 0, nlflags,
771362306a36Sopenharmony_ci				       filter_mask, NULL);
771462306a36Sopenharmony_ci}
771562306a36Sopenharmony_ci
771662306a36Sopenharmony_ci/**
771762306a36Sopenharmony_ci * ice_vsi_update_bridge_mode - Update VSI for switching bridge mode (VEB/VEPA)
771862306a36Sopenharmony_ci * @vsi: Pointer to VSI structure
771962306a36Sopenharmony_ci * @bmode: Hardware bridge mode (VEB/VEPA)
772062306a36Sopenharmony_ci *
772162306a36Sopenharmony_ci * Returns 0 on success, negative on failure
772262306a36Sopenharmony_ci */
772362306a36Sopenharmony_cistatic int ice_vsi_update_bridge_mode(struct ice_vsi *vsi, u16 bmode)
772462306a36Sopenharmony_ci{
772562306a36Sopenharmony_ci	struct ice_aqc_vsi_props *vsi_props;
772662306a36Sopenharmony_ci	struct ice_hw *hw = &vsi->back->hw;
772762306a36Sopenharmony_ci	struct ice_vsi_ctx *ctxt;
772862306a36Sopenharmony_ci	int ret;
772962306a36Sopenharmony_ci
773062306a36Sopenharmony_ci	vsi_props = &vsi->info;
773162306a36Sopenharmony_ci
773262306a36Sopenharmony_ci	ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL);
773362306a36Sopenharmony_ci	if (!ctxt)
773462306a36Sopenharmony_ci		return -ENOMEM;
773562306a36Sopenharmony_ci
773662306a36Sopenharmony_ci	ctxt->info = vsi->info;
773762306a36Sopenharmony_ci
773862306a36Sopenharmony_ci	if (bmode == BRIDGE_MODE_VEB)
773962306a36Sopenharmony_ci		/* change from VEPA to VEB mode */
774062306a36Sopenharmony_ci		ctxt->info.sw_flags |= ICE_AQ_VSI_SW_FLAG_ALLOW_LB;
774162306a36Sopenharmony_ci	else
774262306a36Sopenharmony_ci		/* change from VEB to VEPA mode */
774362306a36Sopenharmony_ci		ctxt->info.sw_flags &= ~ICE_AQ_VSI_SW_FLAG_ALLOW_LB;
774462306a36Sopenharmony_ci	ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SW_VALID);
774562306a36Sopenharmony_ci
774662306a36Sopenharmony_ci	ret = ice_update_vsi(hw, vsi->idx, ctxt, NULL);
774762306a36Sopenharmony_ci	if (ret) {
774862306a36Sopenharmony_ci		dev_err(ice_pf_to_dev(vsi->back), "update VSI for bridge mode failed, bmode = %d err %d aq_err %s\n",
774962306a36Sopenharmony_ci			bmode, ret, ice_aq_str(hw->adminq.sq_last_status));
775062306a36Sopenharmony_ci		goto out;
775162306a36Sopenharmony_ci	}
775262306a36Sopenharmony_ci	/* Update sw flags for book keeping */
775362306a36Sopenharmony_ci	vsi_props->sw_flags = ctxt->info.sw_flags;
775462306a36Sopenharmony_ci
775562306a36Sopenharmony_ciout:
775662306a36Sopenharmony_ci	kfree(ctxt);
775762306a36Sopenharmony_ci	return ret;
775862306a36Sopenharmony_ci}
775962306a36Sopenharmony_ci
776062306a36Sopenharmony_ci/**
776162306a36Sopenharmony_ci * ice_bridge_setlink - Set the hardware bridge mode
776262306a36Sopenharmony_ci * @dev: the netdev being configured
776362306a36Sopenharmony_ci * @nlh: RTNL message
776462306a36Sopenharmony_ci * @flags: bridge setlink flags
776562306a36Sopenharmony_ci * @extack: netlink extended ack
776662306a36Sopenharmony_ci *
776762306a36Sopenharmony_ci * Sets the bridge mode (VEB/VEPA) of the switch to which the netdev (VSI) is
776862306a36Sopenharmony_ci * hooked up to. Iterates through the PF VSI list and sets the loopback mode (if
776962306a36Sopenharmony_ci * not already set for all VSIs connected to this switch. And also update the
777062306a36Sopenharmony_ci * unicast switch filter rules for the corresponding switch of the netdev.
777162306a36Sopenharmony_ci */
777262306a36Sopenharmony_cistatic int
777362306a36Sopenharmony_ciice_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
777462306a36Sopenharmony_ci		   u16 __always_unused flags,
777562306a36Sopenharmony_ci		   struct netlink_ext_ack __always_unused *extack)
777662306a36Sopenharmony_ci{
777762306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(dev);
777862306a36Sopenharmony_ci	struct ice_pf *pf = np->vsi->back;
777962306a36Sopenharmony_ci	struct nlattr *attr, *br_spec;
778062306a36Sopenharmony_ci	struct ice_hw *hw = &pf->hw;
778162306a36Sopenharmony_ci	struct ice_sw *pf_sw;
778262306a36Sopenharmony_ci	int rem, v, err = 0;
778362306a36Sopenharmony_ci
778462306a36Sopenharmony_ci	pf_sw = pf->first_sw;
778562306a36Sopenharmony_ci	/* find the attribute in the netlink message */
778662306a36Sopenharmony_ci	br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
778762306a36Sopenharmony_ci	if (!br_spec)
778862306a36Sopenharmony_ci		return -EINVAL;
778962306a36Sopenharmony_ci
779062306a36Sopenharmony_ci	nla_for_each_nested(attr, br_spec, rem) {
779162306a36Sopenharmony_ci		__u16 mode;
779262306a36Sopenharmony_ci
779362306a36Sopenharmony_ci		if (nla_type(attr) != IFLA_BRIDGE_MODE)
779462306a36Sopenharmony_ci			continue;
779562306a36Sopenharmony_ci		mode = nla_get_u16(attr);
779662306a36Sopenharmony_ci		if (mode != BRIDGE_MODE_VEPA && mode != BRIDGE_MODE_VEB)
779762306a36Sopenharmony_ci			return -EINVAL;
779862306a36Sopenharmony_ci		/* Continue  if bridge mode is not being flipped */
779962306a36Sopenharmony_ci		if (mode == pf_sw->bridge_mode)
780062306a36Sopenharmony_ci			continue;
780162306a36Sopenharmony_ci		/* Iterates through the PF VSI list and update the loopback
780262306a36Sopenharmony_ci		 * mode of the VSI
780362306a36Sopenharmony_ci		 */
780462306a36Sopenharmony_ci		ice_for_each_vsi(pf, v) {
780562306a36Sopenharmony_ci			if (!pf->vsi[v])
780662306a36Sopenharmony_ci				continue;
780762306a36Sopenharmony_ci			err = ice_vsi_update_bridge_mode(pf->vsi[v], mode);
780862306a36Sopenharmony_ci			if (err)
780962306a36Sopenharmony_ci				return err;
781062306a36Sopenharmony_ci		}
781162306a36Sopenharmony_ci
781262306a36Sopenharmony_ci		hw->evb_veb = (mode == BRIDGE_MODE_VEB);
781362306a36Sopenharmony_ci		/* Update the unicast switch filter rules for the corresponding
781462306a36Sopenharmony_ci		 * switch of the netdev
781562306a36Sopenharmony_ci		 */
781662306a36Sopenharmony_ci		err = ice_update_sw_rule_bridge_mode(hw);
781762306a36Sopenharmony_ci		if (err) {
781862306a36Sopenharmony_ci			netdev_err(dev, "switch rule update failed, mode = %d err %d aq_err %s\n",
781962306a36Sopenharmony_ci				   mode, err,
782062306a36Sopenharmony_ci				   ice_aq_str(hw->adminq.sq_last_status));
782162306a36Sopenharmony_ci			/* revert hw->evb_veb */
782262306a36Sopenharmony_ci			hw->evb_veb = (pf_sw->bridge_mode == BRIDGE_MODE_VEB);
782362306a36Sopenharmony_ci			return err;
782462306a36Sopenharmony_ci		}
782562306a36Sopenharmony_ci
782662306a36Sopenharmony_ci		pf_sw->bridge_mode = mode;
782762306a36Sopenharmony_ci	}
782862306a36Sopenharmony_ci
782962306a36Sopenharmony_ci	return 0;
783062306a36Sopenharmony_ci}
783162306a36Sopenharmony_ci
783262306a36Sopenharmony_ci/**
783362306a36Sopenharmony_ci * ice_tx_timeout - Respond to a Tx Hang
783462306a36Sopenharmony_ci * @netdev: network interface device structure
783562306a36Sopenharmony_ci * @txqueue: Tx queue
783662306a36Sopenharmony_ci */
783762306a36Sopenharmony_cistatic void ice_tx_timeout(struct net_device *netdev, unsigned int txqueue)
783862306a36Sopenharmony_ci{
783962306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
784062306a36Sopenharmony_ci	struct ice_tx_ring *tx_ring = NULL;
784162306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
784262306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
784362306a36Sopenharmony_ci	u32 i;
784462306a36Sopenharmony_ci
784562306a36Sopenharmony_ci	pf->tx_timeout_count++;
784662306a36Sopenharmony_ci
784762306a36Sopenharmony_ci	/* Check if PFC is enabled for the TC to which the queue belongs
784862306a36Sopenharmony_ci	 * to. If yes then Tx timeout is not caused by a hung queue, no
784962306a36Sopenharmony_ci	 * need to reset and rebuild
785062306a36Sopenharmony_ci	 */
785162306a36Sopenharmony_ci	if (ice_is_pfc_causing_hung_q(pf, txqueue)) {
785262306a36Sopenharmony_ci		dev_info(ice_pf_to_dev(pf), "Fake Tx hang detected on queue %u, timeout caused by PFC storm\n",
785362306a36Sopenharmony_ci			 txqueue);
785462306a36Sopenharmony_ci		return;
785562306a36Sopenharmony_ci	}
785662306a36Sopenharmony_ci
785762306a36Sopenharmony_ci	/* now that we have an index, find the tx_ring struct */
785862306a36Sopenharmony_ci	ice_for_each_txq(vsi, i)
785962306a36Sopenharmony_ci		if (vsi->tx_rings[i] && vsi->tx_rings[i]->desc)
786062306a36Sopenharmony_ci			if (txqueue == vsi->tx_rings[i]->q_index) {
786162306a36Sopenharmony_ci				tx_ring = vsi->tx_rings[i];
786262306a36Sopenharmony_ci				break;
786362306a36Sopenharmony_ci			}
786462306a36Sopenharmony_ci
786562306a36Sopenharmony_ci	/* Reset recovery level if enough time has elapsed after last timeout.
786662306a36Sopenharmony_ci	 * Also ensure no new reset action happens before next timeout period.
786762306a36Sopenharmony_ci	 */
786862306a36Sopenharmony_ci	if (time_after(jiffies, (pf->tx_timeout_last_recovery + HZ * 20)))
786962306a36Sopenharmony_ci		pf->tx_timeout_recovery_level = 1;
787062306a36Sopenharmony_ci	else if (time_before(jiffies, (pf->tx_timeout_last_recovery +
787162306a36Sopenharmony_ci				       netdev->watchdog_timeo)))
787262306a36Sopenharmony_ci		return;
787362306a36Sopenharmony_ci
787462306a36Sopenharmony_ci	if (tx_ring) {
787562306a36Sopenharmony_ci		struct ice_hw *hw = &pf->hw;
787662306a36Sopenharmony_ci		u32 head, val = 0;
787762306a36Sopenharmony_ci
787862306a36Sopenharmony_ci		head = (rd32(hw, QTX_COMM_HEAD(vsi->txq_map[txqueue])) &
787962306a36Sopenharmony_ci			QTX_COMM_HEAD_HEAD_M) >> QTX_COMM_HEAD_HEAD_S;
788062306a36Sopenharmony_ci		/* Read interrupt register */
788162306a36Sopenharmony_ci		val = rd32(hw, GLINT_DYN_CTL(tx_ring->q_vector->reg_idx));
788262306a36Sopenharmony_ci
788362306a36Sopenharmony_ci		netdev_info(netdev, "tx_timeout: VSI_num: %d, Q %u, NTC: 0x%x, HW_HEAD: 0x%x, NTU: 0x%x, INT: 0x%x\n",
788462306a36Sopenharmony_ci			    vsi->vsi_num, txqueue, tx_ring->next_to_clean,
788562306a36Sopenharmony_ci			    head, tx_ring->next_to_use, val);
788662306a36Sopenharmony_ci	}
788762306a36Sopenharmony_ci
788862306a36Sopenharmony_ci	pf->tx_timeout_last_recovery = jiffies;
788962306a36Sopenharmony_ci	netdev_info(netdev, "tx_timeout recovery level %d, txqueue %u\n",
789062306a36Sopenharmony_ci		    pf->tx_timeout_recovery_level, txqueue);
789162306a36Sopenharmony_ci
789262306a36Sopenharmony_ci	switch (pf->tx_timeout_recovery_level) {
789362306a36Sopenharmony_ci	case 1:
789462306a36Sopenharmony_ci		set_bit(ICE_PFR_REQ, pf->state);
789562306a36Sopenharmony_ci		break;
789662306a36Sopenharmony_ci	case 2:
789762306a36Sopenharmony_ci		set_bit(ICE_CORER_REQ, pf->state);
789862306a36Sopenharmony_ci		break;
789962306a36Sopenharmony_ci	case 3:
790062306a36Sopenharmony_ci		set_bit(ICE_GLOBR_REQ, pf->state);
790162306a36Sopenharmony_ci		break;
790262306a36Sopenharmony_ci	default:
790362306a36Sopenharmony_ci		netdev_err(netdev, "tx_timeout recovery unsuccessful, device is in unrecoverable state.\n");
790462306a36Sopenharmony_ci		set_bit(ICE_DOWN, pf->state);
790562306a36Sopenharmony_ci		set_bit(ICE_VSI_NEEDS_RESTART, vsi->state);
790662306a36Sopenharmony_ci		set_bit(ICE_SERVICE_DIS, pf->state);
790762306a36Sopenharmony_ci		break;
790862306a36Sopenharmony_ci	}
790962306a36Sopenharmony_ci
791062306a36Sopenharmony_ci	ice_service_task_schedule(pf);
791162306a36Sopenharmony_ci	pf->tx_timeout_recovery_level++;
791262306a36Sopenharmony_ci}
791362306a36Sopenharmony_ci
791462306a36Sopenharmony_ci/**
791562306a36Sopenharmony_ci * ice_setup_tc_cls_flower - flower classifier offloads
791662306a36Sopenharmony_ci * @np: net device to configure
791762306a36Sopenharmony_ci * @filter_dev: device on which filter is added
791862306a36Sopenharmony_ci * @cls_flower: offload data
791962306a36Sopenharmony_ci */
792062306a36Sopenharmony_cistatic int
792162306a36Sopenharmony_ciice_setup_tc_cls_flower(struct ice_netdev_priv *np,
792262306a36Sopenharmony_ci			struct net_device *filter_dev,
792362306a36Sopenharmony_ci			struct flow_cls_offload *cls_flower)
792462306a36Sopenharmony_ci{
792562306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
792662306a36Sopenharmony_ci
792762306a36Sopenharmony_ci	if (cls_flower->common.chain_index)
792862306a36Sopenharmony_ci		return -EOPNOTSUPP;
792962306a36Sopenharmony_ci
793062306a36Sopenharmony_ci	switch (cls_flower->command) {
793162306a36Sopenharmony_ci	case FLOW_CLS_REPLACE:
793262306a36Sopenharmony_ci		return ice_add_cls_flower(filter_dev, vsi, cls_flower);
793362306a36Sopenharmony_ci	case FLOW_CLS_DESTROY:
793462306a36Sopenharmony_ci		return ice_del_cls_flower(vsi, cls_flower);
793562306a36Sopenharmony_ci	default:
793662306a36Sopenharmony_ci		return -EINVAL;
793762306a36Sopenharmony_ci	}
793862306a36Sopenharmony_ci}
793962306a36Sopenharmony_ci
794062306a36Sopenharmony_ci/**
794162306a36Sopenharmony_ci * ice_setup_tc_block_cb - callback handler registered for TC block
794262306a36Sopenharmony_ci * @type: TC SETUP type
794362306a36Sopenharmony_ci * @type_data: TC flower offload data that contains user input
794462306a36Sopenharmony_ci * @cb_priv: netdev private data
794562306a36Sopenharmony_ci */
794662306a36Sopenharmony_cistatic int
794762306a36Sopenharmony_ciice_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
794862306a36Sopenharmony_ci{
794962306a36Sopenharmony_ci	struct ice_netdev_priv *np = cb_priv;
795062306a36Sopenharmony_ci
795162306a36Sopenharmony_ci	switch (type) {
795262306a36Sopenharmony_ci	case TC_SETUP_CLSFLOWER:
795362306a36Sopenharmony_ci		return ice_setup_tc_cls_flower(np, np->vsi->netdev,
795462306a36Sopenharmony_ci					       type_data);
795562306a36Sopenharmony_ci	default:
795662306a36Sopenharmony_ci		return -EOPNOTSUPP;
795762306a36Sopenharmony_ci	}
795862306a36Sopenharmony_ci}
795962306a36Sopenharmony_ci
796062306a36Sopenharmony_ci/**
796162306a36Sopenharmony_ci * ice_validate_mqprio_qopt - Validate TCF input parameters
796262306a36Sopenharmony_ci * @vsi: Pointer to VSI
796362306a36Sopenharmony_ci * @mqprio_qopt: input parameters for mqprio queue configuration
796462306a36Sopenharmony_ci *
796562306a36Sopenharmony_ci * This function validates MQPRIO params, such as qcount (power of 2 wherever
796662306a36Sopenharmony_ci * needed), and make sure user doesn't specify qcount and BW rate limit
796762306a36Sopenharmony_ci * for TCs, which are more than "num_tc"
796862306a36Sopenharmony_ci */
796962306a36Sopenharmony_cistatic int
797062306a36Sopenharmony_ciice_validate_mqprio_qopt(struct ice_vsi *vsi,
797162306a36Sopenharmony_ci			 struct tc_mqprio_qopt_offload *mqprio_qopt)
797262306a36Sopenharmony_ci{
797362306a36Sopenharmony_ci	int non_power_of_2_qcount = 0;
797462306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
797562306a36Sopenharmony_ci	int max_rss_q_cnt = 0;
797662306a36Sopenharmony_ci	u64 sum_min_rate = 0;
797762306a36Sopenharmony_ci	struct device *dev;
797862306a36Sopenharmony_ci	int i, speed;
797962306a36Sopenharmony_ci	u8 num_tc;
798062306a36Sopenharmony_ci
798162306a36Sopenharmony_ci	if (vsi->type != ICE_VSI_PF)
798262306a36Sopenharmony_ci		return -EINVAL;
798362306a36Sopenharmony_ci
798462306a36Sopenharmony_ci	if (mqprio_qopt->qopt.offset[0] != 0 ||
798562306a36Sopenharmony_ci	    mqprio_qopt->qopt.num_tc < 1 ||
798662306a36Sopenharmony_ci	    mqprio_qopt->qopt.num_tc > ICE_CHNL_MAX_TC)
798762306a36Sopenharmony_ci		return -EINVAL;
798862306a36Sopenharmony_ci
798962306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
799062306a36Sopenharmony_ci	vsi->ch_rss_size = 0;
799162306a36Sopenharmony_ci	num_tc = mqprio_qopt->qopt.num_tc;
799262306a36Sopenharmony_ci	speed = ice_get_link_speed_kbps(vsi);
799362306a36Sopenharmony_ci
799462306a36Sopenharmony_ci	for (i = 0; num_tc; i++) {
799562306a36Sopenharmony_ci		int qcount = mqprio_qopt->qopt.count[i];
799662306a36Sopenharmony_ci		u64 max_rate, min_rate, rem;
799762306a36Sopenharmony_ci
799862306a36Sopenharmony_ci		if (!qcount)
799962306a36Sopenharmony_ci			return -EINVAL;
800062306a36Sopenharmony_ci
800162306a36Sopenharmony_ci		if (is_power_of_2(qcount)) {
800262306a36Sopenharmony_ci			if (non_power_of_2_qcount &&
800362306a36Sopenharmony_ci			    qcount > non_power_of_2_qcount) {
800462306a36Sopenharmony_ci				dev_err(dev, "qcount[%d] cannot be greater than non power of 2 qcount[%d]\n",
800562306a36Sopenharmony_ci					qcount, non_power_of_2_qcount);
800662306a36Sopenharmony_ci				return -EINVAL;
800762306a36Sopenharmony_ci			}
800862306a36Sopenharmony_ci			if (qcount > max_rss_q_cnt)
800962306a36Sopenharmony_ci				max_rss_q_cnt = qcount;
801062306a36Sopenharmony_ci		} else {
801162306a36Sopenharmony_ci			if (non_power_of_2_qcount &&
801262306a36Sopenharmony_ci			    qcount != non_power_of_2_qcount) {
801362306a36Sopenharmony_ci				dev_err(dev, "Only one non power of 2 qcount allowed[%d,%d]\n",
801462306a36Sopenharmony_ci					qcount, non_power_of_2_qcount);
801562306a36Sopenharmony_ci				return -EINVAL;
801662306a36Sopenharmony_ci			}
801762306a36Sopenharmony_ci			if (qcount < max_rss_q_cnt) {
801862306a36Sopenharmony_ci				dev_err(dev, "non power of 2 qcount[%d] cannot be less than other qcount[%d]\n",
801962306a36Sopenharmony_ci					qcount, max_rss_q_cnt);
802062306a36Sopenharmony_ci				return -EINVAL;
802162306a36Sopenharmony_ci			}
802262306a36Sopenharmony_ci			max_rss_q_cnt = qcount;
802362306a36Sopenharmony_ci			non_power_of_2_qcount = qcount;
802462306a36Sopenharmony_ci		}
802562306a36Sopenharmony_ci
802662306a36Sopenharmony_ci		/* TC command takes input in K/N/Gbps or K/M/Gbit etc but
802762306a36Sopenharmony_ci		 * converts the bandwidth rate limit into Bytes/s when
802862306a36Sopenharmony_ci		 * passing it down to the driver. So convert input bandwidth
802962306a36Sopenharmony_ci		 * from Bytes/s to Kbps
803062306a36Sopenharmony_ci		 */
803162306a36Sopenharmony_ci		max_rate = mqprio_qopt->max_rate[i];
803262306a36Sopenharmony_ci		max_rate = div_u64(max_rate, ICE_BW_KBPS_DIVISOR);
803362306a36Sopenharmony_ci
803462306a36Sopenharmony_ci		/* min_rate is minimum guaranteed rate and it can't be zero */
803562306a36Sopenharmony_ci		min_rate = mqprio_qopt->min_rate[i];
803662306a36Sopenharmony_ci		min_rate = div_u64(min_rate, ICE_BW_KBPS_DIVISOR);
803762306a36Sopenharmony_ci		sum_min_rate += min_rate;
803862306a36Sopenharmony_ci
803962306a36Sopenharmony_ci		if (min_rate && min_rate < ICE_MIN_BW_LIMIT) {
804062306a36Sopenharmony_ci			dev_err(dev, "TC%d: min_rate(%llu Kbps) < %u Kbps\n", i,
804162306a36Sopenharmony_ci				min_rate, ICE_MIN_BW_LIMIT);
804262306a36Sopenharmony_ci			return -EINVAL;
804362306a36Sopenharmony_ci		}
804462306a36Sopenharmony_ci
804562306a36Sopenharmony_ci		if (max_rate && max_rate > speed) {
804662306a36Sopenharmony_ci			dev_err(dev, "TC%d: max_rate(%llu Kbps) > link speed of %u Kbps\n",
804762306a36Sopenharmony_ci				i, max_rate, speed);
804862306a36Sopenharmony_ci			return -EINVAL;
804962306a36Sopenharmony_ci		}
805062306a36Sopenharmony_ci
805162306a36Sopenharmony_ci		iter_div_u64_rem(min_rate, ICE_MIN_BW_LIMIT, &rem);
805262306a36Sopenharmony_ci		if (rem) {
805362306a36Sopenharmony_ci			dev_err(dev, "TC%d: Min Rate not multiple of %u Kbps",
805462306a36Sopenharmony_ci				i, ICE_MIN_BW_LIMIT);
805562306a36Sopenharmony_ci			return -EINVAL;
805662306a36Sopenharmony_ci		}
805762306a36Sopenharmony_ci
805862306a36Sopenharmony_ci		iter_div_u64_rem(max_rate, ICE_MIN_BW_LIMIT, &rem);
805962306a36Sopenharmony_ci		if (rem) {
806062306a36Sopenharmony_ci			dev_err(dev, "TC%d: Max Rate not multiple of %u Kbps",
806162306a36Sopenharmony_ci				i, ICE_MIN_BW_LIMIT);
806262306a36Sopenharmony_ci			return -EINVAL;
806362306a36Sopenharmony_ci		}
806462306a36Sopenharmony_ci
806562306a36Sopenharmony_ci		/* min_rate can't be more than max_rate, except when max_rate
806662306a36Sopenharmony_ci		 * is zero (implies max_rate sought is max line rate). In such
806762306a36Sopenharmony_ci		 * a case min_rate can be more than max.
806862306a36Sopenharmony_ci		 */
806962306a36Sopenharmony_ci		if (max_rate && min_rate > max_rate) {
807062306a36Sopenharmony_ci			dev_err(dev, "min_rate %llu Kbps can't be more than max_rate %llu Kbps\n",
807162306a36Sopenharmony_ci				min_rate, max_rate);
807262306a36Sopenharmony_ci			return -EINVAL;
807362306a36Sopenharmony_ci		}
807462306a36Sopenharmony_ci
807562306a36Sopenharmony_ci		if (i >= mqprio_qopt->qopt.num_tc - 1)
807662306a36Sopenharmony_ci			break;
807762306a36Sopenharmony_ci		if (mqprio_qopt->qopt.offset[i + 1] !=
807862306a36Sopenharmony_ci		    (mqprio_qopt->qopt.offset[i] + qcount))
807962306a36Sopenharmony_ci			return -EINVAL;
808062306a36Sopenharmony_ci	}
808162306a36Sopenharmony_ci	if (vsi->num_rxq <
808262306a36Sopenharmony_ci	    (mqprio_qopt->qopt.offset[i] + mqprio_qopt->qopt.count[i]))
808362306a36Sopenharmony_ci		return -EINVAL;
808462306a36Sopenharmony_ci	if (vsi->num_txq <
808562306a36Sopenharmony_ci	    (mqprio_qopt->qopt.offset[i] + mqprio_qopt->qopt.count[i]))
808662306a36Sopenharmony_ci		return -EINVAL;
808762306a36Sopenharmony_ci
808862306a36Sopenharmony_ci	if (sum_min_rate && sum_min_rate > (u64)speed) {
808962306a36Sopenharmony_ci		dev_err(dev, "Invalid min Tx rate(%llu) Kbps > speed (%u) Kbps specified\n",
809062306a36Sopenharmony_ci			sum_min_rate, speed);
809162306a36Sopenharmony_ci		return -EINVAL;
809262306a36Sopenharmony_ci	}
809362306a36Sopenharmony_ci
809462306a36Sopenharmony_ci	/* make sure vsi->ch_rss_size is set correctly based on TC's qcount */
809562306a36Sopenharmony_ci	vsi->ch_rss_size = max_rss_q_cnt;
809662306a36Sopenharmony_ci
809762306a36Sopenharmony_ci	return 0;
809862306a36Sopenharmony_ci}
809962306a36Sopenharmony_ci
810062306a36Sopenharmony_ci/**
810162306a36Sopenharmony_ci * ice_add_vsi_to_fdir - add a VSI to the flow director group for PF
810262306a36Sopenharmony_ci * @pf: ptr to PF device
810362306a36Sopenharmony_ci * @vsi: ptr to VSI
810462306a36Sopenharmony_ci */
810562306a36Sopenharmony_cistatic int ice_add_vsi_to_fdir(struct ice_pf *pf, struct ice_vsi *vsi)
810662306a36Sopenharmony_ci{
810762306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
810862306a36Sopenharmony_ci	bool added = false;
810962306a36Sopenharmony_ci	struct ice_hw *hw;
811062306a36Sopenharmony_ci	int flow;
811162306a36Sopenharmony_ci
811262306a36Sopenharmony_ci	if (!(vsi->num_gfltr || vsi->num_bfltr))
811362306a36Sopenharmony_ci		return -EINVAL;
811462306a36Sopenharmony_ci
811562306a36Sopenharmony_ci	hw = &pf->hw;
811662306a36Sopenharmony_ci	for (flow = 0; flow < ICE_FLTR_PTYPE_MAX; flow++) {
811762306a36Sopenharmony_ci		struct ice_fd_hw_prof *prof;
811862306a36Sopenharmony_ci		int tun, status;
811962306a36Sopenharmony_ci		u64 entry_h;
812062306a36Sopenharmony_ci
812162306a36Sopenharmony_ci		if (!(hw->fdir_prof && hw->fdir_prof[flow] &&
812262306a36Sopenharmony_ci		      hw->fdir_prof[flow]->cnt))
812362306a36Sopenharmony_ci			continue;
812462306a36Sopenharmony_ci
812562306a36Sopenharmony_ci		for (tun = 0; tun < ICE_FD_HW_SEG_MAX; tun++) {
812662306a36Sopenharmony_ci			enum ice_flow_priority prio;
812762306a36Sopenharmony_ci			u64 prof_id;
812862306a36Sopenharmony_ci
812962306a36Sopenharmony_ci			/* add this VSI to FDir profile for this flow */
813062306a36Sopenharmony_ci			prio = ICE_FLOW_PRIO_NORMAL;
813162306a36Sopenharmony_ci			prof = hw->fdir_prof[flow];
813262306a36Sopenharmony_ci			prof_id = flow + tun * ICE_FLTR_PTYPE_MAX;
813362306a36Sopenharmony_ci			status = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id,
813462306a36Sopenharmony_ci						    prof->vsi_h[0], vsi->idx,
813562306a36Sopenharmony_ci						    prio, prof->fdir_seg[tun],
813662306a36Sopenharmony_ci						    &entry_h);
813762306a36Sopenharmony_ci			if (status) {
813862306a36Sopenharmony_ci				dev_err(dev, "channel VSI idx %d, not able to add to group %d\n",
813962306a36Sopenharmony_ci					vsi->idx, flow);
814062306a36Sopenharmony_ci				continue;
814162306a36Sopenharmony_ci			}
814262306a36Sopenharmony_ci
814362306a36Sopenharmony_ci			prof->entry_h[prof->cnt][tun] = entry_h;
814462306a36Sopenharmony_ci		}
814562306a36Sopenharmony_ci
814662306a36Sopenharmony_ci		/* store VSI for filter replay and delete */
814762306a36Sopenharmony_ci		prof->vsi_h[prof->cnt] = vsi->idx;
814862306a36Sopenharmony_ci		prof->cnt++;
814962306a36Sopenharmony_ci
815062306a36Sopenharmony_ci		added = true;
815162306a36Sopenharmony_ci		dev_dbg(dev, "VSI idx %d added to fdir group %d\n", vsi->idx,
815262306a36Sopenharmony_ci			flow);
815362306a36Sopenharmony_ci	}
815462306a36Sopenharmony_ci
815562306a36Sopenharmony_ci	if (!added)
815662306a36Sopenharmony_ci		dev_dbg(dev, "VSI idx %d not added to fdir groups\n", vsi->idx);
815762306a36Sopenharmony_ci
815862306a36Sopenharmony_ci	return 0;
815962306a36Sopenharmony_ci}
816062306a36Sopenharmony_ci
816162306a36Sopenharmony_ci/**
816262306a36Sopenharmony_ci * ice_add_channel - add a channel by adding VSI
816362306a36Sopenharmony_ci * @pf: ptr to PF device
816462306a36Sopenharmony_ci * @sw_id: underlying HW switching element ID
816562306a36Sopenharmony_ci * @ch: ptr to channel structure
816662306a36Sopenharmony_ci *
816762306a36Sopenharmony_ci * Add a channel (VSI) using add_vsi and queue_map
816862306a36Sopenharmony_ci */
816962306a36Sopenharmony_cistatic int ice_add_channel(struct ice_pf *pf, u16 sw_id, struct ice_channel *ch)
817062306a36Sopenharmony_ci{
817162306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
817262306a36Sopenharmony_ci	struct ice_vsi *vsi;
817362306a36Sopenharmony_ci
817462306a36Sopenharmony_ci	if (ch->type != ICE_VSI_CHNL) {
817562306a36Sopenharmony_ci		dev_err(dev, "add new VSI failed, ch->type %d\n", ch->type);
817662306a36Sopenharmony_ci		return -EINVAL;
817762306a36Sopenharmony_ci	}
817862306a36Sopenharmony_ci
817962306a36Sopenharmony_ci	vsi = ice_chnl_vsi_setup(pf, pf->hw.port_info, ch);
818062306a36Sopenharmony_ci	if (!vsi || vsi->type != ICE_VSI_CHNL) {
818162306a36Sopenharmony_ci		dev_err(dev, "create chnl VSI failure\n");
818262306a36Sopenharmony_ci		return -EINVAL;
818362306a36Sopenharmony_ci	}
818462306a36Sopenharmony_ci
818562306a36Sopenharmony_ci	ice_add_vsi_to_fdir(pf, vsi);
818662306a36Sopenharmony_ci
818762306a36Sopenharmony_ci	ch->sw_id = sw_id;
818862306a36Sopenharmony_ci	ch->vsi_num = vsi->vsi_num;
818962306a36Sopenharmony_ci	ch->info.mapping_flags = vsi->info.mapping_flags;
819062306a36Sopenharmony_ci	ch->ch_vsi = vsi;
819162306a36Sopenharmony_ci	/* set the back pointer of channel for newly created VSI */
819262306a36Sopenharmony_ci	vsi->ch = ch;
819362306a36Sopenharmony_ci
819462306a36Sopenharmony_ci	memcpy(&ch->info.q_mapping, &vsi->info.q_mapping,
819562306a36Sopenharmony_ci	       sizeof(vsi->info.q_mapping));
819662306a36Sopenharmony_ci	memcpy(&ch->info.tc_mapping, vsi->info.tc_mapping,
819762306a36Sopenharmony_ci	       sizeof(vsi->info.tc_mapping));
819862306a36Sopenharmony_ci
819962306a36Sopenharmony_ci	return 0;
820062306a36Sopenharmony_ci}
820162306a36Sopenharmony_ci
820262306a36Sopenharmony_ci/**
820362306a36Sopenharmony_ci * ice_chnl_cfg_res
820462306a36Sopenharmony_ci * @vsi: the VSI being setup
820562306a36Sopenharmony_ci * @ch: ptr to channel structure
820662306a36Sopenharmony_ci *
820762306a36Sopenharmony_ci * Configure channel specific resources such as rings, vector.
820862306a36Sopenharmony_ci */
820962306a36Sopenharmony_cistatic void ice_chnl_cfg_res(struct ice_vsi *vsi, struct ice_channel *ch)
821062306a36Sopenharmony_ci{
821162306a36Sopenharmony_ci	int i;
821262306a36Sopenharmony_ci
821362306a36Sopenharmony_ci	for (i = 0; i < ch->num_txq; i++) {
821462306a36Sopenharmony_ci		struct ice_q_vector *tx_q_vector, *rx_q_vector;
821562306a36Sopenharmony_ci		struct ice_ring_container *rc;
821662306a36Sopenharmony_ci		struct ice_tx_ring *tx_ring;
821762306a36Sopenharmony_ci		struct ice_rx_ring *rx_ring;
821862306a36Sopenharmony_ci
821962306a36Sopenharmony_ci		tx_ring = vsi->tx_rings[ch->base_q + i];
822062306a36Sopenharmony_ci		rx_ring = vsi->rx_rings[ch->base_q + i];
822162306a36Sopenharmony_ci		if (!tx_ring || !rx_ring)
822262306a36Sopenharmony_ci			continue;
822362306a36Sopenharmony_ci
822462306a36Sopenharmony_ci		/* setup ring being channel enabled */
822562306a36Sopenharmony_ci		tx_ring->ch = ch;
822662306a36Sopenharmony_ci		rx_ring->ch = ch;
822762306a36Sopenharmony_ci
822862306a36Sopenharmony_ci		/* following code block sets up vector specific attributes */
822962306a36Sopenharmony_ci		tx_q_vector = tx_ring->q_vector;
823062306a36Sopenharmony_ci		rx_q_vector = rx_ring->q_vector;
823162306a36Sopenharmony_ci		if (!tx_q_vector && !rx_q_vector)
823262306a36Sopenharmony_ci			continue;
823362306a36Sopenharmony_ci
823462306a36Sopenharmony_ci		if (tx_q_vector) {
823562306a36Sopenharmony_ci			tx_q_vector->ch = ch;
823662306a36Sopenharmony_ci			/* setup Tx and Rx ITR setting if DIM is off */
823762306a36Sopenharmony_ci			rc = &tx_q_vector->tx;
823862306a36Sopenharmony_ci			if (!ITR_IS_DYNAMIC(rc))
823962306a36Sopenharmony_ci				ice_write_itr(rc, rc->itr_setting);
824062306a36Sopenharmony_ci		}
824162306a36Sopenharmony_ci		if (rx_q_vector) {
824262306a36Sopenharmony_ci			rx_q_vector->ch = ch;
824362306a36Sopenharmony_ci			/* setup Tx and Rx ITR setting if DIM is off */
824462306a36Sopenharmony_ci			rc = &rx_q_vector->rx;
824562306a36Sopenharmony_ci			if (!ITR_IS_DYNAMIC(rc))
824662306a36Sopenharmony_ci				ice_write_itr(rc, rc->itr_setting);
824762306a36Sopenharmony_ci		}
824862306a36Sopenharmony_ci	}
824962306a36Sopenharmony_ci
825062306a36Sopenharmony_ci	/* it is safe to assume that, if channel has non-zero num_t[r]xq, then
825162306a36Sopenharmony_ci	 * GLINT_ITR register would have written to perform in-context
825262306a36Sopenharmony_ci	 * update, hence perform flush
825362306a36Sopenharmony_ci	 */
825462306a36Sopenharmony_ci	if (ch->num_txq || ch->num_rxq)
825562306a36Sopenharmony_ci		ice_flush(&vsi->back->hw);
825662306a36Sopenharmony_ci}
825762306a36Sopenharmony_ci
825862306a36Sopenharmony_ci/**
825962306a36Sopenharmony_ci * ice_cfg_chnl_all_res - configure channel resources
826062306a36Sopenharmony_ci * @vsi: pte to main_vsi
826162306a36Sopenharmony_ci * @ch: ptr to channel structure
826262306a36Sopenharmony_ci *
826362306a36Sopenharmony_ci * This function configures channel specific resources such as flow-director
826462306a36Sopenharmony_ci * counter index, and other resources such as queues, vectors, ITR settings
826562306a36Sopenharmony_ci */
826662306a36Sopenharmony_cistatic void
826762306a36Sopenharmony_ciice_cfg_chnl_all_res(struct ice_vsi *vsi, struct ice_channel *ch)
826862306a36Sopenharmony_ci{
826962306a36Sopenharmony_ci	/* configure channel (aka ADQ) resources such as queues, vectors,
827062306a36Sopenharmony_ci	 * ITR settings for channel specific vectors and anything else
827162306a36Sopenharmony_ci	 */
827262306a36Sopenharmony_ci	ice_chnl_cfg_res(vsi, ch);
827362306a36Sopenharmony_ci}
827462306a36Sopenharmony_ci
827562306a36Sopenharmony_ci/**
827662306a36Sopenharmony_ci * ice_setup_hw_channel - setup new channel
827762306a36Sopenharmony_ci * @pf: ptr to PF device
827862306a36Sopenharmony_ci * @vsi: the VSI being setup
827962306a36Sopenharmony_ci * @ch: ptr to channel structure
828062306a36Sopenharmony_ci * @sw_id: underlying HW switching element ID
828162306a36Sopenharmony_ci * @type: type of channel to be created (VMDq2/VF)
828262306a36Sopenharmony_ci *
828362306a36Sopenharmony_ci * Setup new channel (VSI) based on specified type (VMDq2/VF)
828462306a36Sopenharmony_ci * and configures Tx rings accordingly
828562306a36Sopenharmony_ci */
828662306a36Sopenharmony_cistatic int
828762306a36Sopenharmony_ciice_setup_hw_channel(struct ice_pf *pf, struct ice_vsi *vsi,
828862306a36Sopenharmony_ci		     struct ice_channel *ch, u16 sw_id, u8 type)
828962306a36Sopenharmony_ci{
829062306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
829162306a36Sopenharmony_ci	int ret;
829262306a36Sopenharmony_ci
829362306a36Sopenharmony_ci	ch->base_q = vsi->next_base_q;
829462306a36Sopenharmony_ci	ch->type = type;
829562306a36Sopenharmony_ci
829662306a36Sopenharmony_ci	ret = ice_add_channel(pf, sw_id, ch);
829762306a36Sopenharmony_ci	if (ret) {
829862306a36Sopenharmony_ci		dev_err(dev, "failed to add_channel using sw_id %u\n", sw_id);
829962306a36Sopenharmony_ci		return ret;
830062306a36Sopenharmony_ci	}
830162306a36Sopenharmony_ci
830262306a36Sopenharmony_ci	/* configure/setup ADQ specific resources */
830362306a36Sopenharmony_ci	ice_cfg_chnl_all_res(vsi, ch);
830462306a36Sopenharmony_ci
830562306a36Sopenharmony_ci	/* make sure to update the next_base_q so that subsequent channel's
830662306a36Sopenharmony_ci	 * (aka ADQ) VSI queue map is correct
830762306a36Sopenharmony_ci	 */
830862306a36Sopenharmony_ci	vsi->next_base_q = vsi->next_base_q + ch->num_rxq;
830962306a36Sopenharmony_ci	dev_dbg(dev, "added channel: vsi_num %u, num_rxq %u\n", ch->vsi_num,
831062306a36Sopenharmony_ci		ch->num_rxq);
831162306a36Sopenharmony_ci
831262306a36Sopenharmony_ci	return 0;
831362306a36Sopenharmony_ci}
831462306a36Sopenharmony_ci
831562306a36Sopenharmony_ci/**
831662306a36Sopenharmony_ci * ice_setup_channel - setup new channel using uplink element
831762306a36Sopenharmony_ci * @pf: ptr to PF device
831862306a36Sopenharmony_ci * @vsi: the VSI being setup
831962306a36Sopenharmony_ci * @ch: ptr to channel structure
832062306a36Sopenharmony_ci *
832162306a36Sopenharmony_ci * Setup new channel (VSI) based on specified type (VMDq2/VF)
832262306a36Sopenharmony_ci * and uplink switching element
832362306a36Sopenharmony_ci */
832462306a36Sopenharmony_cistatic bool
832562306a36Sopenharmony_ciice_setup_channel(struct ice_pf *pf, struct ice_vsi *vsi,
832662306a36Sopenharmony_ci		  struct ice_channel *ch)
832762306a36Sopenharmony_ci{
832862306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
832962306a36Sopenharmony_ci	u16 sw_id;
833062306a36Sopenharmony_ci	int ret;
833162306a36Sopenharmony_ci
833262306a36Sopenharmony_ci	if (vsi->type != ICE_VSI_PF) {
833362306a36Sopenharmony_ci		dev_err(dev, "unsupported parent VSI type(%d)\n", vsi->type);
833462306a36Sopenharmony_ci		return false;
833562306a36Sopenharmony_ci	}
833662306a36Sopenharmony_ci
833762306a36Sopenharmony_ci	sw_id = pf->first_sw->sw_id;
833862306a36Sopenharmony_ci
833962306a36Sopenharmony_ci	/* create channel (VSI) */
834062306a36Sopenharmony_ci	ret = ice_setup_hw_channel(pf, vsi, ch, sw_id, ICE_VSI_CHNL);
834162306a36Sopenharmony_ci	if (ret) {
834262306a36Sopenharmony_ci		dev_err(dev, "failed to setup hw_channel\n");
834362306a36Sopenharmony_ci		return false;
834462306a36Sopenharmony_ci	}
834562306a36Sopenharmony_ci	dev_dbg(dev, "successfully created channel()\n");
834662306a36Sopenharmony_ci
834762306a36Sopenharmony_ci	return ch->ch_vsi ? true : false;
834862306a36Sopenharmony_ci}
834962306a36Sopenharmony_ci
835062306a36Sopenharmony_ci/**
835162306a36Sopenharmony_ci * ice_set_bw_limit - setup BW limit for Tx traffic based on max_tx_rate
835262306a36Sopenharmony_ci * @vsi: VSI to be configured
835362306a36Sopenharmony_ci * @max_tx_rate: max Tx rate in Kbps to be configured as maximum BW limit
835462306a36Sopenharmony_ci * @min_tx_rate: min Tx rate in Kbps to be configured as minimum BW limit
835562306a36Sopenharmony_ci */
835662306a36Sopenharmony_cistatic int
835762306a36Sopenharmony_ciice_set_bw_limit(struct ice_vsi *vsi, u64 max_tx_rate, u64 min_tx_rate)
835862306a36Sopenharmony_ci{
835962306a36Sopenharmony_ci	int err;
836062306a36Sopenharmony_ci
836162306a36Sopenharmony_ci	err = ice_set_min_bw_limit(vsi, min_tx_rate);
836262306a36Sopenharmony_ci	if (err)
836362306a36Sopenharmony_ci		return err;
836462306a36Sopenharmony_ci
836562306a36Sopenharmony_ci	return ice_set_max_bw_limit(vsi, max_tx_rate);
836662306a36Sopenharmony_ci}
836762306a36Sopenharmony_ci
836862306a36Sopenharmony_ci/**
836962306a36Sopenharmony_ci * ice_create_q_channel - function to create channel
837062306a36Sopenharmony_ci * @vsi: VSI to be configured
837162306a36Sopenharmony_ci * @ch: ptr to channel (it contains channel specific params)
837262306a36Sopenharmony_ci *
837362306a36Sopenharmony_ci * This function creates channel (VSI) using num_queues specified by user,
837462306a36Sopenharmony_ci * reconfigs RSS if needed.
837562306a36Sopenharmony_ci */
837662306a36Sopenharmony_cistatic int ice_create_q_channel(struct ice_vsi *vsi, struct ice_channel *ch)
837762306a36Sopenharmony_ci{
837862306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
837962306a36Sopenharmony_ci	struct device *dev;
838062306a36Sopenharmony_ci
838162306a36Sopenharmony_ci	if (!ch)
838262306a36Sopenharmony_ci		return -EINVAL;
838362306a36Sopenharmony_ci
838462306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
838562306a36Sopenharmony_ci	if (!ch->num_txq || !ch->num_rxq) {
838662306a36Sopenharmony_ci		dev_err(dev, "Invalid num_queues requested: %d\n", ch->num_rxq);
838762306a36Sopenharmony_ci		return -EINVAL;
838862306a36Sopenharmony_ci	}
838962306a36Sopenharmony_ci
839062306a36Sopenharmony_ci	if (!vsi->cnt_q_avail || vsi->cnt_q_avail < ch->num_txq) {
839162306a36Sopenharmony_ci		dev_err(dev, "cnt_q_avail (%u) less than num_queues %d\n",
839262306a36Sopenharmony_ci			vsi->cnt_q_avail, ch->num_txq);
839362306a36Sopenharmony_ci		return -EINVAL;
839462306a36Sopenharmony_ci	}
839562306a36Sopenharmony_ci
839662306a36Sopenharmony_ci	if (!ice_setup_channel(pf, vsi, ch)) {
839762306a36Sopenharmony_ci		dev_info(dev, "Failed to setup channel\n");
839862306a36Sopenharmony_ci		return -EINVAL;
839962306a36Sopenharmony_ci	}
840062306a36Sopenharmony_ci	/* configure BW rate limit */
840162306a36Sopenharmony_ci	if (ch->ch_vsi && (ch->max_tx_rate || ch->min_tx_rate)) {
840262306a36Sopenharmony_ci		int ret;
840362306a36Sopenharmony_ci
840462306a36Sopenharmony_ci		ret = ice_set_bw_limit(ch->ch_vsi, ch->max_tx_rate,
840562306a36Sopenharmony_ci				       ch->min_tx_rate);
840662306a36Sopenharmony_ci		if (ret)
840762306a36Sopenharmony_ci			dev_err(dev, "failed to set Tx rate of %llu Kbps for VSI(%u)\n",
840862306a36Sopenharmony_ci				ch->max_tx_rate, ch->ch_vsi->vsi_num);
840962306a36Sopenharmony_ci		else
841062306a36Sopenharmony_ci			dev_dbg(dev, "set Tx rate of %llu Kbps for VSI(%u)\n",
841162306a36Sopenharmony_ci				ch->max_tx_rate, ch->ch_vsi->vsi_num);
841262306a36Sopenharmony_ci	}
841362306a36Sopenharmony_ci
841462306a36Sopenharmony_ci	vsi->cnt_q_avail -= ch->num_txq;
841562306a36Sopenharmony_ci
841662306a36Sopenharmony_ci	return 0;
841762306a36Sopenharmony_ci}
841862306a36Sopenharmony_ci
841962306a36Sopenharmony_ci/**
842062306a36Sopenharmony_ci * ice_rem_all_chnl_fltrs - removes all channel filters
842162306a36Sopenharmony_ci * @pf: ptr to PF, TC-flower based filter are tracked at PF level
842262306a36Sopenharmony_ci *
842362306a36Sopenharmony_ci * Remove all advanced switch filters only if they are channel specific
842462306a36Sopenharmony_ci * tc-flower based filter
842562306a36Sopenharmony_ci */
842662306a36Sopenharmony_cistatic void ice_rem_all_chnl_fltrs(struct ice_pf *pf)
842762306a36Sopenharmony_ci{
842862306a36Sopenharmony_ci	struct ice_tc_flower_fltr *fltr;
842962306a36Sopenharmony_ci	struct hlist_node *node;
843062306a36Sopenharmony_ci
843162306a36Sopenharmony_ci	/* to remove all channel filters, iterate an ordered list of filters */
843262306a36Sopenharmony_ci	hlist_for_each_entry_safe(fltr, node,
843362306a36Sopenharmony_ci				  &pf->tc_flower_fltr_list,
843462306a36Sopenharmony_ci				  tc_flower_node) {
843562306a36Sopenharmony_ci		struct ice_rule_query_data rule;
843662306a36Sopenharmony_ci		int status;
843762306a36Sopenharmony_ci
843862306a36Sopenharmony_ci		/* for now process only channel specific filters */
843962306a36Sopenharmony_ci		if (!ice_is_chnl_fltr(fltr))
844062306a36Sopenharmony_ci			continue;
844162306a36Sopenharmony_ci
844262306a36Sopenharmony_ci		rule.rid = fltr->rid;
844362306a36Sopenharmony_ci		rule.rule_id = fltr->rule_id;
844462306a36Sopenharmony_ci		rule.vsi_handle = fltr->dest_vsi_handle;
844562306a36Sopenharmony_ci		status = ice_rem_adv_rule_by_id(&pf->hw, &rule);
844662306a36Sopenharmony_ci		if (status) {
844762306a36Sopenharmony_ci			if (status == -ENOENT)
844862306a36Sopenharmony_ci				dev_dbg(ice_pf_to_dev(pf), "TC flower filter (rule_id %u) does not exist\n",
844962306a36Sopenharmony_ci					rule.rule_id);
845062306a36Sopenharmony_ci			else
845162306a36Sopenharmony_ci				dev_err(ice_pf_to_dev(pf), "failed to delete TC flower filter, status %d\n",
845262306a36Sopenharmony_ci					status);
845362306a36Sopenharmony_ci		} else if (fltr->dest_vsi) {
845462306a36Sopenharmony_ci			/* update advanced switch filter count */
845562306a36Sopenharmony_ci			if (fltr->dest_vsi->type == ICE_VSI_CHNL) {
845662306a36Sopenharmony_ci				u32 flags = fltr->flags;
845762306a36Sopenharmony_ci
845862306a36Sopenharmony_ci				fltr->dest_vsi->num_chnl_fltr--;
845962306a36Sopenharmony_ci				if (flags & (ICE_TC_FLWR_FIELD_DST_MAC |
846062306a36Sopenharmony_ci					     ICE_TC_FLWR_FIELD_ENC_DST_MAC))
846162306a36Sopenharmony_ci					pf->num_dmac_chnl_fltrs--;
846262306a36Sopenharmony_ci			}
846362306a36Sopenharmony_ci		}
846462306a36Sopenharmony_ci
846562306a36Sopenharmony_ci		hlist_del(&fltr->tc_flower_node);
846662306a36Sopenharmony_ci		kfree(fltr);
846762306a36Sopenharmony_ci	}
846862306a36Sopenharmony_ci}
846962306a36Sopenharmony_ci
847062306a36Sopenharmony_ci/**
847162306a36Sopenharmony_ci * ice_remove_q_channels - Remove queue channels for the TCs
847262306a36Sopenharmony_ci * @vsi: VSI to be configured
847362306a36Sopenharmony_ci * @rem_fltr: delete advanced switch filter or not
847462306a36Sopenharmony_ci *
847562306a36Sopenharmony_ci * Remove queue channels for the TCs
847662306a36Sopenharmony_ci */
847762306a36Sopenharmony_cistatic void ice_remove_q_channels(struct ice_vsi *vsi, bool rem_fltr)
847862306a36Sopenharmony_ci{
847962306a36Sopenharmony_ci	struct ice_channel *ch, *ch_tmp;
848062306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
848162306a36Sopenharmony_ci	int i;
848262306a36Sopenharmony_ci
848362306a36Sopenharmony_ci	/* remove all tc-flower based filter if they are channel filters only */
848462306a36Sopenharmony_ci	if (rem_fltr)
848562306a36Sopenharmony_ci		ice_rem_all_chnl_fltrs(pf);
848662306a36Sopenharmony_ci
848762306a36Sopenharmony_ci	/* remove ntuple filters since queue configuration is being changed */
848862306a36Sopenharmony_ci	if  (vsi->netdev->features & NETIF_F_NTUPLE) {
848962306a36Sopenharmony_ci		struct ice_hw *hw = &pf->hw;
849062306a36Sopenharmony_ci
849162306a36Sopenharmony_ci		mutex_lock(&hw->fdir_fltr_lock);
849262306a36Sopenharmony_ci		ice_fdir_del_all_fltrs(vsi);
849362306a36Sopenharmony_ci		mutex_unlock(&hw->fdir_fltr_lock);
849462306a36Sopenharmony_ci	}
849562306a36Sopenharmony_ci
849662306a36Sopenharmony_ci	/* perform cleanup for channels if they exist */
849762306a36Sopenharmony_ci	list_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list, list) {
849862306a36Sopenharmony_ci		struct ice_vsi *ch_vsi;
849962306a36Sopenharmony_ci
850062306a36Sopenharmony_ci		list_del(&ch->list);
850162306a36Sopenharmony_ci		ch_vsi = ch->ch_vsi;
850262306a36Sopenharmony_ci		if (!ch_vsi) {
850362306a36Sopenharmony_ci			kfree(ch);
850462306a36Sopenharmony_ci			continue;
850562306a36Sopenharmony_ci		}
850662306a36Sopenharmony_ci
850762306a36Sopenharmony_ci		/* Reset queue contexts */
850862306a36Sopenharmony_ci		for (i = 0; i < ch->num_rxq; i++) {
850962306a36Sopenharmony_ci			struct ice_tx_ring *tx_ring;
851062306a36Sopenharmony_ci			struct ice_rx_ring *rx_ring;
851162306a36Sopenharmony_ci
851262306a36Sopenharmony_ci			tx_ring = vsi->tx_rings[ch->base_q + i];
851362306a36Sopenharmony_ci			rx_ring = vsi->rx_rings[ch->base_q + i];
851462306a36Sopenharmony_ci			if (tx_ring) {
851562306a36Sopenharmony_ci				tx_ring->ch = NULL;
851662306a36Sopenharmony_ci				if (tx_ring->q_vector)
851762306a36Sopenharmony_ci					tx_ring->q_vector->ch = NULL;
851862306a36Sopenharmony_ci			}
851962306a36Sopenharmony_ci			if (rx_ring) {
852062306a36Sopenharmony_ci				rx_ring->ch = NULL;
852162306a36Sopenharmony_ci				if (rx_ring->q_vector)
852262306a36Sopenharmony_ci					rx_ring->q_vector->ch = NULL;
852362306a36Sopenharmony_ci			}
852462306a36Sopenharmony_ci		}
852562306a36Sopenharmony_ci
852662306a36Sopenharmony_ci		/* Release FD resources for the channel VSI */
852762306a36Sopenharmony_ci		ice_fdir_rem_adq_chnl(&pf->hw, ch->ch_vsi->idx);
852862306a36Sopenharmony_ci
852962306a36Sopenharmony_ci		/* clear the VSI from scheduler tree */
853062306a36Sopenharmony_ci		ice_rm_vsi_lan_cfg(ch->ch_vsi->port_info, ch->ch_vsi->idx);
853162306a36Sopenharmony_ci
853262306a36Sopenharmony_ci		/* Delete VSI from FW, PF and HW VSI arrays */
853362306a36Sopenharmony_ci		ice_vsi_delete(ch->ch_vsi);
853462306a36Sopenharmony_ci
853562306a36Sopenharmony_ci		/* free the channel */
853662306a36Sopenharmony_ci		kfree(ch);
853762306a36Sopenharmony_ci	}
853862306a36Sopenharmony_ci
853962306a36Sopenharmony_ci	/* clear the channel VSI map which is stored in main VSI */
854062306a36Sopenharmony_ci	ice_for_each_chnl_tc(i)
854162306a36Sopenharmony_ci		vsi->tc_map_vsi[i] = NULL;
854262306a36Sopenharmony_ci
854362306a36Sopenharmony_ci	/* reset main VSI's all TC information */
854462306a36Sopenharmony_ci	vsi->all_enatc = 0;
854562306a36Sopenharmony_ci	vsi->all_numtc = 0;
854662306a36Sopenharmony_ci}
854762306a36Sopenharmony_ci
854862306a36Sopenharmony_ci/**
854962306a36Sopenharmony_ci * ice_rebuild_channels - rebuild channel
855062306a36Sopenharmony_ci * @pf: ptr to PF
855162306a36Sopenharmony_ci *
855262306a36Sopenharmony_ci * Recreate channel VSIs and replay filters
855362306a36Sopenharmony_ci */
855462306a36Sopenharmony_cistatic int ice_rebuild_channels(struct ice_pf *pf)
855562306a36Sopenharmony_ci{
855662306a36Sopenharmony_ci	struct device *dev = ice_pf_to_dev(pf);
855762306a36Sopenharmony_ci	struct ice_vsi *main_vsi;
855862306a36Sopenharmony_ci	bool rem_adv_fltr = true;
855962306a36Sopenharmony_ci	struct ice_channel *ch;
856062306a36Sopenharmony_ci	struct ice_vsi *vsi;
856162306a36Sopenharmony_ci	int tc_idx = 1;
856262306a36Sopenharmony_ci	int i, err;
856362306a36Sopenharmony_ci
856462306a36Sopenharmony_ci	main_vsi = ice_get_main_vsi(pf);
856562306a36Sopenharmony_ci	if (!main_vsi)
856662306a36Sopenharmony_ci		return 0;
856762306a36Sopenharmony_ci
856862306a36Sopenharmony_ci	if (!test_bit(ICE_FLAG_TC_MQPRIO, pf->flags) ||
856962306a36Sopenharmony_ci	    main_vsi->old_numtc == 1)
857062306a36Sopenharmony_ci		return 0; /* nothing to be done */
857162306a36Sopenharmony_ci
857262306a36Sopenharmony_ci	/* reconfigure main VSI based on old value of TC and cached values
857362306a36Sopenharmony_ci	 * for MQPRIO opts
857462306a36Sopenharmony_ci	 */
857562306a36Sopenharmony_ci	err = ice_vsi_cfg_tc(main_vsi, main_vsi->old_ena_tc);
857662306a36Sopenharmony_ci	if (err) {
857762306a36Sopenharmony_ci		dev_err(dev, "failed configuring TC(ena_tc:0x%02x) for HW VSI=%u\n",
857862306a36Sopenharmony_ci			main_vsi->old_ena_tc, main_vsi->vsi_num);
857962306a36Sopenharmony_ci		return err;
858062306a36Sopenharmony_ci	}
858162306a36Sopenharmony_ci
858262306a36Sopenharmony_ci	/* rebuild ADQ VSIs */
858362306a36Sopenharmony_ci	ice_for_each_vsi(pf, i) {
858462306a36Sopenharmony_ci		enum ice_vsi_type type;
858562306a36Sopenharmony_ci
858662306a36Sopenharmony_ci		vsi = pf->vsi[i];
858762306a36Sopenharmony_ci		if (!vsi || vsi->type != ICE_VSI_CHNL)
858862306a36Sopenharmony_ci			continue;
858962306a36Sopenharmony_ci
859062306a36Sopenharmony_ci		type = vsi->type;
859162306a36Sopenharmony_ci
859262306a36Sopenharmony_ci		/* rebuild ADQ VSI */
859362306a36Sopenharmony_ci		err = ice_vsi_rebuild(vsi, ICE_VSI_FLAG_INIT);
859462306a36Sopenharmony_ci		if (err) {
859562306a36Sopenharmony_ci			dev_err(dev, "VSI (type:%s) at index %d rebuild failed, err %d\n",
859662306a36Sopenharmony_ci				ice_vsi_type_str(type), vsi->idx, err);
859762306a36Sopenharmony_ci			goto cleanup;
859862306a36Sopenharmony_ci		}
859962306a36Sopenharmony_ci
860062306a36Sopenharmony_ci		/* Re-map HW VSI number, using VSI handle that has been
860162306a36Sopenharmony_ci		 * previously validated in ice_replay_vsi() call above
860262306a36Sopenharmony_ci		 */
860362306a36Sopenharmony_ci		vsi->vsi_num = ice_get_hw_vsi_num(&pf->hw, vsi->idx);
860462306a36Sopenharmony_ci
860562306a36Sopenharmony_ci		/* replay filters for the VSI */
860662306a36Sopenharmony_ci		err = ice_replay_vsi(&pf->hw, vsi->idx);
860762306a36Sopenharmony_ci		if (err) {
860862306a36Sopenharmony_ci			dev_err(dev, "VSI (type:%s) replay failed, err %d, VSI index %d\n",
860962306a36Sopenharmony_ci				ice_vsi_type_str(type), err, vsi->idx);
861062306a36Sopenharmony_ci			rem_adv_fltr = false;
861162306a36Sopenharmony_ci			goto cleanup;
861262306a36Sopenharmony_ci		}
861362306a36Sopenharmony_ci		dev_info(dev, "VSI (type:%s) at index %d rebuilt successfully\n",
861462306a36Sopenharmony_ci			 ice_vsi_type_str(type), vsi->idx);
861562306a36Sopenharmony_ci
861662306a36Sopenharmony_ci		/* store ADQ VSI at correct TC index in main VSI's
861762306a36Sopenharmony_ci		 * map of TC to VSI
861862306a36Sopenharmony_ci		 */
861962306a36Sopenharmony_ci		main_vsi->tc_map_vsi[tc_idx++] = vsi;
862062306a36Sopenharmony_ci	}
862162306a36Sopenharmony_ci
862262306a36Sopenharmony_ci	/* ADQ VSI(s) has been rebuilt successfully, so setup
862362306a36Sopenharmony_ci	 * channel for main VSI's Tx and Rx rings
862462306a36Sopenharmony_ci	 */
862562306a36Sopenharmony_ci	list_for_each_entry(ch, &main_vsi->ch_list, list) {
862662306a36Sopenharmony_ci		struct ice_vsi *ch_vsi;
862762306a36Sopenharmony_ci
862862306a36Sopenharmony_ci		ch_vsi = ch->ch_vsi;
862962306a36Sopenharmony_ci		if (!ch_vsi)
863062306a36Sopenharmony_ci			continue;
863162306a36Sopenharmony_ci
863262306a36Sopenharmony_ci		/* reconfig channel resources */
863362306a36Sopenharmony_ci		ice_cfg_chnl_all_res(main_vsi, ch);
863462306a36Sopenharmony_ci
863562306a36Sopenharmony_ci		/* replay BW rate limit if it is non-zero */
863662306a36Sopenharmony_ci		if (!ch->max_tx_rate && !ch->min_tx_rate)
863762306a36Sopenharmony_ci			continue;
863862306a36Sopenharmony_ci
863962306a36Sopenharmony_ci		err = ice_set_bw_limit(ch_vsi, ch->max_tx_rate,
864062306a36Sopenharmony_ci				       ch->min_tx_rate);
864162306a36Sopenharmony_ci		if (err)
864262306a36Sopenharmony_ci			dev_err(dev, "failed (err:%d) to rebuild BW rate limit, max_tx_rate: %llu Kbps, min_tx_rate: %llu Kbps for VSI(%u)\n",
864362306a36Sopenharmony_ci				err, ch->max_tx_rate, ch->min_tx_rate,
864462306a36Sopenharmony_ci				ch_vsi->vsi_num);
864562306a36Sopenharmony_ci		else
864662306a36Sopenharmony_ci			dev_dbg(dev, "successfully rebuild BW rate limit, max_tx_rate: %llu Kbps, min_tx_rate: %llu Kbps for VSI(%u)\n",
864762306a36Sopenharmony_ci				ch->max_tx_rate, ch->min_tx_rate,
864862306a36Sopenharmony_ci				ch_vsi->vsi_num);
864962306a36Sopenharmony_ci	}
865062306a36Sopenharmony_ci
865162306a36Sopenharmony_ci	/* reconfig RSS for main VSI */
865262306a36Sopenharmony_ci	if (main_vsi->ch_rss_size)
865362306a36Sopenharmony_ci		ice_vsi_cfg_rss_lut_key(main_vsi);
865462306a36Sopenharmony_ci
865562306a36Sopenharmony_ci	return 0;
865662306a36Sopenharmony_ci
865762306a36Sopenharmony_cicleanup:
865862306a36Sopenharmony_ci	ice_remove_q_channels(main_vsi, rem_adv_fltr);
865962306a36Sopenharmony_ci	return err;
866062306a36Sopenharmony_ci}
866162306a36Sopenharmony_ci
866262306a36Sopenharmony_ci/**
866362306a36Sopenharmony_ci * ice_create_q_channels - Add queue channel for the given TCs
866462306a36Sopenharmony_ci * @vsi: VSI to be configured
866562306a36Sopenharmony_ci *
866662306a36Sopenharmony_ci * Configures queue channel mapping to the given TCs
866762306a36Sopenharmony_ci */
866862306a36Sopenharmony_cistatic int ice_create_q_channels(struct ice_vsi *vsi)
866962306a36Sopenharmony_ci{
867062306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
867162306a36Sopenharmony_ci	struct ice_channel *ch;
867262306a36Sopenharmony_ci	int ret = 0, i;
867362306a36Sopenharmony_ci
867462306a36Sopenharmony_ci	ice_for_each_chnl_tc(i) {
867562306a36Sopenharmony_ci		if (!(vsi->all_enatc & BIT(i)))
867662306a36Sopenharmony_ci			continue;
867762306a36Sopenharmony_ci
867862306a36Sopenharmony_ci		ch = kzalloc(sizeof(*ch), GFP_KERNEL);
867962306a36Sopenharmony_ci		if (!ch) {
868062306a36Sopenharmony_ci			ret = -ENOMEM;
868162306a36Sopenharmony_ci			goto err_free;
868262306a36Sopenharmony_ci		}
868362306a36Sopenharmony_ci		INIT_LIST_HEAD(&ch->list);
868462306a36Sopenharmony_ci		ch->num_rxq = vsi->mqprio_qopt.qopt.count[i];
868562306a36Sopenharmony_ci		ch->num_txq = vsi->mqprio_qopt.qopt.count[i];
868662306a36Sopenharmony_ci		ch->base_q = vsi->mqprio_qopt.qopt.offset[i];
868762306a36Sopenharmony_ci		ch->max_tx_rate = vsi->mqprio_qopt.max_rate[i];
868862306a36Sopenharmony_ci		ch->min_tx_rate = vsi->mqprio_qopt.min_rate[i];
868962306a36Sopenharmony_ci
869062306a36Sopenharmony_ci		/* convert to Kbits/s */
869162306a36Sopenharmony_ci		if (ch->max_tx_rate)
869262306a36Sopenharmony_ci			ch->max_tx_rate = div_u64(ch->max_tx_rate,
869362306a36Sopenharmony_ci						  ICE_BW_KBPS_DIVISOR);
869462306a36Sopenharmony_ci		if (ch->min_tx_rate)
869562306a36Sopenharmony_ci			ch->min_tx_rate = div_u64(ch->min_tx_rate,
869662306a36Sopenharmony_ci						  ICE_BW_KBPS_DIVISOR);
869762306a36Sopenharmony_ci
869862306a36Sopenharmony_ci		ret = ice_create_q_channel(vsi, ch);
869962306a36Sopenharmony_ci		if (ret) {
870062306a36Sopenharmony_ci			dev_err(ice_pf_to_dev(pf),
870162306a36Sopenharmony_ci				"failed creating channel TC:%d\n", i);
870262306a36Sopenharmony_ci			kfree(ch);
870362306a36Sopenharmony_ci			goto err_free;
870462306a36Sopenharmony_ci		}
870562306a36Sopenharmony_ci		list_add_tail(&ch->list, &vsi->ch_list);
870662306a36Sopenharmony_ci		vsi->tc_map_vsi[i] = ch->ch_vsi;
870762306a36Sopenharmony_ci		dev_dbg(ice_pf_to_dev(pf),
870862306a36Sopenharmony_ci			"successfully created channel: VSI %pK\n", ch->ch_vsi);
870962306a36Sopenharmony_ci	}
871062306a36Sopenharmony_ci	return 0;
871162306a36Sopenharmony_ci
871262306a36Sopenharmony_cierr_free:
871362306a36Sopenharmony_ci	ice_remove_q_channels(vsi, false);
871462306a36Sopenharmony_ci
871562306a36Sopenharmony_ci	return ret;
871662306a36Sopenharmony_ci}
871762306a36Sopenharmony_ci
871862306a36Sopenharmony_ci/**
871962306a36Sopenharmony_ci * ice_setup_tc_mqprio_qdisc - configure multiple traffic classes
872062306a36Sopenharmony_ci * @netdev: net device to configure
872162306a36Sopenharmony_ci * @type_data: TC offload data
872262306a36Sopenharmony_ci */
872362306a36Sopenharmony_cistatic int ice_setup_tc_mqprio_qdisc(struct net_device *netdev, void *type_data)
872462306a36Sopenharmony_ci{
872562306a36Sopenharmony_ci	struct tc_mqprio_qopt_offload *mqprio_qopt = type_data;
872662306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
872762306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
872862306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
872962306a36Sopenharmony_ci	u16 mode, ena_tc_qdisc = 0;
873062306a36Sopenharmony_ci	int cur_txq, cur_rxq;
873162306a36Sopenharmony_ci	u8 hw = 0, num_tcf;
873262306a36Sopenharmony_ci	struct device *dev;
873362306a36Sopenharmony_ci	int ret, i;
873462306a36Sopenharmony_ci
873562306a36Sopenharmony_ci	dev = ice_pf_to_dev(pf);
873662306a36Sopenharmony_ci	num_tcf = mqprio_qopt->qopt.num_tc;
873762306a36Sopenharmony_ci	hw = mqprio_qopt->qopt.hw;
873862306a36Sopenharmony_ci	mode = mqprio_qopt->mode;
873962306a36Sopenharmony_ci	if (!hw) {
874062306a36Sopenharmony_ci		clear_bit(ICE_FLAG_TC_MQPRIO, pf->flags);
874162306a36Sopenharmony_ci		vsi->ch_rss_size = 0;
874262306a36Sopenharmony_ci		memcpy(&vsi->mqprio_qopt, mqprio_qopt, sizeof(*mqprio_qopt));
874362306a36Sopenharmony_ci		goto config_tcf;
874462306a36Sopenharmony_ci	}
874562306a36Sopenharmony_ci
874662306a36Sopenharmony_ci	/* Generate queue region map for number of TCF requested */
874762306a36Sopenharmony_ci	for (i = 0; i < num_tcf; i++)
874862306a36Sopenharmony_ci		ena_tc_qdisc |= BIT(i);
874962306a36Sopenharmony_ci
875062306a36Sopenharmony_ci	switch (mode) {
875162306a36Sopenharmony_ci	case TC_MQPRIO_MODE_CHANNEL:
875262306a36Sopenharmony_ci
875362306a36Sopenharmony_ci		if (pf->hw.port_info->is_custom_tx_enabled) {
875462306a36Sopenharmony_ci			dev_err(dev, "Custom Tx scheduler feature enabled, can't configure ADQ\n");
875562306a36Sopenharmony_ci			return -EBUSY;
875662306a36Sopenharmony_ci		}
875762306a36Sopenharmony_ci		ice_tear_down_devlink_rate_tree(pf);
875862306a36Sopenharmony_ci
875962306a36Sopenharmony_ci		ret = ice_validate_mqprio_qopt(vsi, mqprio_qopt);
876062306a36Sopenharmony_ci		if (ret) {
876162306a36Sopenharmony_ci			netdev_err(netdev, "failed to validate_mqprio_qopt(), ret %d\n",
876262306a36Sopenharmony_ci				   ret);
876362306a36Sopenharmony_ci			return ret;
876462306a36Sopenharmony_ci		}
876562306a36Sopenharmony_ci		memcpy(&vsi->mqprio_qopt, mqprio_qopt, sizeof(*mqprio_qopt));
876662306a36Sopenharmony_ci		set_bit(ICE_FLAG_TC_MQPRIO, pf->flags);
876762306a36Sopenharmony_ci		/* don't assume state of hw_tc_offload during driver load
876862306a36Sopenharmony_ci		 * and set the flag for TC flower filter if hw_tc_offload
876962306a36Sopenharmony_ci		 * already ON
877062306a36Sopenharmony_ci		 */
877162306a36Sopenharmony_ci		if (vsi->netdev->features & NETIF_F_HW_TC)
877262306a36Sopenharmony_ci			set_bit(ICE_FLAG_CLS_FLOWER, pf->flags);
877362306a36Sopenharmony_ci		break;
877462306a36Sopenharmony_ci	default:
877562306a36Sopenharmony_ci		return -EINVAL;
877662306a36Sopenharmony_ci	}
877762306a36Sopenharmony_ci
877862306a36Sopenharmony_ciconfig_tcf:
877962306a36Sopenharmony_ci
878062306a36Sopenharmony_ci	/* Requesting same TCF configuration as already enabled */
878162306a36Sopenharmony_ci	if (ena_tc_qdisc == vsi->tc_cfg.ena_tc &&
878262306a36Sopenharmony_ci	    mode != TC_MQPRIO_MODE_CHANNEL)
878362306a36Sopenharmony_ci		return 0;
878462306a36Sopenharmony_ci
878562306a36Sopenharmony_ci	/* Pause VSI queues */
878662306a36Sopenharmony_ci	ice_dis_vsi(vsi, true);
878762306a36Sopenharmony_ci
878862306a36Sopenharmony_ci	if (!hw && !test_bit(ICE_FLAG_TC_MQPRIO, pf->flags))
878962306a36Sopenharmony_ci		ice_remove_q_channels(vsi, true);
879062306a36Sopenharmony_ci
879162306a36Sopenharmony_ci	if (!hw && !test_bit(ICE_FLAG_TC_MQPRIO, pf->flags)) {
879262306a36Sopenharmony_ci		vsi->req_txq = min_t(int, ice_get_avail_txq_count(pf),
879362306a36Sopenharmony_ci				     num_online_cpus());
879462306a36Sopenharmony_ci		vsi->req_rxq = min_t(int, ice_get_avail_rxq_count(pf),
879562306a36Sopenharmony_ci				     num_online_cpus());
879662306a36Sopenharmony_ci	} else {
879762306a36Sopenharmony_ci		/* logic to rebuild VSI, same like ethtool -L */
879862306a36Sopenharmony_ci		u16 offset = 0, qcount_tx = 0, qcount_rx = 0;
879962306a36Sopenharmony_ci
880062306a36Sopenharmony_ci		for (i = 0; i < num_tcf; i++) {
880162306a36Sopenharmony_ci			if (!(ena_tc_qdisc & BIT(i)))
880262306a36Sopenharmony_ci				continue;
880362306a36Sopenharmony_ci
880462306a36Sopenharmony_ci			offset = vsi->mqprio_qopt.qopt.offset[i];
880562306a36Sopenharmony_ci			qcount_rx = vsi->mqprio_qopt.qopt.count[i];
880662306a36Sopenharmony_ci			qcount_tx = vsi->mqprio_qopt.qopt.count[i];
880762306a36Sopenharmony_ci		}
880862306a36Sopenharmony_ci		vsi->req_txq = offset + qcount_tx;
880962306a36Sopenharmony_ci		vsi->req_rxq = offset + qcount_rx;
881062306a36Sopenharmony_ci
881162306a36Sopenharmony_ci		/* store away original rss_size info, so that it gets reused
881262306a36Sopenharmony_ci		 * form ice_vsi_rebuild during tc-qdisc delete stage - to
881362306a36Sopenharmony_ci		 * determine, what should be the rss_sizefor main VSI
881462306a36Sopenharmony_ci		 */
881562306a36Sopenharmony_ci		vsi->orig_rss_size = vsi->rss_size;
881662306a36Sopenharmony_ci	}
881762306a36Sopenharmony_ci
881862306a36Sopenharmony_ci	/* save current values of Tx and Rx queues before calling VSI rebuild
881962306a36Sopenharmony_ci	 * for fallback option
882062306a36Sopenharmony_ci	 */
882162306a36Sopenharmony_ci	cur_txq = vsi->num_txq;
882262306a36Sopenharmony_ci	cur_rxq = vsi->num_rxq;
882362306a36Sopenharmony_ci
882462306a36Sopenharmony_ci	/* proceed with rebuild main VSI using correct number of queues */
882562306a36Sopenharmony_ci	ret = ice_vsi_rebuild(vsi, ICE_VSI_FLAG_NO_INIT);
882662306a36Sopenharmony_ci	if (ret) {
882762306a36Sopenharmony_ci		/* fallback to current number of queues */
882862306a36Sopenharmony_ci		dev_info(dev, "Rebuild failed with new queues, try with current number of queues\n");
882962306a36Sopenharmony_ci		vsi->req_txq = cur_txq;
883062306a36Sopenharmony_ci		vsi->req_rxq = cur_rxq;
883162306a36Sopenharmony_ci		clear_bit(ICE_RESET_FAILED, pf->state);
883262306a36Sopenharmony_ci		if (ice_vsi_rebuild(vsi, ICE_VSI_FLAG_NO_INIT)) {
883362306a36Sopenharmony_ci			dev_err(dev, "Rebuild of main VSI failed again\n");
883462306a36Sopenharmony_ci			return ret;
883562306a36Sopenharmony_ci		}
883662306a36Sopenharmony_ci	}
883762306a36Sopenharmony_ci
883862306a36Sopenharmony_ci	vsi->all_numtc = num_tcf;
883962306a36Sopenharmony_ci	vsi->all_enatc = ena_tc_qdisc;
884062306a36Sopenharmony_ci	ret = ice_vsi_cfg_tc(vsi, ena_tc_qdisc);
884162306a36Sopenharmony_ci	if (ret) {
884262306a36Sopenharmony_ci		netdev_err(netdev, "failed configuring TC for VSI id=%d\n",
884362306a36Sopenharmony_ci			   vsi->vsi_num);
884462306a36Sopenharmony_ci		goto exit;
884562306a36Sopenharmony_ci	}
884662306a36Sopenharmony_ci
884762306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_TC_MQPRIO, pf->flags)) {
884862306a36Sopenharmony_ci		u64 max_tx_rate = vsi->mqprio_qopt.max_rate[0];
884962306a36Sopenharmony_ci		u64 min_tx_rate = vsi->mqprio_qopt.min_rate[0];
885062306a36Sopenharmony_ci
885162306a36Sopenharmony_ci		/* set TC0 rate limit if specified */
885262306a36Sopenharmony_ci		if (max_tx_rate || min_tx_rate) {
885362306a36Sopenharmony_ci			/* convert to Kbits/s */
885462306a36Sopenharmony_ci			if (max_tx_rate)
885562306a36Sopenharmony_ci				max_tx_rate = div_u64(max_tx_rate, ICE_BW_KBPS_DIVISOR);
885662306a36Sopenharmony_ci			if (min_tx_rate)
885762306a36Sopenharmony_ci				min_tx_rate = div_u64(min_tx_rate, ICE_BW_KBPS_DIVISOR);
885862306a36Sopenharmony_ci
885962306a36Sopenharmony_ci			ret = ice_set_bw_limit(vsi, max_tx_rate, min_tx_rate);
886062306a36Sopenharmony_ci			if (!ret) {
886162306a36Sopenharmony_ci				dev_dbg(dev, "set Tx rate max %llu min %llu for VSI(%u)\n",
886262306a36Sopenharmony_ci					max_tx_rate, min_tx_rate, vsi->vsi_num);
886362306a36Sopenharmony_ci			} else {
886462306a36Sopenharmony_ci				dev_err(dev, "failed to set Tx rate max %llu min %llu for VSI(%u)\n",
886562306a36Sopenharmony_ci					max_tx_rate, min_tx_rate, vsi->vsi_num);
886662306a36Sopenharmony_ci				goto exit;
886762306a36Sopenharmony_ci			}
886862306a36Sopenharmony_ci		}
886962306a36Sopenharmony_ci		ret = ice_create_q_channels(vsi);
887062306a36Sopenharmony_ci		if (ret) {
887162306a36Sopenharmony_ci			netdev_err(netdev, "failed configuring queue channels\n");
887262306a36Sopenharmony_ci			goto exit;
887362306a36Sopenharmony_ci		} else {
887462306a36Sopenharmony_ci			netdev_dbg(netdev, "successfully configured channels\n");
887562306a36Sopenharmony_ci		}
887662306a36Sopenharmony_ci	}
887762306a36Sopenharmony_ci
887862306a36Sopenharmony_ci	if (vsi->ch_rss_size)
887962306a36Sopenharmony_ci		ice_vsi_cfg_rss_lut_key(vsi);
888062306a36Sopenharmony_ci
888162306a36Sopenharmony_ciexit:
888262306a36Sopenharmony_ci	/* if error, reset the all_numtc and all_enatc */
888362306a36Sopenharmony_ci	if (ret) {
888462306a36Sopenharmony_ci		vsi->all_numtc = 0;
888562306a36Sopenharmony_ci		vsi->all_enatc = 0;
888662306a36Sopenharmony_ci	}
888762306a36Sopenharmony_ci	/* resume VSI */
888862306a36Sopenharmony_ci	ice_ena_vsi(vsi, true);
888962306a36Sopenharmony_ci
889062306a36Sopenharmony_ci	return ret;
889162306a36Sopenharmony_ci}
889262306a36Sopenharmony_ci
889362306a36Sopenharmony_cistatic LIST_HEAD(ice_block_cb_list);
889462306a36Sopenharmony_ci
889562306a36Sopenharmony_cistatic int
889662306a36Sopenharmony_ciice_setup_tc(struct net_device *netdev, enum tc_setup_type type,
889762306a36Sopenharmony_ci	     void *type_data)
889862306a36Sopenharmony_ci{
889962306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
890062306a36Sopenharmony_ci	struct ice_pf *pf = np->vsi->back;
890162306a36Sopenharmony_ci	bool locked = false;
890262306a36Sopenharmony_ci	int err;
890362306a36Sopenharmony_ci
890462306a36Sopenharmony_ci	switch (type) {
890562306a36Sopenharmony_ci	case TC_SETUP_BLOCK:
890662306a36Sopenharmony_ci		return flow_block_cb_setup_simple(type_data,
890762306a36Sopenharmony_ci						  &ice_block_cb_list,
890862306a36Sopenharmony_ci						  ice_setup_tc_block_cb,
890962306a36Sopenharmony_ci						  np, np, true);
891062306a36Sopenharmony_ci	case TC_SETUP_QDISC_MQPRIO:
891162306a36Sopenharmony_ci		if (ice_is_eswitch_mode_switchdev(pf)) {
891262306a36Sopenharmony_ci			netdev_err(netdev, "TC MQPRIO offload not supported, switchdev is enabled\n");
891362306a36Sopenharmony_ci			return -EOPNOTSUPP;
891462306a36Sopenharmony_ci		}
891562306a36Sopenharmony_ci
891662306a36Sopenharmony_ci		if (pf->adev) {
891762306a36Sopenharmony_ci			mutex_lock(&pf->adev_mutex);
891862306a36Sopenharmony_ci			device_lock(&pf->adev->dev);
891962306a36Sopenharmony_ci			locked = true;
892062306a36Sopenharmony_ci			if (pf->adev->dev.driver) {
892162306a36Sopenharmony_ci				netdev_err(netdev, "Cannot change qdisc when RDMA is active\n");
892262306a36Sopenharmony_ci				err = -EBUSY;
892362306a36Sopenharmony_ci				goto adev_unlock;
892462306a36Sopenharmony_ci			}
892562306a36Sopenharmony_ci		}
892662306a36Sopenharmony_ci
892762306a36Sopenharmony_ci		/* setup traffic classifier for receive side */
892862306a36Sopenharmony_ci		mutex_lock(&pf->tc_mutex);
892962306a36Sopenharmony_ci		err = ice_setup_tc_mqprio_qdisc(netdev, type_data);
893062306a36Sopenharmony_ci		mutex_unlock(&pf->tc_mutex);
893162306a36Sopenharmony_ci
893262306a36Sopenharmony_ciadev_unlock:
893362306a36Sopenharmony_ci		if (locked) {
893462306a36Sopenharmony_ci			device_unlock(&pf->adev->dev);
893562306a36Sopenharmony_ci			mutex_unlock(&pf->adev_mutex);
893662306a36Sopenharmony_ci		}
893762306a36Sopenharmony_ci		return err;
893862306a36Sopenharmony_ci	default:
893962306a36Sopenharmony_ci		return -EOPNOTSUPP;
894062306a36Sopenharmony_ci	}
894162306a36Sopenharmony_ci	return -EOPNOTSUPP;
894262306a36Sopenharmony_ci}
894362306a36Sopenharmony_ci
894462306a36Sopenharmony_cistatic struct ice_indr_block_priv *
894562306a36Sopenharmony_ciice_indr_block_priv_lookup(struct ice_netdev_priv *np,
894662306a36Sopenharmony_ci			   struct net_device *netdev)
894762306a36Sopenharmony_ci{
894862306a36Sopenharmony_ci	struct ice_indr_block_priv *cb_priv;
894962306a36Sopenharmony_ci
895062306a36Sopenharmony_ci	list_for_each_entry(cb_priv, &np->tc_indr_block_priv_list, list) {
895162306a36Sopenharmony_ci		if (!cb_priv->netdev)
895262306a36Sopenharmony_ci			return NULL;
895362306a36Sopenharmony_ci		if (cb_priv->netdev == netdev)
895462306a36Sopenharmony_ci			return cb_priv;
895562306a36Sopenharmony_ci	}
895662306a36Sopenharmony_ci	return NULL;
895762306a36Sopenharmony_ci}
895862306a36Sopenharmony_ci
895962306a36Sopenharmony_cistatic int
896062306a36Sopenharmony_ciice_indr_setup_block_cb(enum tc_setup_type type, void *type_data,
896162306a36Sopenharmony_ci			void *indr_priv)
896262306a36Sopenharmony_ci{
896362306a36Sopenharmony_ci	struct ice_indr_block_priv *priv = indr_priv;
896462306a36Sopenharmony_ci	struct ice_netdev_priv *np = priv->np;
896562306a36Sopenharmony_ci
896662306a36Sopenharmony_ci	switch (type) {
896762306a36Sopenharmony_ci	case TC_SETUP_CLSFLOWER:
896862306a36Sopenharmony_ci		return ice_setup_tc_cls_flower(np, priv->netdev,
896962306a36Sopenharmony_ci					       (struct flow_cls_offload *)
897062306a36Sopenharmony_ci					       type_data);
897162306a36Sopenharmony_ci	default:
897262306a36Sopenharmony_ci		return -EOPNOTSUPP;
897362306a36Sopenharmony_ci	}
897462306a36Sopenharmony_ci}
897562306a36Sopenharmony_ci
897662306a36Sopenharmony_cistatic int
897762306a36Sopenharmony_ciice_indr_setup_tc_block(struct net_device *netdev, struct Qdisc *sch,
897862306a36Sopenharmony_ci			struct ice_netdev_priv *np,
897962306a36Sopenharmony_ci			struct flow_block_offload *f, void *data,
898062306a36Sopenharmony_ci			void (*cleanup)(struct flow_block_cb *block_cb))
898162306a36Sopenharmony_ci{
898262306a36Sopenharmony_ci	struct ice_indr_block_priv *indr_priv;
898362306a36Sopenharmony_ci	struct flow_block_cb *block_cb;
898462306a36Sopenharmony_ci
898562306a36Sopenharmony_ci	if (!ice_is_tunnel_supported(netdev) &&
898662306a36Sopenharmony_ci	    !(is_vlan_dev(netdev) &&
898762306a36Sopenharmony_ci	      vlan_dev_real_dev(netdev) == np->vsi->netdev))
898862306a36Sopenharmony_ci		return -EOPNOTSUPP;
898962306a36Sopenharmony_ci
899062306a36Sopenharmony_ci	if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
899162306a36Sopenharmony_ci		return -EOPNOTSUPP;
899262306a36Sopenharmony_ci
899362306a36Sopenharmony_ci	switch (f->command) {
899462306a36Sopenharmony_ci	case FLOW_BLOCK_BIND:
899562306a36Sopenharmony_ci		indr_priv = ice_indr_block_priv_lookup(np, netdev);
899662306a36Sopenharmony_ci		if (indr_priv)
899762306a36Sopenharmony_ci			return -EEXIST;
899862306a36Sopenharmony_ci
899962306a36Sopenharmony_ci		indr_priv = kzalloc(sizeof(*indr_priv), GFP_KERNEL);
900062306a36Sopenharmony_ci		if (!indr_priv)
900162306a36Sopenharmony_ci			return -ENOMEM;
900262306a36Sopenharmony_ci
900362306a36Sopenharmony_ci		indr_priv->netdev = netdev;
900462306a36Sopenharmony_ci		indr_priv->np = np;
900562306a36Sopenharmony_ci		list_add(&indr_priv->list, &np->tc_indr_block_priv_list);
900662306a36Sopenharmony_ci
900762306a36Sopenharmony_ci		block_cb =
900862306a36Sopenharmony_ci			flow_indr_block_cb_alloc(ice_indr_setup_block_cb,
900962306a36Sopenharmony_ci						 indr_priv, indr_priv,
901062306a36Sopenharmony_ci						 ice_rep_indr_tc_block_unbind,
901162306a36Sopenharmony_ci						 f, netdev, sch, data, np,
901262306a36Sopenharmony_ci						 cleanup);
901362306a36Sopenharmony_ci
901462306a36Sopenharmony_ci		if (IS_ERR(block_cb)) {
901562306a36Sopenharmony_ci			list_del(&indr_priv->list);
901662306a36Sopenharmony_ci			kfree(indr_priv);
901762306a36Sopenharmony_ci			return PTR_ERR(block_cb);
901862306a36Sopenharmony_ci		}
901962306a36Sopenharmony_ci		flow_block_cb_add(block_cb, f);
902062306a36Sopenharmony_ci		list_add_tail(&block_cb->driver_list, &ice_block_cb_list);
902162306a36Sopenharmony_ci		break;
902262306a36Sopenharmony_ci	case FLOW_BLOCK_UNBIND:
902362306a36Sopenharmony_ci		indr_priv = ice_indr_block_priv_lookup(np, netdev);
902462306a36Sopenharmony_ci		if (!indr_priv)
902562306a36Sopenharmony_ci			return -ENOENT;
902662306a36Sopenharmony_ci
902762306a36Sopenharmony_ci		block_cb = flow_block_cb_lookup(f->block,
902862306a36Sopenharmony_ci						ice_indr_setup_block_cb,
902962306a36Sopenharmony_ci						indr_priv);
903062306a36Sopenharmony_ci		if (!block_cb)
903162306a36Sopenharmony_ci			return -ENOENT;
903262306a36Sopenharmony_ci
903362306a36Sopenharmony_ci		flow_indr_block_cb_remove(block_cb, f);
903462306a36Sopenharmony_ci
903562306a36Sopenharmony_ci		list_del(&block_cb->driver_list);
903662306a36Sopenharmony_ci		break;
903762306a36Sopenharmony_ci	default:
903862306a36Sopenharmony_ci		return -EOPNOTSUPP;
903962306a36Sopenharmony_ci	}
904062306a36Sopenharmony_ci	return 0;
904162306a36Sopenharmony_ci}
904262306a36Sopenharmony_ci
904362306a36Sopenharmony_cistatic int
904462306a36Sopenharmony_ciice_indr_setup_tc_cb(struct net_device *netdev, struct Qdisc *sch,
904562306a36Sopenharmony_ci		     void *cb_priv, enum tc_setup_type type, void *type_data,
904662306a36Sopenharmony_ci		     void *data,
904762306a36Sopenharmony_ci		     void (*cleanup)(struct flow_block_cb *block_cb))
904862306a36Sopenharmony_ci{
904962306a36Sopenharmony_ci	switch (type) {
905062306a36Sopenharmony_ci	case TC_SETUP_BLOCK:
905162306a36Sopenharmony_ci		return ice_indr_setup_tc_block(netdev, sch, cb_priv, type_data,
905262306a36Sopenharmony_ci					       data, cleanup);
905362306a36Sopenharmony_ci
905462306a36Sopenharmony_ci	default:
905562306a36Sopenharmony_ci		return -EOPNOTSUPP;
905662306a36Sopenharmony_ci	}
905762306a36Sopenharmony_ci}
905862306a36Sopenharmony_ci
905962306a36Sopenharmony_ci/**
906062306a36Sopenharmony_ci * ice_open - Called when a network interface becomes active
906162306a36Sopenharmony_ci * @netdev: network interface device structure
906262306a36Sopenharmony_ci *
906362306a36Sopenharmony_ci * The open entry point is called when a network interface is made
906462306a36Sopenharmony_ci * active by the system (IFF_UP). At this point all resources needed
906562306a36Sopenharmony_ci * for transmit and receive operations are allocated, the interrupt
906662306a36Sopenharmony_ci * handler is registered with the OS, the netdev watchdog is enabled,
906762306a36Sopenharmony_ci * and the stack is notified that the interface is ready.
906862306a36Sopenharmony_ci *
906962306a36Sopenharmony_ci * Returns 0 on success, negative value on failure
907062306a36Sopenharmony_ci */
907162306a36Sopenharmony_ciint ice_open(struct net_device *netdev)
907262306a36Sopenharmony_ci{
907362306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
907462306a36Sopenharmony_ci	struct ice_pf *pf = np->vsi->back;
907562306a36Sopenharmony_ci
907662306a36Sopenharmony_ci	if (ice_is_reset_in_progress(pf->state)) {
907762306a36Sopenharmony_ci		netdev_err(netdev, "can't open net device while reset is in progress");
907862306a36Sopenharmony_ci		return -EBUSY;
907962306a36Sopenharmony_ci	}
908062306a36Sopenharmony_ci
908162306a36Sopenharmony_ci	return ice_open_internal(netdev);
908262306a36Sopenharmony_ci}
908362306a36Sopenharmony_ci
908462306a36Sopenharmony_ci/**
908562306a36Sopenharmony_ci * ice_open_internal - Called when a network interface becomes active
908662306a36Sopenharmony_ci * @netdev: network interface device structure
908762306a36Sopenharmony_ci *
908862306a36Sopenharmony_ci * Internal ice_open implementation. Should not be used directly except for ice_open and reset
908962306a36Sopenharmony_ci * handling routine
909062306a36Sopenharmony_ci *
909162306a36Sopenharmony_ci * Returns 0 on success, negative value on failure
909262306a36Sopenharmony_ci */
909362306a36Sopenharmony_ciint ice_open_internal(struct net_device *netdev)
909462306a36Sopenharmony_ci{
909562306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
909662306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
909762306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
909862306a36Sopenharmony_ci	struct ice_port_info *pi;
909962306a36Sopenharmony_ci	int err;
910062306a36Sopenharmony_ci
910162306a36Sopenharmony_ci	if (test_bit(ICE_NEEDS_RESTART, pf->state)) {
910262306a36Sopenharmony_ci		netdev_err(netdev, "driver needs to be unloaded and reloaded\n");
910362306a36Sopenharmony_ci		return -EIO;
910462306a36Sopenharmony_ci	}
910562306a36Sopenharmony_ci
910662306a36Sopenharmony_ci	netif_carrier_off(netdev);
910762306a36Sopenharmony_ci
910862306a36Sopenharmony_ci	pi = vsi->port_info;
910962306a36Sopenharmony_ci	err = ice_update_link_info(pi);
911062306a36Sopenharmony_ci	if (err) {
911162306a36Sopenharmony_ci		netdev_err(netdev, "Failed to get link info, error %d\n", err);
911262306a36Sopenharmony_ci		return err;
911362306a36Sopenharmony_ci	}
911462306a36Sopenharmony_ci
911562306a36Sopenharmony_ci	ice_check_link_cfg_err(pf, pi->phy.link_info.link_cfg_err);
911662306a36Sopenharmony_ci
911762306a36Sopenharmony_ci	/* Set PHY if there is media, otherwise, turn off PHY */
911862306a36Sopenharmony_ci	if (pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE) {
911962306a36Sopenharmony_ci		clear_bit(ICE_FLAG_NO_MEDIA, pf->flags);
912062306a36Sopenharmony_ci		if (!test_bit(ICE_PHY_INIT_COMPLETE, pf->state)) {
912162306a36Sopenharmony_ci			err = ice_init_phy_user_cfg(pi);
912262306a36Sopenharmony_ci			if (err) {
912362306a36Sopenharmony_ci				netdev_err(netdev, "Failed to initialize PHY settings, error %d\n",
912462306a36Sopenharmony_ci					   err);
912562306a36Sopenharmony_ci				return err;
912662306a36Sopenharmony_ci			}
912762306a36Sopenharmony_ci		}
912862306a36Sopenharmony_ci
912962306a36Sopenharmony_ci		err = ice_configure_phy(vsi);
913062306a36Sopenharmony_ci		if (err) {
913162306a36Sopenharmony_ci			netdev_err(netdev, "Failed to set physical link up, error %d\n",
913262306a36Sopenharmony_ci				   err);
913362306a36Sopenharmony_ci			return err;
913462306a36Sopenharmony_ci		}
913562306a36Sopenharmony_ci	} else {
913662306a36Sopenharmony_ci		set_bit(ICE_FLAG_NO_MEDIA, pf->flags);
913762306a36Sopenharmony_ci		ice_set_link(vsi, false);
913862306a36Sopenharmony_ci	}
913962306a36Sopenharmony_ci
914062306a36Sopenharmony_ci	err = ice_vsi_open(vsi);
914162306a36Sopenharmony_ci	if (err)
914262306a36Sopenharmony_ci		netdev_err(netdev, "Failed to open VSI 0x%04X on switch 0x%04X\n",
914362306a36Sopenharmony_ci			   vsi->vsi_num, vsi->vsw->sw_id);
914462306a36Sopenharmony_ci
914562306a36Sopenharmony_ci	/* Update existing tunnels information */
914662306a36Sopenharmony_ci	udp_tunnel_get_rx_info(netdev);
914762306a36Sopenharmony_ci
914862306a36Sopenharmony_ci	return err;
914962306a36Sopenharmony_ci}
915062306a36Sopenharmony_ci
915162306a36Sopenharmony_ci/**
915262306a36Sopenharmony_ci * ice_stop - Disables a network interface
915362306a36Sopenharmony_ci * @netdev: network interface device structure
915462306a36Sopenharmony_ci *
915562306a36Sopenharmony_ci * The stop entry point is called when an interface is de-activated by the OS,
915662306a36Sopenharmony_ci * and the netdevice enters the DOWN state. The hardware is still under the
915762306a36Sopenharmony_ci * driver's control, but the netdev interface is disabled.
915862306a36Sopenharmony_ci *
915962306a36Sopenharmony_ci * Returns success only - not allowed to fail
916062306a36Sopenharmony_ci */
916162306a36Sopenharmony_ciint ice_stop(struct net_device *netdev)
916262306a36Sopenharmony_ci{
916362306a36Sopenharmony_ci	struct ice_netdev_priv *np = netdev_priv(netdev);
916462306a36Sopenharmony_ci	struct ice_vsi *vsi = np->vsi;
916562306a36Sopenharmony_ci	struct ice_pf *pf = vsi->back;
916662306a36Sopenharmony_ci
916762306a36Sopenharmony_ci	if (ice_is_reset_in_progress(pf->state)) {
916862306a36Sopenharmony_ci		netdev_err(netdev, "can't stop net device while reset is in progress");
916962306a36Sopenharmony_ci		return -EBUSY;
917062306a36Sopenharmony_ci	}
917162306a36Sopenharmony_ci
917262306a36Sopenharmony_ci	if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags)) {
917362306a36Sopenharmony_ci		int link_err = ice_force_phys_link_state(vsi, false);
917462306a36Sopenharmony_ci
917562306a36Sopenharmony_ci		if (link_err) {
917662306a36Sopenharmony_ci			if (link_err == -ENOMEDIUM)
917762306a36Sopenharmony_ci				netdev_info(vsi->netdev, "Skipping link reconfig - no media attached, VSI %d\n",
917862306a36Sopenharmony_ci					    vsi->vsi_num);
917962306a36Sopenharmony_ci			else
918062306a36Sopenharmony_ci				netdev_err(vsi->netdev, "Failed to set physical link down, VSI %d error %d\n",
918162306a36Sopenharmony_ci					   vsi->vsi_num, link_err);
918262306a36Sopenharmony_ci
918362306a36Sopenharmony_ci			ice_vsi_close(vsi);
918462306a36Sopenharmony_ci			return -EIO;
918562306a36Sopenharmony_ci		}
918662306a36Sopenharmony_ci	}
918762306a36Sopenharmony_ci
918862306a36Sopenharmony_ci	ice_vsi_close(vsi);
918962306a36Sopenharmony_ci
919062306a36Sopenharmony_ci	return 0;
919162306a36Sopenharmony_ci}
919262306a36Sopenharmony_ci
919362306a36Sopenharmony_ci/**
919462306a36Sopenharmony_ci * ice_features_check - Validate encapsulated packet conforms to limits
919562306a36Sopenharmony_ci * @skb: skb buffer
919662306a36Sopenharmony_ci * @netdev: This port's netdev
919762306a36Sopenharmony_ci * @features: Offload features that the stack believes apply
919862306a36Sopenharmony_ci */
919962306a36Sopenharmony_cistatic netdev_features_t
920062306a36Sopenharmony_ciice_features_check(struct sk_buff *skb,
920162306a36Sopenharmony_ci		   struct net_device __always_unused *netdev,
920262306a36Sopenharmony_ci		   netdev_features_t features)
920362306a36Sopenharmony_ci{
920462306a36Sopenharmony_ci	bool gso = skb_is_gso(skb);
920562306a36Sopenharmony_ci	size_t len;
920662306a36Sopenharmony_ci
920762306a36Sopenharmony_ci	/* No point in doing any of this if neither checksum nor GSO are
920862306a36Sopenharmony_ci	 * being requested for this frame. We can rule out both by just
920962306a36Sopenharmony_ci	 * checking for CHECKSUM_PARTIAL
921062306a36Sopenharmony_ci	 */
921162306a36Sopenharmony_ci	if (skb->ip_summed != CHECKSUM_PARTIAL)
921262306a36Sopenharmony_ci		return features;
921362306a36Sopenharmony_ci
921462306a36Sopenharmony_ci	/* We cannot support GSO if the MSS is going to be less than
921562306a36Sopenharmony_ci	 * 64 bytes. If it is then we need to drop support for GSO.
921662306a36Sopenharmony_ci	 */
921762306a36Sopenharmony_ci	if (gso && (skb_shinfo(skb)->gso_size < ICE_TXD_CTX_MIN_MSS))
921862306a36Sopenharmony_ci		features &= ~NETIF_F_GSO_MASK;
921962306a36Sopenharmony_ci
922062306a36Sopenharmony_ci	len = skb_network_offset(skb);
922162306a36Sopenharmony_ci	if (len > ICE_TXD_MACLEN_MAX || len & 0x1)
922262306a36Sopenharmony_ci		goto out_rm_features;
922362306a36Sopenharmony_ci
922462306a36Sopenharmony_ci	len = skb_network_header_len(skb);
922562306a36Sopenharmony_ci	if (len > ICE_TXD_IPLEN_MAX || len & 0x1)
922662306a36Sopenharmony_ci		goto out_rm_features;
922762306a36Sopenharmony_ci
922862306a36Sopenharmony_ci	if (skb->encapsulation) {
922962306a36Sopenharmony_ci		/* this must work for VXLAN frames AND IPIP/SIT frames, and in
923062306a36Sopenharmony_ci		 * the case of IPIP frames, the transport header pointer is
923162306a36Sopenharmony_ci		 * after the inner header! So check to make sure that this
923262306a36Sopenharmony_ci		 * is a GRE or UDP_TUNNEL frame before doing that math.
923362306a36Sopenharmony_ci		 */
923462306a36Sopenharmony_ci		if (gso && (skb_shinfo(skb)->gso_type &
923562306a36Sopenharmony_ci			    (SKB_GSO_GRE | SKB_GSO_UDP_TUNNEL))) {
923662306a36Sopenharmony_ci			len = skb_inner_network_header(skb) -
923762306a36Sopenharmony_ci			      skb_transport_header(skb);
923862306a36Sopenharmony_ci			if (len > ICE_TXD_L4LEN_MAX || len & 0x1)
923962306a36Sopenharmony_ci				goto out_rm_features;
924062306a36Sopenharmony_ci		}
924162306a36Sopenharmony_ci
924262306a36Sopenharmony_ci		len = skb_inner_network_header_len(skb);
924362306a36Sopenharmony_ci		if (len > ICE_TXD_IPLEN_MAX || len & 0x1)
924462306a36Sopenharmony_ci			goto out_rm_features;
924562306a36Sopenharmony_ci	}
924662306a36Sopenharmony_ci
924762306a36Sopenharmony_ci	return features;
924862306a36Sopenharmony_ciout_rm_features:
924962306a36Sopenharmony_ci	return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
925062306a36Sopenharmony_ci}
925162306a36Sopenharmony_ci
925262306a36Sopenharmony_cistatic const struct net_device_ops ice_netdev_safe_mode_ops = {
925362306a36Sopenharmony_ci	.ndo_open = ice_open,
925462306a36Sopenharmony_ci	.ndo_stop = ice_stop,
925562306a36Sopenharmony_ci	.ndo_start_xmit = ice_start_xmit,
925662306a36Sopenharmony_ci	.ndo_set_mac_address = ice_set_mac_address,
925762306a36Sopenharmony_ci	.ndo_validate_addr = eth_validate_addr,
925862306a36Sopenharmony_ci	.ndo_change_mtu = ice_change_mtu,
925962306a36Sopenharmony_ci	.ndo_get_stats64 = ice_get_stats64,
926062306a36Sopenharmony_ci	.ndo_tx_timeout = ice_tx_timeout,
926162306a36Sopenharmony_ci	.ndo_bpf = ice_xdp_safe_mode,
926262306a36Sopenharmony_ci};
926362306a36Sopenharmony_ci
926462306a36Sopenharmony_cistatic const struct net_device_ops ice_netdev_ops = {
926562306a36Sopenharmony_ci	.ndo_open = ice_open,
926662306a36Sopenharmony_ci	.ndo_stop = ice_stop,
926762306a36Sopenharmony_ci	.ndo_start_xmit = ice_start_xmit,
926862306a36Sopenharmony_ci	.ndo_select_queue = ice_select_queue,
926962306a36Sopenharmony_ci	.ndo_features_check = ice_features_check,
927062306a36Sopenharmony_ci	.ndo_fix_features = ice_fix_features,
927162306a36Sopenharmony_ci	.ndo_set_rx_mode = ice_set_rx_mode,
927262306a36Sopenharmony_ci	.ndo_set_mac_address = ice_set_mac_address,
927362306a36Sopenharmony_ci	.ndo_validate_addr = eth_validate_addr,
927462306a36Sopenharmony_ci	.ndo_change_mtu = ice_change_mtu,
927562306a36Sopenharmony_ci	.ndo_get_stats64 = ice_get_stats64,
927662306a36Sopenharmony_ci	.ndo_set_tx_maxrate = ice_set_tx_maxrate,
927762306a36Sopenharmony_ci	.ndo_eth_ioctl = ice_eth_ioctl,
927862306a36Sopenharmony_ci	.ndo_set_vf_spoofchk = ice_set_vf_spoofchk,
927962306a36Sopenharmony_ci	.ndo_set_vf_mac = ice_set_vf_mac,
928062306a36Sopenharmony_ci	.ndo_get_vf_config = ice_get_vf_cfg,
928162306a36Sopenharmony_ci	.ndo_set_vf_trust = ice_set_vf_trust,
928262306a36Sopenharmony_ci	.ndo_set_vf_vlan = ice_set_vf_port_vlan,
928362306a36Sopenharmony_ci	.ndo_set_vf_link_state = ice_set_vf_link_state,
928462306a36Sopenharmony_ci	.ndo_get_vf_stats = ice_get_vf_stats,
928562306a36Sopenharmony_ci	.ndo_set_vf_rate = ice_set_vf_bw,
928662306a36Sopenharmony_ci	.ndo_vlan_rx_add_vid = ice_vlan_rx_add_vid,
928762306a36Sopenharmony_ci	.ndo_vlan_rx_kill_vid = ice_vlan_rx_kill_vid,
928862306a36Sopenharmony_ci	.ndo_setup_tc = ice_setup_tc,
928962306a36Sopenharmony_ci	.ndo_set_features = ice_set_features,
929062306a36Sopenharmony_ci	.ndo_bridge_getlink = ice_bridge_getlink,
929162306a36Sopenharmony_ci	.ndo_bridge_setlink = ice_bridge_setlink,
929262306a36Sopenharmony_ci	.ndo_fdb_add = ice_fdb_add,
929362306a36Sopenharmony_ci	.ndo_fdb_del = ice_fdb_del,
929462306a36Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL
929562306a36Sopenharmony_ci	.ndo_rx_flow_steer = ice_rx_flow_steer,
929662306a36Sopenharmony_ci#endif
929762306a36Sopenharmony_ci	.ndo_tx_timeout = ice_tx_timeout,
929862306a36Sopenharmony_ci	.ndo_bpf = ice_xdp,
929962306a36Sopenharmony_ci	.ndo_xdp_xmit = ice_xdp_xmit,
930062306a36Sopenharmony_ci	.ndo_xsk_wakeup = ice_xsk_wakeup,
930162306a36Sopenharmony_ci};
9302