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, ¶ms); 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, ¶ms); 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, ¶ms); 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, ¶ms); 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, ¶ms); 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, ¶ms); 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, ¶ms); 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