18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2018, Intel Corporation. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci/* Intel(R) Ethernet Connection E800 Series Linux Driver */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <generated/utsrelease.h> 98c2ecf20Sopenharmony_ci#include <linux/crash_dump.h> 108c2ecf20Sopenharmony_ci#include "ice.h" 118c2ecf20Sopenharmony_ci#include "ice_base.h" 128c2ecf20Sopenharmony_ci#include "ice_lib.h" 138c2ecf20Sopenharmony_ci#include "ice_fltr.h" 148c2ecf20Sopenharmony_ci#include "ice_dcb_lib.h" 158c2ecf20Sopenharmony_ci#include "ice_dcb_nl.h" 168c2ecf20Sopenharmony_ci#include "ice_devlink.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define DRV_SUMMARY "Intel(R) Ethernet Connection E800 Series Linux Driver" 198c2ecf20Sopenharmony_cistatic const char ice_driver_string[] = DRV_SUMMARY; 208c2ecf20Sopenharmony_cistatic const char ice_copyright[] = "Copyright (c) 2018, Intel Corporation."; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* DDP Package file located in firmware search paths (e.g. /lib/firmware/) */ 238c2ecf20Sopenharmony_ci#define ICE_DDP_PKG_PATH "intel/ice/ddp/" 248c2ecf20Sopenharmony_ci#define ICE_DDP_PKG_FILE ICE_DDP_PKG_PATH "ice.pkg" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ciMODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>"); 278c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRV_SUMMARY); 288c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 298c2ecf20Sopenharmony_ciMODULE_FIRMWARE(ICE_DDP_PKG_FILE); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int debug = -1; 328c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 338c2ecf20Sopenharmony_ci#ifndef CONFIG_DYNAMIC_DEBUG 348c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "netif level (0=none,...,16=all), hw debug_mask (0x8XXXXXXX)"); 358c2ecf20Sopenharmony_ci#else 368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "netif level (0=none,...,16=all)"); 378c2ecf20Sopenharmony_ci#endif /* !CONFIG_DYNAMIC_DEBUG */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic struct workqueue_struct *ice_wq; 408c2ecf20Sopenharmony_cistatic const struct net_device_ops ice_netdev_safe_mode_ops; 418c2ecf20Sopenharmony_cistatic const struct net_device_ops ice_netdev_ops; 428c2ecf20Sopenharmony_cistatic int ice_vsi_open(struct ice_vsi *vsi); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic void ice_vsi_release_all(struct ice_pf *pf); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/** 498c2ecf20Sopenharmony_ci * ice_get_tx_pending - returns number of Tx descriptors not processed 508c2ecf20Sopenharmony_ci * @ring: the ring of descriptors 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_cistatic u16 ice_get_tx_pending(struct ice_ring *ring) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci u16 head, tail; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci head = ring->next_to_clean; 578c2ecf20Sopenharmony_ci tail = ring->next_to_use; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (head != tail) 608c2ecf20Sopenharmony_ci return (head < tail) ? 618c2ecf20Sopenharmony_ci tail - head : (tail + ring->count - head); 628c2ecf20Sopenharmony_ci return 0; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci/** 668c2ecf20Sopenharmony_ci * ice_check_for_hang_subtask - check for and recover hung queues 678c2ecf20Sopenharmony_ci * @pf: pointer to PF struct 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_cistatic void ice_check_for_hang_subtask(struct ice_pf *pf) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci struct ice_vsi *vsi = NULL; 728c2ecf20Sopenharmony_ci struct ice_hw *hw; 738c2ecf20Sopenharmony_ci unsigned int i; 748c2ecf20Sopenharmony_ci int packets; 758c2ecf20Sopenharmony_ci u32 v; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci ice_for_each_vsi(pf, v) 788c2ecf20Sopenharmony_ci if (pf->vsi[v] && pf->vsi[v]->type == ICE_VSI_PF) { 798c2ecf20Sopenharmony_ci vsi = pf->vsi[v]; 808c2ecf20Sopenharmony_ci break; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (!vsi || test_bit(__ICE_DOWN, vsi->state)) 848c2ecf20Sopenharmony_ci return; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (!(vsi->netdev && netif_carrier_ok(vsi->netdev))) 878c2ecf20Sopenharmony_ci return; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci hw = &vsi->back->hw; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci for (i = 0; i < vsi->num_txq; i++) { 928c2ecf20Sopenharmony_ci struct ice_ring *tx_ring = vsi->tx_rings[i]; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (tx_ring && tx_ring->desc) { 958c2ecf20Sopenharmony_ci /* If packet counter has not changed the queue is 968c2ecf20Sopenharmony_ci * likely stalled, so force an interrupt for this 978c2ecf20Sopenharmony_ci * queue. 988c2ecf20Sopenharmony_ci * 998c2ecf20Sopenharmony_ci * prev_pkt would be negative if there was no 1008c2ecf20Sopenharmony_ci * pending work. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ci packets = tx_ring->stats.pkts & INT_MAX; 1038c2ecf20Sopenharmony_ci if (tx_ring->tx_stats.prev_pkt == packets) { 1048c2ecf20Sopenharmony_ci /* Trigger sw interrupt to revive the queue */ 1058c2ecf20Sopenharmony_ci ice_trigger_sw_intr(hw, tx_ring->q_vector); 1068c2ecf20Sopenharmony_ci continue; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* Memory barrier between read of packet count and call 1108c2ecf20Sopenharmony_ci * to ice_get_tx_pending() 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ci smp_rmb(); 1138c2ecf20Sopenharmony_ci tx_ring->tx_stats.prev_pkt = 1148c2ecf20Sopenharmony_ci ice_get_tx_pending(tx_ring) ? packets : -1; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/** 1208c2ecf20Sopenharmony_ci * ice_init_mac_fltr - Set initial MAC filters 1218c2ecf20Sopenharmony_ci * @pf: board private structure 1228c2ecf20Sopenharmony_ci * 1238c2ecf20Sopenharmony_ci * Set initial set of MAC filters for PF VSI; configure filters for permanent 1248c2ecf20Sopenharmony_ci * address and broadcast address. If an error is encountered, netdevice will be 1258c2ecf20Sopenharmony_ci * unregistered. 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_cistatic int ice_init_mac_fltr(struct ice_pf *pf) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci enum ice_status status; 1308c2ecf20Sopenharmony_ci struct ice_vsi *vsi; 1318c2ecf20Sopenharmony_ci u8 *perm_addr; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci vsi = ice_get_main_vsi(pf); 1348c2ecf20Sopenharmony_ci if (!vsi) 1358c2ecf20Sopenharmony_ci return -EINVAL; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci perm_addr = vsi->port_info->mac.perm_addr; 1388c2ecf20Sopenharmony_ci status = ice_fltr_add_mac_and_broadcast(vsi, perm_addr, ICE_FWD_TO_VSI); 1398c2ecf20Sopenharmony_ci if (!status) 1408c2ecf20Sopenharmony_ci return 0; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci /* We aren't useful with no MAC filters, so unregister if we 1438c2ecf20Sopenharmony_ci * had an error 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_ci if (vsi->netdev->reg_state == NETREG_REGISTERED) { 1468c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(pf), "Could not add MAC filters error %s. Unregistering device\n", 1478c2ecf20Sopenharmony_ci ice_stat_str(status)); 1488c2ecf20Sopenharmony_ci unregister_netdev(vsi->netdev); 1498c2ecf20Sopenharmony_ci free_netdev(vsi->netdev); 1508c2ecf20Sopenharmony_ci vsi->netdev = NULL; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return -EIO; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/** 1578c2ecf20Sopenharmony_ci * ice_add_mac_to_sync_list - creates list of MAC addresses to be synced 1588c2ecf20Sopenharmony_ci * @netdev: the net device on which the sync is happening 1598c2ecf20Sopenharmony_ci * @addr: MAC address to sync 1608c2ecf20Sopenharmony_ci * 1618c2ecf20Sopenharmony_ci * This is a callback function which is called by the in kernel device sync 1628c2ecf20Sopenharmony_ci * functions (like __dev_uc_sync, __dev_mc_sync, etc). This function only 1638c2ecf20Sopenharmony_ci * populates the tmp_sync_list, which is later used by ice_add_mac to add the 1648c2ecf20Sopenharmony_ci * MAC filters from the hardware. 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_cistatic int ice_add_mac_to_sync_list(struct net_device *netdev, const u8 *addr) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 1698c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (ice_fltr_add_mac_to_list(vsi, &vsi->tmp_sync_list, addr, 1728c2ecf20Sopenharmony_ci ICE_FWD_TO_VSI)) 1738c2ecf20Sopenharmony_ci return -EINVAL; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci return 0; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci/** 1798c2ecf20Sopenharmony_ci * ice_add_mac_to_unsync_list - creates list of MAC addresses to be unsynced 1808c2ecf20Sopenharmony_ci * @netdev: the net device on which the unsync is happening 1818c2ecf20Sopenharmony_ci * @addr: MAC address to unsync 1828c2ecf20Sopenharmony_ci * 1838c2ecf20Sopenharmony_ci * This is a callback function which is called by the in kernel device unsync 1848c2ecf20Sopenharmony_ci * functions (like __dev_uc_unsync, __dev_mc_unsync, etc). This function only 1858c2ecf20Sopenharmony_ci * populates the tmp_unsync_list, which is later used by ice_remove_mac to 1868c2ecf20Sopenharmony_ci * delete the MAC filters from the hardware. 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_cistatic int ice_add_mac_to_unsync_list(struct net_device *netdev, const u8 *addr) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 1918c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* Under some circumstances, we might receive a request to delete our 1948c2ecf20Sopenharmony_ci * own device address from our uc list. Because we store the device 1958c2ecf20Sopenharmony_ci * address in the VSI's MAC filter list, we need to ignore such 1968c2ecf20Sopenharmony_ci * requests and not delete our device address from this list. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci if (ether_addr_equal(addr, netdev->dev_addr)) 1998c2ecf20Sopenharmony_ci return 0; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (ice_fltr_add_mac_to_list(vsi, &vsi->tmp_unsync_list, addr, 2028c2ecf20Sopenharmony_ci ICE_FWD_TO_VSI)) 2038c2ecf20Sopenharmony_ci return -EINVAL; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci/** 2098c2ecf20Sopenharmony_ci * ice_vsi_fltr_changed - check if filter state changed 2108c2ecf20Sopenharmony_ci * @vsi: VSI to be checked 2118c2ecf20Sopenharmony_ci * 2128c2ecf20Sopenharmony_ci * returns true if filter state has changed, false otherwise. 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_cistatic bool ice_vsi_fltr_changed(struct ice_vsi *vsi) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci return test_bit(ICE_VSI_FLAG_UMAC_FLTR_CHANGED, vsi->flags) || 2178c2ecf20Sopenharmony_ci test_bit(ICE_VSI_FLAG_MMAC_FLTR_CHANGED, vsi->flags) || 2188c2ecf20Sopenharmony_ci test_bit(ICE_VSI_FLAG_VLAN_FLTR_CHANGED, vsi->flags); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci/** 2228c2ecf20Sopenharmony_ci * ice_cfg_promisc - Enable or disable promiscuous mode for a given PF 2238c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 2248c2ecf20Sopenharmony_ci * @promisc_m: mask of promiscuous config bits 2258c2ecf20Sopenharmony_ci * @set_promisc: enable or disable promisc flag request 2268c2ecf20Sopenharmony_ci * 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_cistatic int ice_cfg_promisc(struct ice_vsi *vsi, u8 promisc_m, bool set_promisc) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct ice_hw *hw = &vsi->back->hw; 2318c2ecf20Sopenharmony_ci enum ice_status status = 0; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci if (vsi->type != ICE_VSI_PF) 2348c2ecf20Sopenharmony_ci return 0; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (vsi->vlan_ena) { 2378c2ecf20Sopenharmony_ci status = ice_set_vlan_vsi_promisc(hw, vsi->idx, promisc_m, 2388c2ecf20Sopenharmony_ci set_promisc); 2398c2ecf20Sopenharmony_ci } else { 2408c2ecf20Sopenharmony_ci if (set_promisc) 2418c2ecf20Sopenharmony_ci status = ice_set_vsi_promisc(hw, vsi->idx, promisc_m, 2428c2ecf20Sopenharmony_ci 0); 2438c2ecf20Sopenharmony_ci else 2448c2ecf20Sopenharmony_ci status = ice_clear_vsi_promisc(hw, vsi->idx, promisc_m, 2458c2ecf20Sopenharmony_ci 0); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (status) 2498c2ecf20Sopenharmony_ci return -EIO; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci/** 2558c2ecf20Sopenharmony_ci * ice_vsi_sync_fltr - Update the VSI filter list to the HW 2568c2ecf20Sopenharmony_ci * @vsi: ptr to the VSI 2578c2ecf20Sopenharmony_ci * 2588c2ecf20Sopenharmony_ci * Push any outstanding VSI filter changes through the AdminQ. 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_cistatic int ice_vsi_sync_fltr(struct ice_vsi *vsi) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(vsi->back); 2638c2ecf20Sopenharmony_ci struct net_device *netdev = vsi->netdev; 2648c2ecf20Sopenharmony_ci bool promisc_forced_on = false; 2658c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 2668c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 2678c2ecf20Sopenharmony_ci enum ice_status status = 0; 2688c2ecf20Sopenharmony_ci u32 changed_flags = 0; 2698c2ecf20Sopenharmony_ci u8 promisc_m; 2708c2ecf20Sopenharmony_ci int err = 0; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (!vsi->netdev) 2738c2ecf20Sopenharmony_ci return -EINVAL; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci while (test_and_set_bit(__ICE_CFG_BUSY, vsi->state)) 2768c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci changed_flags = vsi->current_netdev_flags ^ vsi->netdev->flags; 2798c2ecf20Sopenharmony_ci vsi->current_netdev_flags = vsi->netdev->flags; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vsi->tmp_sync_list); 2828c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&vsi->tmp_unsync_list); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (ice_vsi_fltr_changed(vsi)) { 2858c2ecf20Sopenharmony_ci clear_bit(ICE_VSI_FLAG_UMAC_FLTR_CHANGED, vsi->flags); 2868c2ecf20Sopenharmony_ci clear_bit(ICE_VSI_FLAG_MMAC_FLTR_CHANGED, vsi->flags); 2878c2ecf20Sopenharmony_ci clear_bit(ICE_VSI_FLAG_VLAN_FLTR_CHANGED, vsi->flags); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* grab the netdev's addr_list_lock */ 2908c2ecf20Sopenharmony_ci netif_addr_lock_bh(netdev); 2918c2ecf20Sopenharmony_ci __dev_uc_sync(netdev, ice_add_mac_to_sync_list, 2928c2ecf20Sopenharmony_ci ice_add_mac_to_unsync_list); 2938c2ecf20Sopenharmony_ci __dev_mc_sync(netdev, ice_add_mac_to_sync_list, 2948c2ecf20Sopenharmony_ci ice_add_mac_to_unsync_list); 2958c2ecf20Sopenharmony_ci /* our temp lists are populated. release lock */ 2968c2ecf20Sopenharmony_ci netif_addr_unlock_bh(netdev); 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* Remove MAC addresses in the unsync list */ 3008c2ecf20Sopenharmony_ci status = ice_fltr_remove_mac_list(vsi, &vsi->tmp_unsync_list); 3018c2ecf20Sopenharmony_ci ice_fltr_free_list(dev, &vsi->tmp_unsync_list); 3028c2ecf20Sopenharmony_ci if (status) { 3038c2ecf20Sopenharmony_ci netdev_err(netdev, "Failed to delete MAC filters\n"); 3048c2ecf20Sopenharmony_ci /* if we failed because of alloc failures, just bail */ 3058c2ecf20Sopenharmony_ci if (status == ICE_ERR_NO_MEMORY) { 3068c2ecf20Sopenharmony_ci err = -ENOMEM; 3078c2ecf20Sopenharmony_ci goto out; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* Add MAC addresses in the sync list */ 3128c2ecf20Sopenharmony_ci status = ice_fltr_add_mac_list(vsi, &vsi->tmp_sync_list); 3138c2ecf20Sopenharmony_ci ice_fltr_free_list(dev, &vsi->tmp_sync_list); 3148c2ecf20Sopenharmony_ci /* If filter is added successfully or already exists, do not go into 3158c2ecf20Sopenharmony_ci * 'if' condition and report it as error. Instead continue processing 3168c2ecf20Sopenharmony_ci * rest of the function. 3178c2ecf20Sopenharmony_ci */ 3188c2ecf20Sopenharmony_ci if (status && status != ICE_ERR_ALREADY_EXISTS) { 3198c2ecf20Sopenharmony_ci netdev_err(netdev, "Failed to add MAC filters\n"); 3208c2ecf20Sopenharmony_ci /* If there is no more space for new umac filters, VSI 3218c2ecf20Sopenharmony_ci * should go into promiscuous mode. There should be some 3228c2ecf20Sopenharmony_ci * space reserved for promiscuous filters. 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_ci if (hw->adminq.sq_last_status == ICE_AQ_RC_ENOSPC && 3258c2ecf20Sopenharmony_ci !test_and_set_bit(__ICE_FLTR_OVERFLOW_PROMISC, 3268c2ecf20Sopenharmony_ci vsi->state)) { 3278c2ecf20Sopenharmony_ci promisc_forced_on = true; 3288c2ecf20Sopenharmony_ci netdev_warn(netdev, "Reached MAC filter limit, forcing promisc mode on VSI %d\n", 3298c2ecf20Sopenharmony_ci vsi->vsi_num); 3308c2ecf20Sopenharmony_ci } else { 3318c2ecf20Sopenharmony_ci err = -EIO; 3328c2ecf20Sopenharmony_ci goto out; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci /* check for changes in promiscuous modes */ 3368c2ecf20Sopenharmony_ci if (changed_flags & IFF_ALLMULTI) { 3378c2ecf20Sopenharmony_ci if (vsi->current_netdev_flags & IFF_ALLMULTI) { 3388c2ecf20Sopenharmony_ci if (vsi->vlan_ena) 3398c2ecf20Sopenharmony_ci promisc_m = ICE_MCAST_VLAN_PROMISC_BITS; 3408c2ecf20Sopenharmony_ci else 3418c2ecf20Sopenharmony_ci promisc_m = ICE_MCAST_PROMISC_BITS; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci err = ice_cfg_promisc(vsi, promisc_m, true); 3448c2ecf20Sopenharmony_ci if (err) { 3458c2ecf20Sopenharmony_ci netdev_err(netdev, "Error setting Multicast promiscuous mode on VSI %i\n", 3468c2ecf20Sopenharmony_ci vsi->vsi_num); 3478c2ecf20Sopenharmony_ci vsi->current_netdev_flags &= ~IFF_ALLMULTI; 3488c2ecf20Sopenharmony_ci goto out_promisc; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci } else { 3518c2ecf20Sopenharmony_ci /* !(vsi->current_netdev_flags & IFF_ALLMULTI) */ 3528c2ecf20Sopenharmony_ci if (vsi->vlan_ena) 3538c2ecf20Sopenharmony_ci promisc_m = ICE_MCAST_VLAN_PROMISC_BITS; 3548c2ecf20Sopenharmony_ci else 3558c2ecf20Sopenharmony_ci promisc_m = ICE_MCAST_PROMISC_BITS; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci err = ice_cfg_promisc(vsi, promisc_m, false); 3588c2ecf20Sopenharmony_ci if (err) { 3598c2ecf20Sopenharmony_ci netdev_err(netdev, "Error clearing Multicast promiscuous mode on VSI %i\n", 3608c2ecf20Sopenharmony_ci vsi->vsi_num); 3618c2ecf20Sopenharmony_ci vsi->current_netdev_flags |= IFF_ALLMULTI; 3628c2ecf20Sopenharmony_ci goto out_promisc; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (((changed_flags & IFF_PROMISC) || promisc_forced_on) || 3688c2ecf20Sopenharmony_ci test_bit(ICE_VSI_FLAG_PROMISC_CHANGED, vsi->flags)) { 3698c2ecf20Sopenharmony_ci clear_bit(ICE_VSI_FLAG_PROMISC_CHANGED, vsi->flags); 3708c2ecf20Sopenharmony_ci if (vsi->current_netdev_flags & IFF_PROMISC) { 3718c2ecf20Sopenharmony_ci /* Apply Rx filter rule to get traffic from wire */ 3728c2ecf20Sopenharmony_ci if (!ice_is_dflt_vsi_in_use(pf->first_sw)) { 3738c2ecf20Sopenharmony_ci err = ice_set_dflt_vsi(pf->first_sw, vsi); 3748c2ecf20Sopenharmony_ci if (err && err != -EEXIST) { 3758c2ecf20Sopenharmony_ci netdev_err(netdev, "Error %d setting default VSI %i Rx rule\n", 3768c2ecf20Sopenharmony_ci err, vsi->vsi_num); 3778c2ecf20Sopenharmony_ci vsi->current_netdev_flags &= 3788c2ecf20Sopenharmony_ci ~IFF_PROMISC; 3798c2ecf20Sopenharmony_ci goto out_promisc; 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci ice_cfg_vlan_pruning(vsi, false, false); 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci } else { 3848c2ecf20Sopenharmony_ci /* Clear Rx filter to remove traffic from wire */ 3858c2ecf20Sopenharmony_ci if (ice_is_vsi_dflt_vsi(pf->first_sw, vsi)) { 3868c2ecf20Sopenharmony_ci err = ice_clear_dflt_vsi(pf->first_sw); 3878c2ecf20Sopenharmony_ci if (err) { 3888c2ecf20Sopenharmony_ci netdev_err(netdev, "Error %d clearing default VSI %i Rx rule\n", 3898c2ecf20Sopenharmony_ci err, vsi->vsi_num); 3908c2ecf20Sopenharmony_ci vsi->current_netdev_flags |= 3918c2ecf20Sopenharmony_ci IFF_PROMISC; 3928c2ecf20Sopenharmony_ci goto out_promisc; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci if (vsi->num_vlan > 1) 3958c2ecf20Sopenharmony_ci ice_cfg_vlan_pruning(vsi, true, false); 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci goto exit; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ciout_promisc: 4028c2ecf20Sopenharmony_ci set_bit(ICE_VSI_FLAG_PROMISC_CHANGED, vsi->flags); 4038c2ecf20Sopenharmony_ci goto exit; 4048c2ecf20Sopenharmony_ciout: 4058c2ecf20Sopenharmony_ci /* if something went wrong then set the changed flag so we try again */ 4068c2ecf20Sopenharmony_ci set_bit(ICE_VSI_FLAG_UMAC_FLTR_CHANGED, vsi->flags); 4078c2ecf20Sopenharmony_ci set_bit(ICE_VSI_FLAG_MMAC_FLTR_CHANGED, vsi->flags); 4088c2ecf20Sopenharmony_ciexit: 4098c2ecf20Sopenharmony_ci clear_bit(__ICE_CFG_BUSY, vsi->state); 4108c2ecf20Sopenharmony_ci return err; 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci/** 4148c2ecf20Sopenharmony_ci * ice_sync_fltr_subtask - Sync the VSI filter list with HW 4158c2ecf20Sopenharmony_ci * @pf: board private structure 4168c2ecf20Sopenharmony_ci */ 4178c2ecf20Sopenharmony_cistatic void ice_sync_fltr_subtask(struct ice_pf *pf) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci int v; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (!pf || !(test_bit(ICE_FLAG_FLTR_SYNC, pf->flags))) 4228c2ecf20Sopenharmony_ci return; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci clear_bit(ICE_FLAG_FLTR_SYNC, pf->flags); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci ice_for_each_vsi(pf, v) 4278c2ecf20Sopenharmony_ci if (pf->vsi[v] && ice_vsi_fltr_changed(pf->vsi[v]) && 4288c2ecf20Sopenharmony_ci ice_vsi_sync_fltr(pf->vsi[v])) { 4298c2ecf20Sopenharmony_ci /* come back and try again later */ 4308c2ecf20Sopenharmony_ci set_bit(ICE_FLAG_FLTR_SYNC, pf->flags); 4318c2ecf20Sopenharmony_ci break; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci/** 4368c2ecf20Sopenharmony_ci * ice_pf_dis_all_vsi - Pause all VSIs on a PF 4378c2ecf20Sopenharmony_ci * @pf: the PF 4388c2ecf20Sopenharmony_ci * @locked: is the rtnl_lock already held 4398c2ecf20Sopenharmony_ci */ 4408c2ecf20Sopenharmony_cistatic void ice_pf_dis_all_vsi(struct ice_pf *pf, bool locked) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci int v; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci ice_for_each_vsi(pf, v) 4458c2ecf20Sopenharmony_ci if (pf->vsi[v]) 4468c2ecf20Sopenharmony_ci ice_dis_vsi(pf->vsi[v], locked); 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci/** 4508c2ecf20Sopenharmony_ci * ice_prepare_for_reset - prep for the core to reset 4518c2ecf20Sopenharmony_ci * @pf: board private structure 4528c2ecf20Sopenharmony_ci * 4538c2ecf20Sopenharmony_ci * Inform or close all dependent features in prep for reset. 4548c2ecf20Sopenharmony_ci */ 4558c2ecf20Sopenharmony_cistatic void 4568c2ecf20Sopenharmony_ciice_prepare_for_reset(struct ice_pf *pf) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 4598c2ecf20Sopenharmony_ci unsigned int i; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* already prepared for reset */ 4628c2ecf20Sopenharmony_ci if (test_bit(__ICE_PREPARED_FOR_RESET, pf->state)) 4638c2ecf20Sopenharmony_ci return; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci /* Notify VFs of impending reset */ 4668c2ecf20Sopenharmony_ci if (ice_check_sq_alive(hw, &hw->mailboxq)) 4678c2ecf20Sopenharmony_ci ice_vc_notify_reset(pf); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* Disable VFs until reset is completed */ 4708c2ecf20Sopenharmony_ci ice_for_each_vf(pf, i) 4718c2ecf20Sopenharmony_ci ice_set_vf_state_qs_dis(&pf->vf[i]); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* clear SW filtering DB */ 4748c2ecf20Sopenharmony_ci ice_clear_hw_tbls(hw); 4758c2ecf20Sopenharmony_ci /* disable the VSIs and their queues that are not already DOWN */ 4768c2ecf20Sopenharmony_ci ice_pf_dis_all_vsi(pf, false); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (hw->port_info) 4798c2ecf20Sopenharmony_ci ice_sched_clear_port(hw->port_info); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci ice_shutdown_all_ctrlq(hw); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci set_bit(__ICE_PREPARED_FOR_RESET, pf->state); 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci/** 4878c2ecf20Sopenharmony_ci * ice_do_reset - Initiate one of many types of resets 4888c2ecf20Sopenharmony_ci * @pf: board private structure 4898c2ecf20Sopenharmony_ci * @reset_type: reset type requested 4908c2ecf20Sopenharmony_ci * before this function was called. 4918c2ecf20Sopenharmony_ci */ 4928c2ecf20Sopenharmony_cistatic void ice_do_reset(struct ice_pf *pf, enum ice_reset_req reset_type) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 4958c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci dev_dbg(dev, "reset_type 0x%x requested\n", reset_type); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci ice_prepare_for_reset(pf); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci /* trigger the reset */ 5028c2ecf20Sopenharmony_ci if (ice_reset(hw, reset_type)) { 5038c2ecf20Sopenharmony_ci dev_err(dev, "reset %d failed\n", reset_type); 5048c2ecf20Sopenharmony_ci set_bit(__ICE_RESET_FAILED, pf->state); 5058c2ecf20Sopenharmony_ci clear_bit(__ICE_RESET_OICR_RECV, pf->state); 5068c2ecf20Sopenharmony_ci clear_bit(__ICE_PREPARED_FOR_RESET, pf->state); 5078c2ecf20Sopenharmony_ci clear_bit(__ICE_PFR_REQ, pf->state); 5088c2ecf20Sopenharmony_ci clear_bit(__ICE_CORER_REQ, pf->state); 5098c2ecf20Sopenharmony_ci clear_bit(__ICE_GLOBR_REQ, pf->state); 5108c2ecf20Sopenharmony_ci return; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci /* PFR is a bit of a special case because it doesn't result in an OICR 5148c2ecf20Sopenharmony_ci * interrupt. So for PFR, rebuild after the reset and clear the reset- 5158c2ecf20Sopenharmony_ci * associated state bits. 5168c2ecf20Sopenharmony_ci */ 5178c2ecf20Sopenharmony_ci if (reset_type == ICE_RESET_PFR) { 5188c2ecf20Sopenharmony_ci pf->pfr_count++; 5198c2ecf20Sopenharmony_ci ice_rebuild(pf, reset_type); 5208c2ecf20Sopenharmony_ci clear_bit(__ICE_PREPARED_FOR_RESET, pf->state); 5218c2ecf20Sopenharmony_ci clear_bit(__ICE_PFR_REQ, pf->state); 5228c2ecf20Sopenharmony_ci ice_reset_all_vfs(pf, true); 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci/** 5278c2ecf20Sopenharmony_ci * ice_reset_subtask - Set up for resetting the device and driver 5288c2ecf20Sopenharmony_ci * @pf: board private structure 5298c2ecf20Sopenharmony_ci */ 5308c2ecf20Sopenharmony_cistatic void ice_reset_subtask(struct ice_pf *pf) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci enum ice_reset_req reset_type = ICE_RESET_INVAL; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* When a CORER/GLOBR/EMPR is about to happen, the hardware triggers an 5358c2ecf20Sopenharmony_ci * OICR interrupt. The OICR handler (ice_misc_intr) determines what type 5368c2ecf20Sopenharmony_ci * of reset is pending and sets bits in pf->state indicating the reset 5378c2ecf20Sopenharmony_ci * type and __ICE_RESET_OICR_RECV. So, if the latter bit is set 5388c2ecf20Sopenharmony_ci * prepare for pending reset if not already (for PF software-initiated 5398c2ecf20Sopenharmony_ci * global resets the software should already be prepared for it as 5408c2ecf20Sopenharmony_ci * indicated by __ICE_PREPARED_FOR_RESET; for global resets initiated 5418c2ecf20Sopenharmony_ci * by firmware or software on other PFs, that bit is not set so prepare 5428c2ecf20Sopenharmony_ci * for the reset now), poll for reset done, rebuild and return. 5438c2ecf20Sopenharmony_ci */ 5448c2ecf20Sopenharmony_ci if (test_bit(__ICE_RESET_OICR_RECV, pf->state)) { 5458c2ecf20Sopenharmony_ci /* Perform the largest reset requested */ 5468c2ecf20Sopenharmony_ci if (test_and_clear_bit(__ICE_CORER_RECV, pf->state)) 5478c2ecf20Sopenharmony_ci reset_type = ICE_RESET_CORER; 5488c2ecf20Sopenharmony_ci if (test_and_clear_bit(__ICE_GLOBR_RECV, pf->state)) 5498c2ecf20Sopenharmony_ci reset_type = ICE_RESET_GLOBR; 5508c2ecf20Sopenharmony_ci if (test_and_clear_bit(__ICE_EMPR_RECV, pf->state)) 5518c2ecf20Sopenharmony_ci reset_type = ICE_RESET_EMPR; 5528c2ecf20Sopenharmony_ci /* return if no valid reset type requested */ 5538c2ecf20Sopenharmony_ci if (reset_type == ICE_RESET_INVAL) 5548c2ecf20Sopenharmony_ci return; 5558c2ecf20Sopenharmony_ci ice_prepare_for_reset(pf); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* make sure we are ready to rebuild */ 5588c2ecf20Sopenharmony_ci if (ice_check_reset(&pf->hw)) { 5598c2ecf20Sopenharmony_ci set_bit(__ICE_RESET_FAILED, pf->state); 5608c2ecf20Sopenharmony_ci } else { 5618c2ecf20Sopenharmony_ci /* done with reset. start rebuild */ 5628c2ecf20Sopenharmony_ci pf->hw.reset_ongoing = false; 5638c2ecf20Sopenharmony_ci ice_rebuild(pf, reset_type); 5648c2ecf20Sopenharmony_ci /* clear bit to resume normal operations, but 5658c2ecf20Sopenharmony_ci * ICE_NEEDS_RESTART bit is set in case rebuild failed 5668c2ecf20Sopenharmony_ci */ 5678c2ecf20Sopenharmony_ci clear_bit(__ICE_RESET_OICR_RECV, pf->state); 5688c2ecf20Sopenharmony_ci clear_bit(__ICE_PREPARED_FOR_RESET, pf->state); 5698c2ecf20Sopenharmony_ci clear_bit(__ICE_PFR_REQ, pf->state); 5708c2ecf20Sopenharmony_ci clear_bit(__ICE_CORER_REQ, pf->state); 5718c2ecf20Sopenharmony_ci clear_bit(__ICE_GLOBR_REQ, pf->state); 5728c2ecf20Sopenharmony_ci ice_reset_all_vfs(pf, true); 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci return; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* No pending resets to finish processing. Check for new resets */ 5798c2ecf20Sopenharmony_ci if (test_bit(__ICE_PFR_REQ, pf->state)) 5808c2ecf20Sopenharmony_ci reset_type = ICE_RESET_PFR; 5818c2ecf20Sopenharmony_ci if (test_bit(__ICE_CORER_REQ, pf->state)) 5828c2ecf20Sopenharmony_ci reset_type = ICE_RESET_CORER; 5838c2ecf20Sopenharmony_ci if (test_bit(__ICE_GLOBR_REQ, pf->state)) 5848c2ecf20Sopenharmony_ci reset_type = ICE_RESET_GLOBR; 5858c2ecf20Sopenharmony_ci /* If no valid reset type requested just return */ 5868c2ecf20Sopenharmony_ci if (reset_type == ICE_RESET_INVAL) 5878c2ecf20Sopenharmony_ci return; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci /* reset if not already down or busy */ 5908c2ecf20Sopenharmony_ci if (!test_bit(__ICE_DOWN, pf->state) && 5918c2ecf20Sopenharmony_ci !test_bit(__ICE_CFG_BUSY, pf->state)) { 5928c2ecf20Sopenharmony_ci ice_do_reset(pf, reset_type); 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci} 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci/** 5978c2ecf20Sopenharmony_ci * ice_print_topo_conflict - print topology conflict message 5988c2ecf20Sopenharmony_ci * @vsi: the VSI whose topology status is being checked 5998c2ecf20Sopenharmony_ci */ 6008c2ecf20Sopenharmony_cistatic void ice_print_topo_conflict(struct ice_vsi *vsi) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci switch (vsi->port_info->phy.link_info.topo_media_conflict) { 6038c2ecf20Sopenharmony_ci case ICE_AQ_LINK_TOPO_CONFLICT: 6048c2ecf20Sopenharmony_ci case ICE_AQ_LINK_MEDIA_CONFLICT: 6058c2ecf20Sopenharmony_ci case ICE_AQ_LINK_TOPO_UNREACH_PRT: 6068c2ecf20Sopenharmony_ci case ICE_AQ_LINK_TOPO_UNDRUTIL_PRT: 6078c2ecf20Sopenharmony_ci case ICE_AQ_LINK_TOPO_UNDRUTIL_MEDIA: 6088c2ecf20Sopenharmony_ci netdev_info(vsi->netdev, "Possible mis-configuration of the Ethernet port detected, please use the Intel(R) Ethernet Port Configuration Tool application to address the issue.\n"); 6098c2ecf20Sopenharmony_ci break; 6108c2ecf20Sopenharmony_ci case ICE_AQ_LINK_TOPO_UNSUPP_MEDIA: 6118c2ecf20Sopenharmony_ci netdev_info(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"); 6128c2ecf20Sopenharmony_ci break; 6138c2ecf20Sopenharmony_ci default: 6148c2ecf20Sopenharmony_ci break; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci/** 6198c2ecf20Sopenharmony_ci * ice_print_link_msg - print link up or down message 6208c2ecf20Sopenharmony_ci * @vsi: the VSI whose link status is being queried 6218c2ecf20Sopenharmony_ci * @isup: boolean for if the link is now up or down 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_civoid ice_print_link_msg(struct ice_vsi *vsi, bool isup) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci struct ice_aqc_get_phy_caps_data *caps; 6268c2ecf20Sopenharmony_ci const char *an_advertised; 6278c2ecf20Sopenharmony_ci enum ice_status status; 6288c2ecf20Sopenharmony_ci const char *fec_req; 6298c2ecf20Sopenharmony_ci const char *speed; 6308c2ecf20Sopenharmony_ci const char *fec; 6318c2ecf20Sopenharmony_ci const char *fc; 6328c2ecf20Sopenharmony_ci const char *an; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci if (!vsi) 6358c2ecf20Sopenharmony_ci return; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if (vsi->current_isup == isup) 6388c2ecf20Sopenharmony_ci return; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci vsi->current_isup = isup; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (!isup) { 6438c2ecf20Sopenharmony_ci netdev_info(vsi->netdev, "NIC Link is Down\n"); 6448c2ecf20Sopenharmony_ci return; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci switch (vsi->port_info->phy.link_info.link_speed) { 6488c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_100GB: 6498c2ecf20Sopenharmony_ci speed = "100 G"; 6508c2ecf20Sopenharmony_ci break; 6518c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_50GB: 6528c2ecf20Sopenharmony_ci speed = "50 G"; 6538c2ecf20Sopenharmony_ci break; 6548c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_40GB: 6558c2ecf20Sopenharmony_ci speed = "40 G"; 6568c2ecf20Sopenharmony_ci break; 6578c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_25GB: 6588c2ecf20Sopenharmony_ci speed = "25 G"; 6598c2ecf20Sopenharmony_ci break; 6608c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_20GB: 6618c2ecf20Sopenharmony_ci speed = "20 G"; 6628c2ecf20Sopenharmony_ci break; 6638c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_10GB: 6648c2ecf20Sopenharmony_ci speed = "10 G"; 6658c2ecf20Sopenharmony_ci break; 6668c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_5GB: 6678c2ecf20Sopenharmony_ci speed = "5 G"; 6688c2ecf20Sopenharmony_ci break; 6698c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_2500MB: 6708c2ecf20Sopenharmony_ci speed = "2.5 G"; 6718c2ecf20Sopenharmony_ci break; 6728c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_1000MB: 6738c2ecf20Sopenharmony_ci speed = "1 G"; 6748c2ecf20Sopenharmony_ci break; 6758c2ecf20Sopenharmony_ci case ICE_AQ_LINK_SPEED_100MB: 6768c2ecf20Sopenharmony_ci speed = "100 M"; 6778c2ecf20Sopenharmony_ci break; 6788c2ecf20Sopenharmony_ci default: 6798c2ecf20Sopenharmony_ci speed = "Unknown"; 6808c2ecf20Sopenharmony_ci break; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci switch (vsi->port_info->fc.current_mode) { 6848c2ecf20Sopenharmony_ci case ICE_FC_FULL: 6858c2ecf20Sopenharmony_ci fc = "Rx/Tx"; 6868c2ecf20Sopenharmony_ci break; 6878c2ecf20Sopenharmony_ci case ICE_FC_TX_PAUSE: 6888c2ecf20Sopenharmony_ci fc = "Tx"; 6898c2ecf20Sopenharmony_ci break; 6908c2ecf20Sopenharmony_ci case ICE_FC_RX_PAUSE: 6918c2ecf20Sopenharmony_ci fc = "Rx"; 6928c2ecf20Sopenharmony_ci break; 6938c2ecf20Sopenharmony_ci case ICE_FC_NONE: 6948c2ecf20Sopenharmony_ci fc = "None"; 6958c2ecf20Sopenharmony_ci break; 6968c2ecf20Sopenharmony_ci default: 6978c2ecf20Sopenharmony_ci fc = "Unknown"; 6988c2ecf20Sopenharmony_ci break; 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci /* Get FEC mode based on negotiated link info */ 7028c2ecf20Sopenharmony_ci switch (vsi->port_info->phy.link_info.fec_info) { 7038c2ecf20Sopenharmony_ci case ICE_AQ_LINK_25G_RS_528_FEC_EN: 7048c2ecf20Sopenharmony_ci case ICE_AQ_LINK_25G_RS_544_FEC_EN: 7058c2ecf20Sopenharmony_ci fec = "RS-FEC"; 7068c2ecf20Sopenharmony_ci break; 7078c2ecf20Sopenharmony_ci case ICE_AQ_LINK_25G_KR_FEC_EN: 7088c2ecf20Sopenharmony_ci fec = "FC-FEC/BASE-R"; 7098c2ecf20Sopenharmony_ci break; 7108c2ecf20Sopenharmony_ci default: 7118c2ecf20Sopenharmony_ci fec = "NONE"; 7128c2ecf20Sopenharmony_ci break; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci /* check if autoneg completed, might be false due to not supported */ 7168c2ecf20Sopenharmony_ci if (vsi->port_info->phy.link_info.an_info & ICE_AQ_AN_COMPLETED) 7178c2ecf20Sopenharmony_ci an = "True"; 7188c2ecf20Sopenharmony_ci else 7198c2ecf20Sopenharmony_ci an = "False"; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci /* Get FEC mode requested based on PHY caps last SW configuration */ 7228c2ecf20Sopenharmony_ci caps = kzalloc(sizeof(*caps), GFP_KERNEL); 7238c2ecf20Sopenharmony_ci if (!caps) { 7248c2ecf20Sopenharmony_ci fec_req = "Unknown"; 7258c2ecf20Sopenharmony_ci an_advertised = "Unknown"; 7268c2ecf20Sopenharmony_ci goto done; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci status = ice_aq_get_phy_caps(vsi->port_info, false, 7308c2ecf20Sopenharmony_ci ICE_AQC_REPORT_ACTIVE_CFG, caps, NULL); 7318c2ecf20Sopenharmony_ci if (status) 7328c2ecf20Sopenharmony_ci netdev_info(vsi->netdev, "Get phy capability failed.\n"); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci an_advertised = ice_is_phy_caps_an_enabled(caps) ? "On" : "Off"; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if (caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_528_REQ || 7378c2ecf20Sopenharmony_ci caps->link_fec_options & ICE_AQC_PHY_FEC_25G_RS_544_REQ) 7388c2ecf20Sopenharmony_ci fec_req = "RS-FEC"; 7398c2ecf20Sopenharmony_ci else if (caps->link_fec_options & ICE_AQC_PHY_FEC_10G_KR_40G_KR4_REQ || 7408c2ecf20Sopenharmony_ci caps->link_fec_options & ICE_AQC_PHY_FEC_25G_KR_REQ) 7418c2ecf20Sopenharmony_ci fec_req = "FC-FEC/BASE-R"; 7428c2ecf20Sopenharmony_ci else 7438c2ecf20Sopenharmony_ci fec_req = "NONE"; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci kfree(caps); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cidone: 7488c2ecf20Sopenharmony_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", 7498c2ecf20Sopenharmony_ci speed, fec_req, fec, an_advertised, an, fc); 7508c2ecf20Sopenharmony_ci ice_print_topo_conflict(vsi); 7518c2ecf20Sopenharmony_ci} 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci/** 7548c2ecf20Sopenharmony_ci * ice_vsi_link_event - update the VSI's netdev 7558c2ecf20Sopenharmony_ci * @vsi: the VSI on which the link event occurred 7568c2ecf20Sopenharmony_ci * @link_up: whether or not the VSI needs to be set up or down 7578c2ecf20Sopenharmony_ci */ 7588c2ecf20Sopenharmony_cistatic void ice_vsi_link_event(struct ice_vsi *vsi, bool link_up) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci if (!vsi) 7618c2ecf20Sopenharmony_ci return; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (test_bit(__ICE_DOWN, vsi->state) || !vsi->netdev) 7648c2ecf20Sopenharmony_ci return; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_PF) { 7678c2ecf20Sopenharmony_ci if (link_up == netif_carrier_ok(vsi->netdev)) 7688c2ecf20Sopenharmony_ci return; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if (link_up) { 7718c2ecf20Sopenharmony_ci netif_carrier_on(vsi->netdev); 7728c2ecf20Sopenharmony_ci netif_tx_wake_all_queues(vsi->netdev); 7738c2ecf20Sopenharmony_ci } else { 7748c2ecf20Sopenharmony_ci netif_carrier_off(vsi->netdev); 7758c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(vsi->netdev); 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci/** 7818c2ecf20Sopenharmony_ci * ice_set_dflt_mib - send a default config MIB to the FW 7828c2ecf20Sopenharmony_ci * @pf: private PF struct 7838c2ecf20Sopenharmony_ci * 7848c2ecf20Sopenharmony_ci * This function sends a default configuration MIB to the FW. 7858c2ecf20Sopenharmony_ci * 7868c2ecf20Sopenharmony_ci * If this function errors out at any point, the driver is still able to 7878c2ecf20Sopenharmony_ci * function. The main impact is that LFC may not operate as expected. 7888c2ecf20Sopenharmony_ci * Therefore an error state in this function should be treated with a DBG 7898c2ecf20Sopenharmony_ci * message and continue on with driver rebuild/reenable. 7908c2ecf20Sopenharmony_ci */ 7918c2ecf20Sopenharmony_cistatic void ice_set_dflt_mib(struct ice_pf *pf) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 7948c2ecf20Sopenharmony_ci u8 mib_type, *buf, *lldpmib = NULL; 7958c2ecf20Sopenharmony_ci u16 len, typelen, offset = 0; 7968c2ecf20Sopenharmony_ci struct ice_lldp_org_tlv *tlv; 7978c2ecf20Sopenharmony_ci struct ice_hw *hw; 7988c2ecf20Sopenharmony_ci u32 ouisubtype; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci if (!pf) { 8018c2ecf20Sopenharmony_ci dev_dbg(dev, "%s NULL pf pointer\n", __func__); 8028c2ecf20Sopenharmony_ci return; 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci hw = &pf->hw; 8068c2ecf20Sopenharmony_ci mib_type = SET_LOCAL_MIB_TYPE_LOCAL_MIB; 8078c2ecf20Sopenharmony_ci lldpmib = kzalloc(ICE_LLDPDU_SIZE, GFP_KERNEL); 8088c2ecf20Sopenharmony_ci if (!lldpmib) { 8098c2ecf20Sopenharmony_ci dev_dbg(dev, "%s Failed to allocate MIB memory\n", 8108c2ecf20Sopenharmony_ci __func__); 8118c2ecf20Sopenharmony_ci return; 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci /* Add ETS CFG TLV */ 8158c2ecf20Sopenharmony_ci tlv = (struct ice_lldp_org_tlv *)lldpmib; 8168c2ecf20Sopenharmony_ci typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) | 8178c2ecf20Sopenharmony_ci ICE_IEEE_ETS_TLV_LEN); 8188c2ecf20Sopenharmony_ci tlv->typelen = htons(typelen); 8198c2ecf20Sopenharmony_ci ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) | 8208c2ecf20Sopenharmony_ci ICE_IEEE_SUBTYPE_ETS_CFG); 8218c2ecf20Sopenharmony_ci tlv->ouisubtype = htonl(ouisubtype); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci buf = tlv->tlvinfo; 8248c2ecf20Sopenharmony_ci buf[0] = 0; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci /* ETS CFG all UPs map to TC 0. Next 4 (1 - 4) Octets = 0. 8278c2ecf20Sopenharmony_ci * Octets 5 - 12 are BW values, set octet 5 to 100% BW. 8288c2ecf20Sopenharmony_ci * Octets 13 - 20 are TSA values - leave as zeros 8298c2ecf20Sopenharmony_ci */ 8308c2ecf20Sopenharmony_ci buf[5] = 0x64; 8318c2ecf20Sopenharmony_ci len = (typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S; 8328c2ecf20Sopenharmony_ci offset += len + 2; 8338c2ecf20Sopenharmony_ci tlv = (struct ice_lldp_org_tlv *) 8348c2ecf20Sopenharmony_ci ((char *)tlv + sizeof(tlv->typelen) + len); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci /* Add ETS REC TLV */ 8378c2ecf20Sopenharmony_ci buf = tlv->tlvinfo; 8388c2ecf20Sopenharmony_ci tlv->typelen = htons(typelen); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) | 8418c2ecf20Sopenharmony_ci ICE_IEEE_SUBTYPE_ETS_REC); 8428c2ecf20Sopenharmony_ci tlv->ouisubtype = htonl(ouisubtype); 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci /* First octet of buf is reserved 8458c2ecf20Sopenharmony_ci * Octets 1 - 4 map UP to TC - all UPs map to zero 8468c2ecf20Sopenharmony_ci * Octets 5 - 12 are BW values - set TC 0 to 100%. 8478c2ecf20Sopenharmony_ci * Octets 13 - 20 are TSA value - leave as zeros 8488c2ecf20Sopenharmony_ci */ 8498c2ecf20Sopenharmony_ci buf[5] = 0x64; 8508c2ecf20Sopenharmony_ci offset += len + 2; 8518c2ecf20Sopenharmony_ci tlv = (struct ice_lldp_org_tlv *) 8528c2ecf20Sopenharmony_ci ((char *)tlv + sizeof(tlv->typelen) + len); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* Add PFC CFG TLV */ 8558c2ecf20Sopenharmony_ci typelen = ((ICE_TLV_TYPE_ORG << ICE_LLDP_TLV_TYPE_S) | 8568c2ecf20Sopenharmony_ci ICE_IEEE_PFC_TLV_LEN); 8578c2ecf20Sopenharmony_ci tlv->typelen = htons(typelen); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci ouisubtype = ((ICE_IEEE_8021QAZ_OUI << ICE_LLDP_TLV_OUI_S) | 8608c2ecf20Sopenharmony_ci ICE_IEEE_SUBTYPE_PFC_CFG); 8618c2ecf20Sopenharmony_ci tlv->ouisubtype = htonl(ouisubtype); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci /* Octet 1 left as all zeros - PFC disabled */ 8648c2ecf20Sopenharmony_ci buf[0] = 0x08; 8658c2ecf20Sopenharmony_ci len = (typelen & ICE_LLDP_TLV_LEN_M) >> ICE_LLDP_TLV_LEN_S; 8668c2ecf20Sopenharmony_ci offset += len + 2; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (ice_aq_set_lldp_mib(hw, mib_type, (void *)lldpmib, offset, NULL)) 8698c2ecf20Sopenharmony_ci dev_dbg(dev, "%s Failed to set default LLDP MIB\n", __func__); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci kfree(lldpmib); 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci/** 8758c2ecf20Sopenharmony_ci * ice_link_event - process the link event 8768c2ecf20Sopenharmony_ci * @pf: PF that the link event is associated with 8778c2ecf20Sopenharmony_ci * @pi: port_info for the port that the link event is associated with 8788c2ecf20Sopenharmony_ci * @link_up: true if the physical link is up and false if it is down 8798c2ecf20Sopenharmony_ci * @link_speed: current link speed received from the link event 8808c2ecf20Sopenharmony_ci * 8818c2ecf20Sopenharmony_ci * Returns 0 on success and negative on failure 8828c2ecf20Sopenharmony_ci */ 8838c2ecf20Sopenharmony_cistatic int 8848c2ecf20Sopenharmony_ciice_link_event(struct ice_pf *pf, struct ice_port_info *pi, bool link_up, 8858c2ecf20Sopenharmony_ci u16 link_speed) 8868c2ecf20Sopenharmony_ci{ 8878c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 8888c2ecf20Sopenharmony_ci struct ice_phy_info *phy_info; 8898c2ecf20Sopenharmony_ci struct ice_vsi *vsi; 8908c2ecf20Sopenharmony_ci u16 old_link_speed; 8918c2ecf20Sopenharmony_ci bool old_link; 8928c2ecf20Sopenharmony_ci int result; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci phy_info = &pi->phy; 8958c2ecf20Sopenharmony_ci phy_info->link_info_old = phy_info->link_info; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci old_link = !!(phy_info->link_info_old.link_info & ICE_AQ_LINK_UP); 8988c2ecf20Sopenharmony_ci old_link_speed = phy_info->link_info_old.link_speed; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci /* update the link info structures and re-enable link events, 9018c2ecf20Sopenharmony_ci * don't bail on failure due to other book keeping needed 9028c2ecf20Sopenharmony_ci */ 9038c2ecf20Sopenharmony_ci result = ice_update_link_info(pi); 9048c2ecf20Sopenharmony_ci if (result) 9058c2ecf20Sopenharmony_ci dev_dbg(dev, "Failed to update link status and re-enable link events for port %d\n", 9068c2ecf20Sopenharmony_ci pi->lport); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci /* Check if the link state is up after updating link info, and treat 9098c2ecf20Sopenharmony_ci * this event as an UP event since the link is actually UP now. 9108c2ecf20Sopenharmony_ci */ 9118c2ecf20Sopenharmony_ci if (phy_info->link_info.link_info & ICE_AQ_LINK_UP) 9128c2ecf20Sopenharmony_ci link_up = true; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci vsi = ice_get_main_vsi(pf); 9158c2ecf20Sopenharmony_ci if (!vsi || !vsi->port_info) 9168c2ecf20Sopenharmony_ci return -EINVAL; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci /* turn off PHY if media was removed */ 9198c2ecf20Sopenharmony_ci if (!test_bit(ICE_FLAG_NO_MEDIA, pf->flags) && 9208c2ecf20Sopenharmony_ci !(pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE)) { 9218c2ecf20Sopenharmony_ci set_bit(ICE_FLAG_NO_MEDIA, pf->flags); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci result = ice_aq_set_link_restart_an(pi, false, NULL); 9248c2ecf20Sopenharmony_ci if (result) { 9258c2ecf20Sopenharmony_ci dev_dbg(dev, "Failed to set link down, VSI %d error %d\n", 9268c2ecf20Sopenharmony_ci vsi->vsi_num, result); 9278c2ecf20Sopenharmony_ci return result; 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci /* if the old link up/down and speed is the same as the new */ 9328c2ecf20Sopenharmony_ci if (link_up == old_link && link_speed == old_link_speed) 9338c2ecf20Sopenharmony_ci return result; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci if (ice_is_dcb_active(pf)) { 9368c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_DCB_ENA, pf->flags)) 9378c2ecf20Sopenharmony_ci ice_dcb_rebuild(pf); 9388c2ecf20Sopenharmony_ci } else { 9398c2ecf20Sopenharmony_ci if (link_up) 9408c2ecf20Sopenharmony_ci ice_set_dflt_mib(pf); 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci ice_vsi_link_event(vsi, link_up); 9438c2ecf20Sopenharmony_ci ice_print_link_msg(vsi, link_up); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci ice_vc_notify_link_state(pf); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci return result; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci/** 9518c2ecf20Sopenharmony_ci * ice_watchdog_subtask - periodic tasks not using event driven scheduling 9528c2ecf20Sopenharmony_ci * @pf: board private structure 9538c2ecf20Sopenharmony_ci */ 9548c2ecf20Sopenharmony_cistatic void ice_watchdog_subtask(struct ice_pf *pf) 9558c2ecf20Sopenharmony_ci{ 9568c2ecf20Sopenharmony_ci int i; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci /* if interface is down do nothing */ 9598c2ecf20Sopenharmony_ci if (test_bit(__ICE_DOWN, pf->state) || 9608c2ecf20Sopenharmony_ci test_bit(__ICE_CFG_BUSY, pf->state)) 9618c2ecf20Sopenharmony_ci return; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci /* make sure we don't do these things too often */ 9648c2ecf20Sopenharmony_ci if (time_before(jiffies, 9658c2ecf20Sopenharmony_ci pf->serv_tmr_prev + pf->serv_tmr_period)) 9668c2ecf20Sopenharmony_ci return; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci pf->serv_tmr_prev = jiffies; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci /* Update the stats for active netdevs so the network stack 9718c2ecf20Sopenharmony_ci * can look at updated numbers whenever it cares to 9728c2ecf20Sopenharmony_ci */ 9738c2ecf20Sopenharmony_ci ice_update_pf_stats(pf); 9748c2ecf20Sopenharmony_ci ice_for_each_vsi(pf, i) 9758c2ecf20Sopenharmony_ci if (pf->vsi[i] && pf->vsi[i]->netdev) 9768c2ecf20Sopenharmony_ci ice_update_vsi_stats(pf->vsi[i]); 9778c2ecf20Sopenharmony_ci} 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci/** 9808c2ecf20Sopenharmony_ci * ice_init_link_events - enable/initialize link events 9818c2ecf20Sopenharmony_ci * @pi: pointer to the port_info instance 9828c2ecf20Sopenharmony_ci * 9838c2ecf20Sopenharmony_ci * Returns -EIO on failure, 0 on success 9848c2ecf20Sopenharmony_ci */ 9858c2ecf20Sopenharmony_cistatic int ice_init_link_events(struct ice_port_info *pi) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci u16 mask; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci mask = ~((u16)(ICE_AQ_LINK_EVENT_UPDOWN | ICE_AQ_LINK_EVENT_MEDIA_NA | 9908c2ecf20Sopenharmony_ci ICE_AQ_LINK_EVENT_MODULE_QUAL_FAIL)); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci if (ice_aq_set_event_mask(pi->hw, pi->lport, mask, NULL)) { 9938c2ecf20Sopenharmony_ci dev_dbg(ice_hw_to_dev(pi->hw), "Failed to set link event mask for port %d\n", 9948c2ecf20Sopenharmony_ci pi->lport); 9958c2ecf20Sopenharmony_ci return -EIO; 9968c2ecf20Sopenharmony_ci } 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_ci if (ice_aq_get_link_info(pi, true, NULL, NULL)) { 9998c2ecf20Sopenharmony_ci dev_dbg(ice_hw_to_dev(pi->hw), "Failed to enable link events for port %d\n", 10008c2ecf20Sopenharmony_ci pi->lport); 10018c2ecf20Sopenharmony_ci return -EIO; 10028c2ecf20Sopenharmony_ci } 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci return 0; 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci/** 10088c2ecf20Sopenharmony_ci * ice_handle_link_event - handle link event via ARQ 10098c2ecf20Sopenharmony_ci * @pf: PF that the link event is associated with 10108c2ecf20Sopenharmony_ci * @event: event structure containing link status info 10118c2ecf20Sopenharmony_ci */ 10128c2ecf20Sopenharmony_cistatic int 10138c2ecf20Sopenharmony_ciice_handle_link_event(struct ice_pf *pf, struct ice_rq_event_info *event) 10148c2ecf20Sopenharmony_ci{ 10158c2ecf20Sopenharmony_ci struct ice_aqc_get_link_status_data *link_data; 10168c2ecf20Sopenharmony_ci struct ice_port_info *port_info; 10178c2ecf20Sopenharmony_ci int status; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci link_data = (struct ice_aqc_get_link_status_data *)event->msg_buf; 10208c2ecf20Sopenharmony_ci port_info = pf->hw.port_info; 10218c2ecf20Sopenharmony_ci if (!port_info) 10228c2ecf20Sopenharmony_ci return -EINVAL; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci status = ice_link_event(pf, port_info, 10258c2ecf20Sopenharmony_ci !!(link_data->link_info & ICE_AQ_LINK_UP), 10268c2ecf20Sopenharmony_ci le16_to_cpu(link_data->link_speed)); 10278c2ecf20Sopenharmony_ci if (status) 10288c2ecf20Sopenharmony_ci dev_dbg(ice_pf_to_dev(pf), "Could not process link event, error %d\n", 10298c2ecf20Sopenharmony_ci status); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci return status; 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_cienum ice_aq_task_state { 10358c2ecf20Sopenharmony_ci ICE_AQ_TASK_WAITING = 0, 10368c2ecf20Sopenharmony_ci ICE_AQ_TASK_COMPLETE, 10378c2ecf20Sopenharmony_ci ICE_AQ_TASK_CANCELED, 10388c2ecf20Sopenharmony_ci}; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cistruct ice_aq_task { 10418c2ecf20Sopenharmony_ci struct hlist_node entry; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci u16 opcode; 10448c2ecf20Sopenharmony_ci struct ice_rq_event_info *event; 10458c2ecf20Sopenharmony_ci enum ice_aq_task_state state; 10468c2ecf20Sopenharmony_ci}; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci/** 10498c2ecf20Sopenharmony_ci * ice_wait_for_aq_event - Wait for an AdminQ event from firmware 10508c2ecf20Sopenharmony_ci * @pf: pointer to the PF private structure 10518c2ecf20Sopenharmony_ci * @opcode: the opcode to wait for 10528c2ecf20Sopenharmony_ci * @timeout: how long to wait, in jiffies 10538c2ecf20Sopenharmony_ci * @event: storage for the event info 10548c2ecf20Sopenharmony_ci * 10558c2ecf20Sopenharmony_ci * Waits for a specific AdminQ completion event on the ARQ for a given PF. The 10568c2ecf20Sopenharmony_ci * current thread will be put to sleep until the specified event occurs or 10578c2ecf20Sopenharmony_ci * until the given timeout is reached. 10588c2ecf20Sopenharmony_ci * 10598c2ecf20Sopenharmony_ci * To obtain only the descriptor contents, pass an event without an allocated 10608c2ecf20Sopenharmony_ci * msg_buf. If the complete data buffer is desired, allocate the 10618c2ecf20Sopenharmony_ci * event->msg_buf with enough space ahead of time. 10628c2ecf20Sopenharmony_ci * 10638c2ecf20Sopenharmony_ci * Returns: zero on success, or a negative error code on failure. 10648c2ecf20Sopenharmony_ci */ 10658c2ecf20Sopenharmony_ciint ice_aq_wait_for_event(struct ice_pf *pf, u16 opcode, unsigned long timeout, 10668c2ecf20Sopenharmony_ci struct ice_rq_event_info *event) 10678c2ecf20Sopenharmony_ci{ 10688c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 10698c2ecf20Sopenharmony_ci struct ice_aq_task *task; 10708c2ecf20Sopenharmony_ci unsigned long start; 10718c2ecf20Sopenharmony_ci long ret; 10728c2ecf20Sopenharmony_ci int err; 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci task = kzalloc(sizeof(*task), GFP_KERNEL); 10758c2ecf20Sopenharmony_ci if (!task) 10768c2ecf20Sopenharmony_ci return -ENOMEM; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci INIT_HLIST_NODE(&task->entry); 10798c2ecf20Sopenharmony_ci task->opcode = opcode; 10808c2ecf20Sopenharmony_ci task->event = event; 10818c2ecf20Sopenharmony_ci task->state = ICE_AQ_TASK_WAITING; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci spin_lock_bh(&pf->aq_wait_lock); 10848c2ecf20Sopenharmony_ci hlist_add_head(&task->entry, &pf->aq_wait_list); 10858c2ecf20Sopenharmony_ci spin_unlock_bh(&pf->aq_wait_lock); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci start = jiffies; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci ret = wait_event_interruptible_timeout(pf->aq_wait_queue, task->state, 10908c2ecf20Sopenharmony_ci timeout); 10918c2ecf20Sopenharmony_ci switch (task->state) { 10928c2ecf20Sopenharmony_ci case ICE_AQ_TASK_WAITING: 10938c2ecf20Sopenharmony_ci err = ret < 0 ? ret : -ETIMEDOUT; 10948c2ecf20Sopenharmony_ci break; 10958c2ecf20Sopenharmony_ci case ICE_AQ_TASK_CANCELED: 10968c2ecf20Sopenharmony_ci err = ret < 0 ? ret : -ECANCELED; 10978c2ecf20Sopenharmony_ci break; 10988c2ecf20Sopenharmony_ci case ICE_AQ_TASK_COMPLETE: 10998c2ecf20Sopenharmony_ci err = ret < 0 ? ret : 0; 11008c2ecf20Sopenharmony_ci break; 11018c2ecf20Sopenharmony_ci default: 11028c2ecf20Sopenharmony_ci WARN(1, "Unexpected AdminQ wait task state %u", task->state); 11038c2ecf20Sopenharmony_ci err = -EINVAL; 11048c2ecf20Sopenharmony_ci break; 11058c2ecf20Sopenharmony_ci } 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci dev_dbg(dev, "Waited %u msecs (max %u msecs) for firmware response to op 0x%04x\n", 11088c2ecf20Sopenharmony_ci jiffies_to_msecs(jiffies - start), 11098c2ecf20Sopenharmony_ci jiffies_to_msecs(timeout), 11108c2ecf20Sopenharmony_ci opcode); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci spin_lock_bh(&pf->aq_wait_lock); 11138c2ecf20Sopenharmony_ci hlist_del(&task->entry); 11148c2ecf20Sopenharmony_ci spin_unlock_bh(&pf->aq_wait_lock); 11158c2ecf20Sopenharmony_ci kfree(task); 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci return err; 11188c2ecf20Sopenharmony_ci} 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci/** 11218c2ecf20Sopenharmony_ci * ice_aq_check_events - Check if any thread is waiting for an AdminQ event 11228c2ecf20Sopenharmony_ci * @pf: pointer to the PF private structure 11238c2ecf20Sopenharmony_ci * @opcode: the opcode of the event 11248c2ecf20Sopenharmony_ci * @event: the event to check 11258c2ecf20Sopenharmony_ci * 11268c2ecf20Sopenharmony_ci * Loops over the current list of pending threads waiting for an AdminQ event. 11278c2ecf20Sopenharmony_ci * For each matching task, copy the contents of the event into the task 11288c2ecf20Sopenharmony_ci * structure and wake up the thread. 11298c2ecf20Sopenharmony_ci * 11308c2ecf20Sopenharmony_ci * If multiple threads wait for the same opcode, they will all be woken up. 11318c2ecf20Sopenharmony_ci * 11328c2ecf20Sopenharmony_ci * Note that event->msg_buf will only be duplicated if the event has a buffer 11338c2ecf20Sopenharmony_ci * with enough space already allocated. Otherwise, only the descriptor and 11348c2ecf20Sopenharmony_ci * message length will be copied. 11358c2ecf20Sopenharmony_ci * 11368c2ecf20Sopenharmony_ci * Returns: true if an event was found, false otherwise 11378c2ecf20Sopenharmony_ci */ 11388c2ecf20Sopenharmony_cistatic void ice_aq_check_events(struct ice_pf *pf, u16 opcode, 11398c2ecf20Sopenharmony_ci struct ice_rq_event_info *event) 11408c2ecf20Sopenharmony_ci{ 11418c2ecf20Sopenharmony_ci struct ice_rq_event_info *task_ev; 11428c2ecf20Sopenharmony_ci struct ice_aq_task *task; 11438c2ecf20Sopenharmony_ci bool found = false; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci spin_lock_bh(&pf->aq_wait_lock); 11468c2ecf20Sopenharmony_ci hlist_for_each_entry(task, &pf->aq_wait_list, entry) { 11478c2ecf20Sopenharmony_ci if (task->state || task->opcode != opcode) 11488c2ecf20Sopenharmony_ci continue; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci task_ev = task->event; 11518c2ecf20Sopenharmony_ci memcpy(&task_ev->desc, &event->desc, sizeof(event->desc)); 11528c2ecf20Sopenharmony_ci task_ev->msg_len = event->msg_len; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci /* Only copy the data buffer if a destination was set */ 11558c2ecf20Sopenharmony_ci if (task_ev->msg_buf && task_ev->buf_len >= event->buf_len) { 11568c2ecf20Sopenharmony_ci memcpy(task_ev->msg_buf, event->msg_buf, 11578c2ecf20Sopenharmony_ci event->buf_len); 11588c2ecf20Sopenharmony_ci task_ev->buf_len = event->buf_len; 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci task->state = ICE_AQ_TASK_COMPLETE; 11628c2ecf20Sopenharmony_ci found = true; 11638c2ecf20Sopenharmony_ci } 11648c2ecf20Sopenharmony_ci spin_unlock_bh(&pf->aq_wait_lock); 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci if (found) 11678c2ecf20Sopenharmony_ci wake_up(&pf->aq_wait_queue); 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci/** 11718c2ecf20Sopenharmony_ci * ice_aq_cancel_waiting_tasks - Immediately cancel all waiting tasks 11728c2ecf20Sopenharmony_ci * @pf: the PF private structure 11738c2ecf20Sopenharmony_ci * 11748c2ecf20Sopenharmony_ci * Set all waiting tasks to ICE_AQ_TASK_CANCELED, and wake up their threads. 11758c2ecf20Sopenharmony_ci * This will then cause ice_aq_wait_for_event to exit with -ECANCELED. 11768c2ecf20Sopenharmony_ci */ 11778c2ecf20Sopenharmony_cistatic void ice_aq_cancel_waiting_tasks(struct ice_pf *pf) 11788c2ecf20Sopenharmony_ci{ 11798c2ecf20Sopenharmony_ci struct ice_aq_task *task; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci spin_lock_bh(&pf->aq_wait_lock); 11828c2ecf20Sopenharmony_ci hlist_for_each_entry(task, &pf->aq_wait_list, entry) 11838c2ecf20Sopenharmony_ci task->state = ICE_AQ_TASK_CANCELED; 11848c2ecf20Sopenharmony_ci spin_unlock_bh(&pf->aq_wait_lock); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci wake_up(&pf->aq_wait_queue); 11878c2ecf20Sopenharmony_ci} 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci/** 11908c2ecf20Sopenharmony_ci * __ice_clean_ctrlq - helper function to clean controlq rings 11918c2ecf20Sopenharmony_ci * @pf: ptr to struct ice_pf 11928c2ecf20Sopenharmony_ci * @q_type: specific Control queue type 11938c2ecf20Sopenharmony_ci */ 11948c2ecf20Sopenharmony_cistatic int __ice_clean_ctrlq(struct ice_pf *pf, enum ice_ctl_q q_type) 11958c2ecf20Sopenharmony_ci{ 11968c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 11978c2ecf20Sopenharmony_ci struct ice_rq_event_info event; 11988c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 11998c2ecf20Sopenharmony_ci struct ice_ctl_q_info *cq; 12008c2ecf20Sopenharmony_ci u16 pending, i = 0; 12018c2ecf20Sopenharmony_ci const char *qtype; 12028c2ecf20Sopenharmony_ci u32 oldval, val; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci /* Do not clean control queue if/when PF reset fails */ 12058c2ecf20Sopenharmony_ci if (test_bit(__ICE_RESET_FAILED, pf->state)) 12068c2ecf20Sopenharmony_ci return 0; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci switch (q_type) { 12098c2ecf20Sopenharmony_ci case ICE_CTL_Q_ADMIN: 12108c2ecf20Sopenharmony_ci cq = &hw->adminq; 12118c2ecf20Sopenharmony_ci qtype = "Admin"; 12128c2ecf20Sopenharmony_ci break; 12138c2ecf20Sopenharmony_ci case ICE_CTL_Q_MAILBOX: 12148c2ecf20Sopenharmony_ci cq = &hw->mailboxq; 12158c2ecf20Sopenharmony_ci qtype = "Mailbox"; 12168c2ecf20Sopenharmony_ci break; 12178c2ecf20Sopenharmony_ci default: 12188c2ecf20Sopenharmony_ci dev_warn(dev, "Unknown control queue type 0x%x\n", q_type); 12198c2ecf20Sopenharmony_ci return 0; 12208c2ecf20Sopenharmony_ci } 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci /* check for error indications - PF_xx_AxQLEN register layout for 12238c2ecf20Sopenharmony_ci * FW/MBX/SB are identical so just use defines for PF_FW_AxQLEN. 12248c2ecf20Sopenharmony_ci */ 12258c2ecf20Sopenharmony_ci val = rd32(hw, cq->rq.len); 12268c2ecf20Sopenharmony_ci if (val & (PF_FW_ARQLEN_ARQVFE_M | PF_FW_ARQLEN_ARQOVFL_M | 12278c2ecf20Sopenharmony_ci PF_FW_ARQLEN_ARQCRIT_M)) { 12288c2ecf20Sopenharmony_ci oldval = val; 12298c2ecf20Sopenharmony_ci if (val & PF_FW_ARQLEN_ARQVFE_M) 12308c2ecf20Sopenharmony_ci dev_dbg(dev, "%s Receive Queue VF Error detected\n", 12318c2ecf20Sopenharmony_ci qtype); 12328c2ecf20Sopenharmony_ci if (val & PF_FW_ARQLEN_ARQOVFL_M) { 12338c2ecf20Sopenharmony_ci dev_dbg(dev, "%s Receive Queue Overflow Error detected\n", 12348c2ecf20Sopenharmony_ci qtype); 12358c2ecf20Sopenharmony_ci } 12368c2ecf20Sopenharmony_ci if (val & PF_FW_ARQLEN_ARQCRIT_M) 12378c2ecf20Sopenharmony_ci dev_dbg(dev, "%s Receive Queue Critical Error detected\n", 12388c2ecf20Sopenharmony_ci qtype); 12398c2ecf20Sopenharmony_ci val &= ~(PF_FW_ARQLEN_ARQVFE_M | PF_FW_ARQLEN_ARQOVFL_M | 12408c2ecf20Sopenharmony_ci PF_FW_ARQLEN_ARQCRIT_M); 12418c2ecf20Sopenharmony_ci if (oldval != val) 12428c2ecf20Sopenharmony_ci wr32(hw, cq->rq.len, val); 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci val = rd32(hw, cq->sq.len); 12468c2ecf20Sopenharmony_ci if (val & (PF_FW_ATQLEN_ATQVFE_M | PF_FW_ATQLEN_ATQOVFL_M | 12478c2ecf20Sopenharmony_ci PF_FW_ATQLEN_ATQCRIT_M)) { 12488c2ecf20Sopenharmony_ci oldval = val; 12498c2ecf20Sopenharmony_ci if (val & PF_FW_ATQLEN_ATQVFE_M) 12508c2ecf20Sopenharmony_ci dev_dbg(dev, "%s Send Queue VF Error detected\n", 12518c2ecf20Sopenharmony_ci qtype); 12528c2ecf20Sopenharmony_ci if (val & PF_FW_ATQLEN_ATQOVFL_M) { 12538c2ecf20Sopenharmony_ci dev_dbg(dev, "%s Send Queue Overflow Error detected\n", 12548c2ecf20Sopenharmony_ci qtype); 12558c2ecf20Sopenharmony_ci } 12568c2ecf20Sopenharmony_ci if (val & PF_FW_ATQLEN_ATQCRIT_M) 12578c2ecf20Sopenharmony_ci dev_dbg(dev, "%s Send Queue Critical Error detected\n", 12588c2ecf20Sopenharmony_ci qtype); 12598c2ecf20Sopenharmony_ci val &= ~(PF_FW_ATQLEN_ATQVFE_M | PF_FW_ATQLEN_ATQOVFL_M | 12608c2ecf20Sopenharmony_ci PF_FW_ATQLEN_ATQCRIT_M); 12618c2ecf20Sopenharmony_ci if (oldval != val) 12628c2ecf20Sopenharmony_ci wr32(hw, cq->sq.len, val); 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci event.buf_len = cq->rq_buf_size; 12668c2ecf20Sopenharmony_ci event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL); 12678c2ecf20Sopenharmony_ci if (!event.msg_buf) 12688c2ecf20Sopenharmony_ci return 0; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci do { 12718c2ecf20Sopenharmony_ci enum ice_status ret; 12728c2ecf20Sopenharmony_ci u16 opcode; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci ret = ice_clean_rq_elem(hw, cq, &event, &pending); 12758c2ecf20Sopenharmony_ci if (ret == ICE_ERR_AQ_NO_WORK) 12768c2ecf20Sopenharmony_ci break; 12778c2ecf20Sopenharmony_ci if (ret) { 12788c2ecf20Sopenharmony_ci dev_err(dev, "%s Receive Queue event error %s\n", qtype, 12798c2ecf20Sopenharmony_ci ice_stat_str(ret)); 12808c2ecf20Sopenharmony_ci break; 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci opcode = le16_to_cpu(event.desc.opcode); 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci /* Notify any thread that might be waiting for this event */ 12868c2ecf20Sopenharmony_ci ice_aq_check_events(pf, opcode, &event); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci switch (opcode) { 12898c2ecf20Sopenharmony_ci case ice_aqc_opc_get_link_status: 12908c2ecf20Sopenharmony_ci if (ice_handle_link_event(pf, &event)) 12918c2ecf20Sopenharmony_ci dev_err(dev, "Could not handle link event\n"); 12928c2ecf20Sopenharmony_ci break; 12938c2ecf20Sopenharmony_ci case ice_aqc_opc_event_lan_overflow: 12948c2ecf20Sopenharmony_ci ice_vf_lan_overflow_event(pf, &event); 12958c2ecf20Sopenharmony_ci break; 12968c2ecf20Sopenharmony_ci case ice_mbx_opc_send_msg_to_pf: 12978c2ecf20Sopenharmony_ci ice_vc_process_vf_msg(pf, &event); 12988c2ecf20Sopenharmony_ci break; 12998c2ecf20Sopenharmony_ci case ice_aqc_opc_fw_logging: 13008c2ecf20Sopenharmony_ci ice_output_fw_log(hw, &event.desc, event.msg_buf); 13018c2ecf20Sopenharmony_ci break; 13028c2ecf20Sopenharmony_ci case ice_aqc_opc_lldp_set_mib_change: 13038c2ecf20Sopenharmony_ci ice_dcb_process_lldp_set_mib_change(pf, &event); 13048c2ecf20Sopenharmony_ci break; 13058c2ecf20Sopenharmony_ci default: 13068c2ecf20Sopenharmony_ci dev_dbg(dev, "%s Receive Queue unknown event 0x%04x ignored\n", 13078c2ecf20Sopenharmony_ci qtype, opcode); 13088c2ecf20Sopenharmony_ci break; 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci } while (pending && (i++ < ICE_DFLT_IRQ_WORK)); 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci kfree(event.msg_buf); 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci return pending && (i == ICE_DFLT_IRQ_WORK); 13158c2ecf20Sopenharmony_ci} 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci/** 13188c2ecf20Sopenharmony_ci * ice_ctrlq_pending - check if there is a difference between ntc and ntu 13198c2ecf20Sopenharmony_ci * @hw: pointer to hardware info 13208c2ecf20Sopenharmony_ci * @cq: control queue information 13218c2ecf20Sopenharmony_ci * 13228c2ecf20Sopenharmony_ci * returns true if there are pending messages in a queue, false if there aren't 13238c2ecf20Sopenharmony_ci */ 13248c2ecf20Sopenharmony_cistatic bool ice_ctrlq_pending(struct ice_hw *hw, struct ice_ctl_q_info *cq) 13258c2ecf20Sopenharmony_ci{ 13268c2ecf20Sopenharmony_ci u16 ntu; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci ntu = (u16)(rd32(hw, cq->rq.head) & cq->rq.head_mask); 13298c2ecf20Sopenharmony_ci return cq->rq.next_to_clean != ntu; 13308c2ecf20Sopenharmony_ci} 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci/** 13338c2ecf20Sopenharmony_ci * ice_clean_adminq_subtask - clean the AdminQ rings 13348c2ecf20Sopenharmony_ci * @pf: board private structure 13358c2ecf20Sopenharmony_ci */ 13368c2ecf20Sopenharmony_cistatic void ice_clean_adminq_subtask(struct ice_pf *pf) 13378c2ecf20Sopenharmony_ci{ 13388c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci if (!test_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state)) 13418c2ecf20Sopenharmony_ci return; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci if (__ice_clean_ctrlq(pf, ICE_CTL_Q_ADMIN)) 13448c2ecf20Sopenharmony_ci return; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci clear_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state); 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci /* There might be a situation where new messages arrive to a control 13498c2ecf20Sopenharmony_ci * queue between processing the last message and clearing the 13508c2ecf20Sopenharmony_ci * EVENT_PENDING bit. So before exiting, check queue head again (using 13518c2ecf20Sopenharmony_ci * ice_ctrlq_pending) and process new messages if any. 13528c2ecf20Sopenharmony_ci */ 13538c2ecf20Sopenharmony_ci if (ice_ctrlq_pending(hw, &hw->adminq)) 13548c2ecf20Sopenharmony_ci __ice_clean_ctrlq(pf, ICE_CTL_Q_ADMIN); 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci ice_flush(hw); 13578c2ecf20Sopenharmony_ci} 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci/** 13608c2ecf20Sopenharmony_ci * ice_clean_mailboxq_subtask - clean the MailboxQ rings 13618c2ecf20Sopenharmony_ci * @pf: board private structure 13628c2ecf20Sopenharmony_ci */ 13638c2ecf20Sopenharmony_cistatic void ice_clean_mailboxq_subtask(struct ice_pf *pf) 13648c2ecf20Sopenharmony_ci{ 13658c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci if (!test_bit(__ICE_MAILBOXQ_EVENT_PENDING, pf->state)) 13688c2ecf20Sopenharmony_ci return; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci if (__ice_clean_ctrlq(pf, ICE_CTL_Q_MAILBOX)) 13718c2ecf20Sopenharmony_ci return; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci clear_bit(__ICE_MAILBOXQ_EVENT_PENDING, pf->state); 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci if (ice_ctrlq_pending(hw, &hw->mailboxq)) 13768c2ecf20Sopenharmony_ci __ice_clean_ctrlq(pf, ICE_CTL_Q_MAILBOX); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci ice_flush(hw); 13798c2ecf20Sopenharmony_ci} 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci/** 13828c2ecf20Sopenharmony_ci * ice_service_task_schedule - schedule the service task to wake up 13838c2ecf20Sopenharmony_ci * @pf: board private structure 13848c2ecf20Sopenharmony_ci * 13858c2ecf20Sopenharmony_ci * If not already scheduled, this puts the task into the work queue. 13868c2ecf20Sopenharmony_ci */ 13878c2ecf20Sopenharmony_civoid ice_service_task_schedule(struct ice_pf *pf) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci if (!test_bit(__ICE_SERVICE_DIS, pf->state) && 13908c2ecf20Sopenharmony_ci !test_and_set_bit(__ICE_SERVICE_SCHED, pf->state) && 13918c2ecf20Sopenharmony_ci !test_bit(__ICE_NEEDS_RESTART, pf->state)) 13928c2ecf20Sopenharmony_ci queue_work(ice_wq, &pf->serv_task); 13938c2ecf20Sopenharmony_ci} 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci/** 13968c2ecf20Sopenharmony_ci * ice_service_task_complete - finish up the service task 13978c2ecf20Sopenharmony_ci * @pf: board private structure 13988c2ecf20Sopenharmony_ci */ 13998c2ecf20Sopenharmony_cistatic void ice_service_task_complete(struct ice_pf *pf) 14008c2ecf20Sopenharmony_ci{ 14018c2ecf20Sopenharmony_ci WARN_ON(!test_bit(__ICE_SERVICE_SCHED, pf->state)); 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci /* force memory (pf->state) to sync before next service task */ 14048c2ecf20Sopenharmony_ci smp_mb__before_atomic(); 14058c2ecf20Sopenharmony_ci clear_bit(__ICE_SERVICE_SCHED, pf->state); 14068c2ecf20Sopenharmony_ci} 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci/** 14098c2ecf20Sopenharmony_ci * ice_service_task_stop - stop service task and cancel works 14108c2ecf20Sopenharmony_ci * @pf: board private structure 14118c2ecf20Sopenharmony_ci * 14128c2ecf20Sopenharmony_ci * Return 0 if the __ICE_SERVICE_DIS bit was not already set, 14138c2ecf20Sopenharmony_ci * 1 otherwise. 14148c2ecf20Sopenharmony_ci */ 14158c2ecf20Sopenharmony_cistatic int ice_service_task_stop(struct ice_pf *pf) 14168c2ecf20Sopenharmony_ci{ 14178c2ecf20Sopenharmony_ci int ret; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci ret = test_and_set_bit(__ICE_SERVICE_DIS, pf->state); 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci if (pf->serv_tmr.function) 14228c2ecf20Sopenharmony_ci del_timer_sync(&pf->serv_tmr); 14238c2ecf20Sopenharmony_ci if (pf->serv_task.func) 14248c2ecf20Sopenharmony_ci cancel_work_sync(&pf->serv_task); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci clear_bit(__ICE_SERVICE_SCHED, pf->state); 14278c2ecf20Sopenharmony_ci return ret; 14288c2ecf20Sopenharmony_ci} 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci/** 14318c2ecf20Sopenharmony_ci * ice_service_task_restart - restart service task and schedule works 14328c2ecf20Sopenharmony_ci * @pf: board private structure 14338c2ecf20Sopenharmony_ci * 14348c2ecf20Sopenharmony_ci * This function is needed for suspend and resume works (e.g WoL scenario) 14358c2ecf20Sopenharmony_ci */ 14368c2ecf20Sopenharmony_cistatic void ice_service_task_restart(struct ice_pf *pf) 14378c2ecf20Sopenharmony_ci{ 14388c2ecf20Sopenharmony_ci clear_bit(__ICE_SERVICE_DIS, pf->state); 14398c2ecf20Sopenharmony_ci ice_service_task_schedule(pf); 14408c2ecf20Sopenharmony_ci} 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci/** 14438c2ecf20Sopenharmony_ci * ice_service_timer - timer callback to schedule service task 14448c2ecf20Sopenharmony_ci * @t: pointer to timer_list 14458c2ecf20Sopenharmony_ci */ 14468c2ecf20Sopenharmony_cistatic void ice_service_timer(struct timer_list *t) 14478c2ecf20Sopenharmony_ci{ 14488c2ecf20Sopenharmony_ci struct ice_pf *pf = from_timer(pf, t, serv_tmr); 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci mod_timer(&pf->serv_tmr, round_jiffies(pf->serv_tmr_period + jiffies)); 14518c2ecf20Sopenharmony_ci ice_service_task_schedule(pf); 14528c2ecf20Sopenharmony_ci} 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci/** 14558c2ecf20Sopenharmony_ci * ice_handle_mdd_event - handle malicious driver detect event 14568c2ecf20Sopenharmony_ci * @pf: pointer to the PF structure 14578c2ecf20Sopenharmony_ci * 14588c2ecf20Sopenharmony_ci * Called from service task. OICR interrupt handler indicates MDD event. 14598c2ecf20Sopenharmony_ci * VF MDD logging is guarded by net_ratelimit. Additional PF and VF log 14608c2ecf20Sopenharmony_ci * messages are wrapped by netif_msg_[rx|tx]_err. Since VF Rx MDD events 14618c2ecf20Sopenharmony_ci * disable the queue, the PF can be configured to reset the VF using ethtool 14628c2ecf20Sopenharmony_ci * private flag mdd-auto-reset-vf. 14638c2ecf20Sopenharmony_ci */ 14648c2ecf20Sopenharmony_cistatic void ice_handle_mdd_event(struct ice_pf *pf) 14658c2ecf20Sopenharmony_ci{ 14668c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 14678c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 14688c2ecf20Sopenharmony_ci unsigned int i; 14698c2ecf20Sopenharmony_ci u32 reg; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci if (!test_and_clear_bit(__ICE_MDD_EVENT_PENDING, pf->state)) { 14728c2ecf20Sopenharmony_ci /* Since the VF MDD event logging is rate limited, check if 14738c2ecf20Sopenharmony_ci * there are pending MDD events. 14748c2ecf20Sopenharmony_ci */ 14758c2ecf20Sopenharmony_ci ice_print_vfs_mdd_events(pf); 14768c2ecf20Sopenharmony_ci return; 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci /* find what triggered an MDD event */ 14808c2ecf20Sopenharmony_ci reg = rd32(hw, GL_MDET_TX_PQM); 14818c2ecf20Sopenharmony_ci if (reg & GL_MDET_TX_PQM_VALID_M) { 14828c2ecf20Sopenharmony_ci u8 pf_num = (reg & GL_MDET_TX_PQM_PF_NUM_M) >> 14838c2ecf20Sopenharmony_ci GL_MDET_TX_PQM_PF_NUM_S; 14848c2ecf20Sopenharmony_ci u16 vf_num = (reg & GL_MDET_TX_PQM_VF_NUM_M) >> 14858c2ecf20Sopenharmony_ci GL_MDET_TX_PQM_VF_NUM_S; 14868c2ecf20Sopenharmony_ci u8 event = (reg & GL_MDET_TX_PQM_MAL_TYPE_M) >> 14878c2ecf20Sopenharmony_ci GL_MDET_TX_PQM_MAL_TYPE_S; 14888c2ecf20Sopenharmony_ci u16 queue = ((reg & GL_MDET_TX_PQM_QNUM_M) >> 14898c2ecf20Sopenharmony_ci GL_MDET_TX_PQM_QNUM_S); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci if (netif_msg_tx_err(pf)) 14928c2ecf20Sopenharmony_ci dev_info(dev, "Malicious Driver Detection event %d on TX queue %d PF# %d VF# %d\n", 14938c2ecf20Sopenharmony_ci event, queue, pf_num, vf_num); 14948c2ecf20Sopenharmony_ci wr32(hw, GL_MDET_TX_PQM, 0xffffffff); 14958c2ecf20Sopenharmony_ci } 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci reg = rd32(hw, GL_MDET_TX_TCLAN); 14988c2ecf20Sopenharmony_ci if (reg & GL_MDET_TX_TCLAN_VALID_M) { 14998c2ecf20Sopenharmony_ci u8 pf_num = (reg & GL_MDET_TX_TCLAN_PF_NUM_M) >> 15008c2ecf20Sopenharmony_ci GL_MDET_TX_TCLAN_PF_NUM_S; 15018c2ecf20Sopenharmony_ci u16 vf_num = (reg & GL_MDET_TX_TCLAN_VF_NUM_M) >> 15028c2ecf20Sopenharmony_ci GL_MDET_TX_TCLAN_VF_NUM_S; 15038c2ecf20Sopenharmony_ci u8 event = (reg & GL_MDET_TX_TCLAN_MAL_TYPE_M) >> 15048c2ecf20Sopenharmony_ci GL_MDET_TX_TCLAN_MAL_TYPE_S; 15058c2ecf20Sopenharmony_ci u16 queue = ((reg & GL_MDET_TX_TCLAN_QNUM_M) >> 15068c2ecf20Sopenharmony_ci GL_MDET_TX_TCLAN_QNUM_S); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci if (netif_msg_tx_err(pf)) 15098c2ecf20Sopenharmony_ci dev_info(dev, "Malicious Driver Detection event %d on TX queue %d PF# %d VF# %d\n", 15108c2ecf20Sopenharmony_ci event, queue, pf_num, vf_num); 15118c2ecf20Sopenharmony_ci wr32(hw, GL_MDET_TX_TCLAN, 0xffffffff); 15128c2ecf20Sopenharmony_ci } 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci reg = rd32(hw, GL_MDET_RX); 15158c2ecf20Sopenharmony_ci if (reg & GL_MDET_RX_VALID_M) { 15168c2ecf20Sopenharmony_ci u8 pf_num = (reg & GL_MDET_RX_PF_NUM_M) >> 15178c2ecf20Sopenharmony_ci GL_MDET_RX_PF_NUM_S; 15188c2ecf20Sopenharmony_ci u16 vf_num = (reg & GL_MDET_RX_VF_NUM_M) >> 15198c2ecf20Sopenharmony_ci GL_MDET_RX_VF_NUM_S; 15208c2ecf20Sopenharmony_ci u8 event = (reg & GL_MDET_RX_MAL_TYPE_M) >> 15218c2ecf20Sopenharmony_ci GL_MDET_RX_MAL_TYPE_S; 15228c2ecf20Sopenharmony_ci u16 queue = ((reg & GL_MDET_RX_QNUM_M) >> 15238c2ecf20Sopenharmony_ci GL_MDET_RX_QNUM_S); 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci if (netif_msg_rx_err(pf)) 15268c2ecf20Sopenharmony_ci dev_info(dev, "Malicious Driver Detection event %d on RX queue %d PF# %d VF# %d\n", 15278c2ecf20Sopenharmony_ci event, queue, pf_num, vf_num); 15288c2ecf20Sopenharmony_ci wr32(hw, GL_MDET_RX, 0xffffffff); 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci /* check to see if this PF caused an MDD event */ 15328c2ecf20Sopenharmony_ci reg = rd32(hw, PF_MDET_TX_PQM); 15338c2ecf20Sopenharmony_ci if (reg & PF_MDET_TX_PQM_VALID_M) { 15348c2ecf20Sopenharmony_ci wr32(hw, PF_MDET_TX_PQM, 0xFFFF); 15358c2ecf20Sopenharmony_ci if (netif_msg_tx_err(pf)) 15368c2ecf20Sopenharmony_ci dev_info(dev, "Malicious Driver Detection event TX_PQM detected on PF\n"); 15378c2ecf20Sopenharmony_ci } 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci reg = rd32(hw, PF_MDET_TX_TCLAN); 15408c2ecf20Sopenharmony_ci if (reg & PF_MDET_TX_TCLAN_VALID_M) { 15418c2ecf20Sopenharmony_ci wr32(hw, PF_MDET_TX_TCLAN, 0xFFFF); 15428c2ecf20Sopenharmony_ci if (netif_msg_tx_err(pf)) 15438c2ecf20Sopenharmony_ci dev_info(dev, "Malicious Driver Detection event TX_TCLAN detected on PF\n"); 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci reg = rd32(hw, PF_MDET_RX); 15478c2ecf20Sopenharmony_ci if (reg & PF_MDET_RX_VALID_M) { 15488c2ecf20Sopenharmony_ci wr32(hw, PF_MDET_RX, 0xFFFF); 15498c2ecf20Sopenharmony_ci if (netif_msg_rx_err(pf)) 15508c2ecf20Sopenharmony_ci dev_info(dev, "Malicious Driver Detection event RX detected on PF\n"); 15518c2ecf20Sopenharmony_ci } 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci /* Check to see if one of the VFs caused an MDD event, and then 15548c2ecf20Sopenharmony_ci * increment counters and set print pending 15558c2ecf20Sopenharmony_ci */ 15568c2ecf20Sopenharmony_ci ice_for_each_vf(pf, i) { 15578c2ecf20Sopenharmony_ci struct ice_vf *vf = &pf->vf[i]; 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci reg = rd32(hw, VP_MDET_TX_PQM(i)); 15608c2ecf20Sopenharmony_ci if (reg & VP_MDET_TX_PQM_VALID_M) { 15618c2ecf20Sopenharmony_ci wr32(hw, VP_MDET_TX_PQM(i), 0xFFFF); 15628c2ecf20Sopenharmony_ci vf->mdd_tx_events.count++; 15638c2ecf20Sopenharmony_ci set_bit(__ICE_MDD_VF_PRINT_PENDING, pf->state); 15648c2ecf20Sopenharmony_ci if (netif_msg_tx_err(pf)) 15658c2ecf20Sopenharmony_ci dev_info(dev, "Malicious Driver Detection event TX_PQM detected on VF %d\n", 15668c2ecf20Sopenharmony_ci i); 15678c2ecf20Sopenharmony_ci } 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci reg = rd32(hw, VP_MDET_TX_TCLAN(i)); 15708c2ecf20Sopenharmony_ci if (reg & VP_MDET_TX_TCLAN_VALID_M) { 15718c2ecf20Sopenharmony_ci wr32(hw, VP_MDET_TX_TCLAN(i), 0xFFFF); 15728c2ecf20Sopenharmony_ci vf->mdd_tx_events.count++; 15738c2ecf20Sopenharmony_ci set_bit(__ICE_MDD_VF_PRINT_PENDING, pf->state); 15748c2ecf20Sopenharmony_ci if (netif_msg_tx_err(pf)) 15758c2ecf20Sopenharmony_ci dev_info(dev, "Malicious Driver Detection event TX_TCLAN detected on VF %d\n", 15768c2ecf20Sopenharmony_ci i); 15778c2ecf20Sopenharmony_ci } 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci reg = rd32(hw, VP_MDET_TX_TDPU(i)); 15808c2ecf20Sopenharmony_ci if (reg & VP_MDET_TX_TDPU_VALID_M) { 15818c2ecf20Sopenharmony_ci wr32(hw, VP_MDET_TX_TDPU(i), 0xFFFF); 15828c2ecf20Sopenharmony_ci vf->mdd_tx_events.count++; 15838c2ecf20Sopenharmony_ci set_bit(__ICE_MDD_VF_PRINT_PENDING, pf->state); 15848c2ecf20Sopenharmony_ci if (netif_msg_tx_err(pf)) 15858c2ecf20Sopenharmony_ci dev_info(dev, "Malicious Driver Detection event TX_TDPU detected on VF %d\n", 15868c2ecf20Sopenharmony_ci i); 15878c2ecf20Sopenharmony_ci } 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci reg = rd32(hw, VP_MDET_RX(i)); 15908c2ecf20Sopenharmony_ci if (reg & VP_MDET_RX_VALID_M) { 15918c2ecf20Sopenharmony_ci wr32(hw, VP_MDET_RX(i), 0xFFFF); 15928c2ecf20Sopenharmony_ci vf->mdd_rx_events.count++; 15938c2ecf20Sopenharmony_ci set_bit(__ICE_MDD_VF_PRINT_PENDING, pf->state); 15948c2ecf20Sopenharmony_ci if (netif_msg_rx_err(pf)) 15958c2ecf20Sopenharmony_ci dev_info(dev, "Malicious Driver Detection event RX detected on VF %d\n", 15968c2ecf20Sopenharmony_ci i); 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci /* Since the queue is disabled on VF Rx MDD events, the 15998c2ecf20Sopenharmony_ci * PF can be configured to reset the VF through ethtool 16008c2ecf20Sopenharmony_ci * private flag mdd-auto-reset-vf. 16018c2ecf20Sopenharmony_ci */ 16028c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_MDD_AUTO_RESET_VF, pf->flags)) { 16038c2ecf20Sopenharmony_ci /* VF MDD event counters will be cleared by 16048c2ecf20Sopenharmony_ci * reset, so print the event prior to reset. 16058c2ecf20Sopenharmony_ci */ 16068c2ecf20Sopenharmony_ci ice_print_vf_rx_mdd_event(vf); 16078c2ecf20Sopenharmony_ci mutex_lock(&pf->vf[i].cfg_lock); 16088c2ecf20Sopenharmony_ci ice_reset_vf(&pf->vf[i], false); 16098c2ecf20Sopenharmony_ci mutex_unlock(&pf->vf[i].cfg_lock); 16108c2ecf20Sopenharmony_ci } 16118c2ecf20Sopenharmony_ci } 16128c2ecf20Sopenharmony_ci } 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci ice_print_vfs_mdd_events(pf); 16158c2ecf20Sopenharmony_ci} 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci/** 16188c2ecf20Sopenharmony_ci * ice_force_phys_link_state - Force the physical link state 16198c2ecf20Sopenharmony_ci * @vsi: VSI to force the physical link state to up/down 16208c2ecf20Sopenharmony_ci * @link_up: true/false indicates to set the physical link to up/down 16218c2ecf20Sopenharmony_ci * 16228c2ecf20Sopenharmony_ci * Force the physical link state by getting the current PHY capabilities from 16238c2ecf20Sopenharmony_ci * hardware and setting the PHY config based on the determined capabilities. If 16248c2ecf20Sopenharmony_ci * link changes a link event will be triggered because both the Enable Automatic 16258c2ecf20Sopenharmony_ci * Link Update and LESM Enable bits are set when setting the PHY capabilities. 16268c2ecf20Sopenharmony_ci * 16278c2ecf20Sopenharmony_ci * Returns 0 on success, negative on failure 16288c2ecf20Sopenharmony_ci */ 16298c2ecf20Sopenharmony_cistatic int ice_force_phys_link_state(struct ice_vsi *vsi, bool link_up) 16308c2ecf20Sopenharmony_ci{ 16318c2ecf20Sopenharmony_ci struct ice_aqc_get_phy_caps_data *pcaps; 16328c2ecf20Sopenharmony_ci struct ice_aqc_set_phy_cfg_data *cfg; 16338c2ecf20Sopenharmony_ci struct ice_port_info *pi; 16348c2ecf20Sopenharmony_ci struct device *dev; 16358c2ecf20Sopenharmony_ci int retcode; 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci if (!vsi || !vsi->port_info || !vsi->back) 16388c2ecf20Sopenharmony_ci return -EINVAL; 16398c2ecf20Sopenharmony_ci if (vsi->type != ICE_VSI_PF) 16408c2ecf20Sopenharmony_ci return 0; 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(vsi->back); 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci pi = vsi->port_info; 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL); 16478c2ecf20Sopenharmony_ci if (!pcaps) 16488c2ecf20Sopenharmony_ci return -ENOMEM; 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci retcode = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_ACTIVE_CFG, pcaps, 16518c2ecf20Sopenharmony_ci NULL); 16528c2ecf20Sopenharmony_ci if (retcode) { 16538c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get phy capabilities, VSI %d error %d\n", 16548c2ecf20Sopenharmony_ci vsi->vsi_num, retcode); 16558c2ecf20Sopenharmony_ci retcode = -EIO; 16568c2ecf20Sopenharmony_ci goto out; 16578c2ecf20Sopenharmony_ci } 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci /* No change in link */ 16608c2ecf20Sopenharmony_ci if (link_up == !!(pcaps->caps & ICE_AQC_PHY_EN_LINK) && 16618c2ecf20Sopenharmony_ci link_up == !!(pi->phy.link_info.link_info & ICE_AQ_LINK_UP)) 16628c2ecf20Sopenharmony_ci goto out; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci /* Use the current user PHY configuration. The current user PHY 16658c2ecf20Sopenharmony_ci * configuration is initialized during probe from PHY capabilities 16668c2ecf20Sopenharmony_ci * software mode, and updated on set PHY configuration. 16678c2ecf20Sopenharmony_ci */ 16688c2ecf20Sopenharmony_ci cfg = kmemdup(&pi->phy.curr_user_phy_cfg, sizeof(*cfg), GFP_KERNEL); 16698c2ecf20Sopenharmony_ci if (!cfg) { 16708c2ecf20Sopenharmony_ci retcode = -ENOMEM; 16718c2ecf20Sopenharmony_ci goto out; 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci cfg->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT; 16758c2ecf20Sopenharmony_ci if (link_up) 16768c2ecf20Sopenharmony_ci cfg->caps |= ICE_AQ_PHY_ENA_LINK; 16778c2ecf20Sopenharmony_ci else 16788c2ecf20Sopenharmony_ci cfg->caps &= ~ICE_AQ_PHY_ENA_LINK; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci retcode = ice_aq_set_phy_cfg(&vsi->back->hw, pi, cfg, NULL); 16818c2ecf20Sopenharmony_ci if (retcode) { 16828c2ecf20Sopenharmony_ci dev_err(dev, "Failed to set phy config, VSI %d error %d\n", 16838c2ecf20Sopenharmony_ci vsi->vsi_num, retcode); 16848c2ecf20Sopenharmony_ci retcode = -EIO; 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci kfree(cfg); 16888c2ecf20Sopenharmony_ciout: 16898c2ecf20Sopenharmony_ci kfree(pcaps); 16908c2ecf20Sopenharmony_ci return retcode; 16918c2ecf20Sopenharmony_ci} 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci/** 16948c2ecf20Sopenharmony_ci * ice_init_nvm_phy_type - Initialize the NVM PHY type 16958c2ecf20Sopenharmony_ci * @pi: port info structure 16968c2ecf20Sopenharmony_ci * 16978c2ecf20Sopenharmony_ci * Initialize nvm_phy_type_[low|high] for link lenient mode support 16988c2ecf20Sopenharmony_ci */ 16998c2ecf20Sopenharmony_cistatic int ice_init_nvm_phy_type(struct ice_port_info *pi) 17008c2ecf20Sopenharmony_ci{ 17018c2ecf20Sopenharmony_ci struct ice_aqc_get_phy_caps_data *pcaps; 17028c2ecf20Sopenharmony_ci struct ice_pf *pf = pi->hw->back; 17038c2ecf20Sopenharmony_ci enum ice_status status; 17048c2ecf20Sopenharmony_ci int err = 0; 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL); 17078c2ecf20Sopenharmony_ci if (!pcaps) 17088c2ecf20Sopenharmony_ci return -ENOMEM; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP_NO_MEDIA, pcaps, 17118c2ecf20Sopenharmony_ci NULL); 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci if (status) { 17148c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(pf), "Get PHY capability failed.\n"); 17158c2ecf20Sopenharmony_ci err = -EIO; 17168c2ecf20Sopenharmony_ci goto out; 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci pf->nvm_phy_type_hi = pcaps->phy_type_high; 17208c2ecf20Sopenharmony_ci pf->nvm_phy_type_lo = pcaps->phy_type_low; 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ciout: 17238c2ecf20Sopenharmony_ci kfree(pcaps); 17248c2ecf20Sopenharmony_ci return err; 17258c2ecf20Sopenharmony_ci} 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci/** 17288c2ecf20Sopenharmony_ci * ice_init_link_dflt_override - Initialize link default override 17298c2ecf20Sopenharmony_ci * @pi: port info structure 17308c2ecf20Sopenharmony_ci * 17318c2ecf20Sopenharmony_ci * Initialize link default override and PHY total port shutdown during probe 17328c2ecf20Sopenharmony_ci */ 17338c2ecf20Sopenharmony_cistatic void ice_init_link_dflt_override(struct ice_port_info *pi) 17348c2ecf20Sopenharmony_ci{ 17358c2ecf20Sopenharmony_ci struct ice_link_default_override_tlv *ldo; 17368c2ecf20Sopenharmony_ci struct ice_pf *pf = pi->hw->back; 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci ldo = &pf->link_dflt_override; 17398c2ecf20Sopenharmony_ci if (ice_get_link_default_override(ldo, pi)) 17408c2ecf20Sopenharmony_ci return; 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci if (!(ldo->options & ICE_LINK_OVERRIDE_PORT_DIS)) 17438c2ecf20Sopenharmony_ci return; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci /* Enable Total Port Shutdown (override/replace link-down-on-close 17468c2ecf20Sopenharmony_ci * ethtool private flag) for ports with Port Disable bit set. 17478c2ecf20Sopenharmony_ci */ 17488c2ecf20Sopenharmony_ci set_bit(ICE_FLAG_TOTAL_PORT_SHUTDOWN_ENA, pf->flags); 17498c2ecf20Sopenharmony_ci set_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags); 17508c2ecf20Sopenharmony_ci} 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci/** 17538c2ecf20Sopenharmony_ci * ice_init_phy_cfg_dflt_override - Initialize PHY cfg default override settings 17548c2ecf20Sopenharmony_ci * @pi: port info structure 17558c2ecf20Sopenharmony_ci * 17568c2ecf20Sopenharmony_ci * If default override is enabled, initialized the user PHY cfg speed and FEC 17578c2ecf20Sopenharmony_ci * settings using the default override mask from the NVM. 17588c2ecf20Sopenharmony_ci * 17598c2ecf20Sopenharmony_ci * The PHY should only be configured with the default override settings the 17608c2ecf20Sopenharmony_ci * first time media is available. The __ICE_LINK_DEFAULT_OVERRIDE_PENDING state 17618c2ecf20Sopenharmony_ci * is used to indicate that the user PHY cfg default override is initialized 17628c2ecf20Sopenharmony_ci * and the PHY has not been configured with the default override settings. The 17638c2ecf20Sopenharmony_ci * state is set here, and cleared in ice_configure_phy the first time the PHY is 17648c2ecf20Sopenharmony_ci * configured. 17658c2ecf20Sopenharmony_ci */ 17668c2ecf20Sopenharmony_cistatic void ice_init_phy_cfg_dflt_override(struct ice_port_info *pi) 17678c2ecf20Sopenharmony_ci{ 17688c2ecf20Sopenharmony_ci struct ice_link_default_override_tlv *ldo; 17698c2ecf20Sopenharmony_ci struct ice_aqc_set_phy_cfg_data *cfg; 17708c2ecf20Sopenharmony_ci struct ice_phy_info *phy = &pi->phy; 17718c2ecf20Sopenharmony_ci struct ice_pf *pf = pi->hw->back; 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci ldo = &pf->link_dflt_override; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci /* If link default override is enabled, use to mask NVM PHY capabilities 17768c2ecf20Sopenharmony_ci * for speed and FEC default configuration. 17778c2ecf20Sopenharmony_ci */ 17788c2ecf20Sopenharmony_ci cfg = &phy->curr_user_phy_cfg; 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci if (ldo->phy_type_low || ldo->phy_type_high) { 17818c2ecf20Sopenharmony_ci cfg->phy_type_low = pf->nvm_phy_type_lo & 17828c2ecf20Sopenharmony_ci cpu_to_le64(ldo->phy_type_low); 17838c2ecf20Sopenharmony_ci cfg->phy_type_high = pf->nvm_phy_type_hi & 17848c2ecf20Sopenharmony_ci cpu_to_le64(ldo->phy_type_high); 17858c2ecf20Sopenharmony_ci } 17868c2ecf20Sopenharmony_ci cfg->link_fec_opt = ldo->fec_options; 17878c2ecf20Sopenharmony_ci phy->curr_user_fec_req = ICE_FEC_AUTO; 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci set_bit(__ICE_LINK_DEFAULT_OVERRIDE_PENDING, pf->state); 17908c2ecf20Sopenharmony_ci} 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci/** 17938c2ecf20Sopenharmony_ci * ice_init_phy_user_cfg - Initialize the PHY user configuration 17948c2ecf20Sopenharmony_ci * @pi: port info structure 17958c2ecf20Sopenharmony_ci * 17968c2ecf20Sopenharmony_ci * Initialize the current user PHY configuration, speed, FEC, and FC requested 17978c2ecf20Sopenharmony_ci * mode to default. The PHY defaults are from get PHY capabilities topology 17988c2ecf20Sopenharmony_ci * with media so call when media is first available. An error is returned if 17998c2ecf20Sopenharmony_ci * called when media is not available. The PHY initialization completed state is 18008c2ecf20Sopenharmony_ci * set here. 18018c2ecf20Sopenharmony_ci * 18028c2ecf20Sopenharmony_ci * These configurations are used when setting PHY 18038c2ecf20Sopenharmony_ci * configuration. The user PHY configuration is updated on set PHY 18048c2ecf20Sopenharmony_ci * configuration. Returns 0 on success, negative on failure 18058c2ecf20Sopenharmony_ci */ 18068c2ecf20Sopenharmony_cistatic int ice_init_phy_user_cfg(struct ice_port_info *pi) 18078c2ecf20Sopenharmony_ci{ 18088c2ecf20Sopenharmony_ci struct ice_aqc_get_phy_caps_data *pcaps; 18098c2ecf20Sopenharmony_ci struct ice_phy_info *phy = &pi->phy; 18108c2ecf20Sopenharmony_ci struct ice_pf *pf = pi->hw->back; 18118c2ecf20Sopenharmony_ci enum ice_status status; 18128c2ecf20Sopenharmony_ci struct ice_vsi *vsi; 18138c2ecf20Sopenharmony_ci int err = 0; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci if (!(phy->link_info.link_info & ICE_AQ_MEDIA_AVAILABLE)) 18168c2ecf20Sopenharmony_ci return -EIO; 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci vsi = ice_get_main_vsi(pf); 18198c2ecf20Sopenharmony_ci if (!vsi) 18208c2ecf20Sopenharmony_ci return -EINVAL; 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL); 18238c2ecf20Sopenharmony_ci if (!pcaps) 18248c2ecf20Sopenharmony_ci return -ENOMEM; 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP_MEDIA, pcaps, 18278c2ecf20Sopenharmony_ci NULL); 18288c2ecf20Sopenharmony_ci if (status) { 18298c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(pf), "Get PHY capability failed.\n"); 18308c2ecf20Sopenharmony_ci err = -EIO; 18318c2ecf20Sopenharmony_ci goto err_out; 18328c2ecf20Sopenharmony_ci } 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci ice_copy_phy_caps_to_cfg(pi, pcaps, &pi->phy.curr_user_phy_cfg); 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci /* check if lenient mode is supported and enabled */ 18378c2ecf20Sopenharmony_ci if (ice_fw_supports_link_override(&vsi->back->hw) && 18388c2ecf20Sopenharmony_ci !(pcaps->module_compliance_enforcement & 18398c2ecf20Sopenharmony_ci ICE_AQC_MOD_ENFORCE_STRICT_MODE)) { 18408c2ecf20Sopenharmony_ci set_bit(ICE_FLAG_LINK_LENIENT_MODE_ENA, pf->flags); 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci /* if link default override is enabled, initialize user PHY 18438c2ecf20Sopenharmony_ci * configuration with link default override values 18448c2ecf20Sopenharmony_ci */ 18458c2ecf20Sopenharmony_ci if (pf->link_dflt_override.options & ICE_LINK_OVERRIDE_EN) { 18468c2ecf20Sopenharmony_ci ice_init_phy_cfg_dflt_override(pi); 18478c2ecf20Sopenharmony_ci goto out; 18488c2ecf20Sopenharmony_ci } 18498c2ecf20Sopenharmony_ci } 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ci /* if link default override is not enabled, initialize PHY using 18528c2ecf20Sopenharmony_ci * topology with media 18538c2ecf20Sopenharmony_ci */ 18548c2ecf20Sopenharmony_ci phy->curr_user_fec_req = ice_caps_to_fec_mode(pcaps->caps, 18558c2ecf20Sopenharmony_ci pcaps->link_fec_options); 18568c2ecf20Sopenharmony_ci phy->curr_user_fc_req = ice_caps_to_fc_mode(pcaps->caps); 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ciout: 18598c2ecf20Sopenharmony_ci phy->curr_user_speed_req = ICE_AQ_LINK_SPEED_M; 18608c2ecf20Sopenharmony_ci set_bit(__ICE_PHY_INIT_COMPLETE, pf->state); 18618c2ecf20Sopenharmony_cierr_out: 18628c2ecf20Sopenharmony_ci kfree(pcaps); 18638c2ecf20Sopenharmony_ci return err; 18648c2ecf20Sopenharmony_ci} 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci/** 18678c2ecf20Sopenharmony_ci * ice_configure_phy - configure PHY 18688c2ecf20Sopenharmony_ci * @vsi: VSI of PHY 18698c2ecf20Sopenharmony_ci * 18708c2ecf20Sopenharmony_ci * Set the PHY configuration. If the current PHY configuration is the same as 18718c2ecf20Sopenharmony_ci * the curr_user_phy_cfg, then do nothing to avoid link flap. Otherwise 18728c2ecf20Sopenharmony_ci * configure the based get PHY capabilities for topology with media. 18738c2ecf20Sopenharmony_ci */ 18748c2ecf20Sopenharmony_cistatic int ice_configure_phy(struct ice_vsi *vsi) 18758c2ecf20Sopenharmony_ci{ 18768c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(vsi->back); 18778c2ecf20Sopenharmony_ci struct ice_aqc_get_phy_caps_data *pcaps; 18788c2ecf20Sopenharmony_ci struct ice_aqc_set_phy_cfg_data *cfg; 18798c2ecf20Sopenharmony_ci struct ice_port_info *pi; 18808c2ecf20Sopenharmony_ci enum ice_status status; 18818c2ecf20Sopenharmony_ci int err = 0; 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci pi = vsi->port_info; 18848c2ecf20Sopenharmony_ci if (!pi) 18858c2ecf20Sopenharmony_ci return -EINVAL; 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci /* Ensure we have media as we cannot configure a medialess port */ 18888c2ecf20Sopenharmony_ci if (!(pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE)) 18898c2ecf20Sopenharmony_ci return -EPERM; 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci ice_print_topo_conflict(vsi); 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci if (vsi->port_info->phy.link_info.topo_media_conflict == 18948c2ecf20Sopenharmony_ci ICE_AQ_LINK_TOPO_UNSUPP_MEDIA) 18958c2ecf20Sopenharmony_ci return -EPERM; 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags)) 18988c2ecf20Sopenharmony_ci return ice_force_phys_link_state(vsi, true); 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci pcaps = kzalloc(sizeof(*pcaps), GFP_KERNEL); 19018c2ecf20Sopenharmony_ci if (!pcaps) 19028c2ecf20Sopenharmony_ci return -ENOMEM; 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci /* Get current PHY config */ 19058c2ecf20Sopenharmony_ci status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_ACTIVE_CFG, pcaps, 19068c2ecf20Sopenharmony_ci NULL); 19078c2ecf20Sopenharmony_ci if (status) { 19088c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get PHY configuration, VSI %d error %s\n", 19098c2ecf20Sopenharmony_ci vsi->vsi_num, ice_stat_str(status)); 19108c2ecf20Sopenharmony_ci err = -EIO; 19118c2ecf20Sopenharmony_ci goto done; 19128c2ecf20Sopenharmony_ci } 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci /* If PHY enable link is configured and configuration has not changed, 19158c2ecf20Sopenharmony_ci * there's nothing to do 19168c2ecf20Sopenharmony_ci */ 19178c2ecf20Sopenharmony_ci if (pcaps->caps & ICE_AQC_PHY_EN_LINK && 19188c2ecf20Sopenharmony_ci ice_phy_caps_equals_cfg(pcaps, &pi->phy.curr_user_phy_cfg)) 19198c2ecf20Sopenharmony_ci goto done; 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci /* Use PHY topology as baseline for configuration */ 19228c2ecf20Sopenharmony_ci memset(pcaps, 0, sizeof(*pcaps)); 19238c2ecf20Sopenharmony_ci status = ice_aq_get_phy_caps(pi, false, ICE_AQC_REPORT_TOPO_CAP_MEDIA, pcaps, 19248c2ecf20Sopenharmony_ci NULL); 19258c2ecf20Sopenharmony_ci if (status) { 19268c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get PHY topology, VSI %d error %s\n", 19278c2ecf20Sopenharmony_ci vsi->vsi_num, ice_stat_str(status)); 19288c2ecf20Sopenharmony_ci err = -EIO; 19298c2ecf20Sopenharmony_ci goto done; 19308c2ecf20Sopenharmony_ci } 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); 19338c2ecf20Sopenharmony_ci if (!cfg) { 19348c2ecf20Sopenharmony_ci err = -ENOMEM; 19358c2ecf20Sopenharmony_ci goto done; 19368c2ecf20Sopenharmony_ci } 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci ice_copy_phy_caps_to_cfg(pi, pcaps, cfg); 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci /* Speed - If default override pending, use curr_user_phy_cfg set in 19418c2ecf20Sopenharmony_ci * ice_init_phy_user_cfg_ldo. 19428c2ecf20Sopenharmony_ci */ 19438c2ecf20Sopenharmony_ci if (test_and_clear_bit(__ICE_LINK_DEFAULT_OVERRIDE_PENDING, 19448c2ecf20Sopenharmony_ci vsi->back->state)) { 19458c2ecf20Sopenharmony_ci cfg->phy_type_low = pi->phy.curr_user_phy_cfg.phy_type_low; 19468c2ecf20Sopenharmony_ci cfg->phy_type_high = pi->phy.curr_user_phy_cfg.phy_type_high; 19478c2ecf20Sopenharmony_ci } else { 19488c2ecf20Sopenharmony_ci u64 phy_low = 0, phy_high = 0; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci ice_update_phy_type(&phy_low, &phy_high, 19518c2ecf20Sopenharmony_ci pi->phy.curr_user_speed_req); 19528c2ecf20Sopenharmony_ci cfg->phy_type_low = pcaps->phy_type_low & cpu_to_le64(phy_low); 19538c2ecf20Sopenharmony_ci cfg->phy_type_high = pcaps->phy_type_high & 19548c2ecf20Sopenharmony_ci cpu_to_le64(phy_high); 19558c2ecf20Sopenharmony_ci } 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci /* Can't provide what was requested; use PHY capabilities */ 19588c2ecf20Sopenharmony_ci if (!cfg->phy_type_low && !cfg->phy_type_high) { 19598c2ecf20Sopenharmony_ci cfg->phy_type_low = pcaps->phy_type_low; 19608c2ecf20Sopenharmony_ci cfg->phy_type_high = pcaps->phy_type_high; 19618c2ecf20Sopenharmony_ci } 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci /* FEC */ 19648c2ecf20Sopenharmony_ci ice_cfg_phy_fec(pi, cfg, pi->phy.curr_user_fec_req); 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci /* Can't provide what was requested; use PHY capabilities */ 19678c2ecf20Sopenharmony_ci if (cfg->link_fec_opt != 19688c2ecf20Sopenharmony_ci (cfg->link_fec_opt & pcaps->link_fec_options)) { 19698c2ecf20Sopenharmony_ci cfg->caps |= pcaps->caps & ICE_AQC_PHY_EN_AUTO_FEC; 19708c2ecf20Sopenharmony_ci cfg->link_fec_opt = pcaps->link_fec_options; 19718c2ecf20Sopenharmony_ci } 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci /* Flow Control - always supported; no need to check against 19748c2ecf20Sopenharmony_ci * capabilities 19758c2ecf20Sopenharmony_ci */ 19768c2ecf20Sopenharmony_ci ice_cfg_phy_fc(pi, cfg, pi->phy.curr_user_fc_req); 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci /* Enable link and link update */ 19798c2ecf20Sopenharmony_ci cfg->caps |= ICE_AQ_PHY_ENA_AUTO_LINK_UPDT | ICE_AQ_PHY_ENA_LINK; 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci status = ice_aq_set_phy_cfg(&vsi->back->hw, pi, cfg, NULL); 19828c2ecf20Sopenharmony_ci if (status) { 19838c2ecf20Sopenharmony_ci dev_err(dev, "Failed to set phy config, VSI %d error %s\n", 19848c2ecf20Sopenharmony_ci vsi->vsi_num, ice_stat_str(status)); 19858c2ecf20Sopenharmony_ci err = -EIO; 19868c2ecf20Sopenharmony_ci } 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci kfree(cfg); 19898c2ecf20Sopenharmony_cidone: 19908c2ecf20Sopenharmony_ci kfree(pcaps); 19918c2ecf20Sopenharmony_ci return err; 19928c2ecf20Sopenharmony_ci} 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci/** 19958c2ecf20Sopenharmony_ci * ice_check_media_subtask - Check for media 19968c2ecf20Sopenharmony_ci * @pf: pointer to PF struct 19978c2ecf20Sopenharmony_ci * 19988c2ecf20Sopenharmony_ci * If media is available, then initialize PHY user configuration if it is not 19998c2ecf20Sopenharmony_ci * been, and configure the PHY if the interface is up. 20008c2ecf20Sopenharmony_ci */ 20018c2ecf20Sopenharmony_cistatic void ice_check_media_subtask(struct ice_pf *pf) 20028c2ecf20Sopenharmony_ci{ 20038c2ecf20Sopenharmony_ci struct ice_port_info *pi; 20048c2ecf20Sopenharmony_ci struct ice_vsi *vsi; 20058c2ecf20Sopenharmony_ci int err; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci /* No need to check for media if it's already present */ 20088c2ecf20Sopenharmony_ci if (!test_bit(ICE_FLAG_NO_MEDIA, pf->flags)) 20098c2ecf20Sopenharmony_ci return; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci vsi = ice_get_main_vsi(pf); 20128c2ecf20Sopenharmony_ci if (!vsi) 20138c2ecf20Sopenharmony_ci return; 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci /* Refresh link info and check if media is present */ 20168c2ecf20Sopenharmony_ci pi = vsi->port_info; 20178c2ecf20Sopenharmony_ci err = ice_update_link_info(pi); 20188c2ecf20Sopenharmony_ci if (err) 20198c2ecf20Sopenharmony_ci return; 20208c2ecf20Sopenharmony_ci 20218c2ecf20Sopenharmony_ci if (pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE) { 20228c2ecf20Sopenharmony_ci if (!test_bit(__ICE_PHY_INIT_COMPLETE, pf->state)) 20238c2ecf20Sopenharmony_ci ice_init_phy_user_cfg(pi); 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci /* PHY settings are reset on media insertion, reconfigure 20268c2ecf20Sopenharmony_ci * PHY to preserve settings. 20278c2ecf20Sopenharmony_ci */ 20288c2ecf20Sopenharmony_ci if (test_bit(__ICE_DOWN, vsi->state) && 20298c2ecf20Sopenharmony_ci test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags)) 20308c2ecf20Sopenharmony_ci return; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci err = ice_configure_phy(vsi); 20338c2ecf20Sopenharmony_ci if (!err) 20348c2ecf20Sopenharmony_ci clear_bit(ICE_FLAG_NO_MEDIA, pf->flags); 20358c2ecf20Sopenharmony_ci 20368c2ecf20Sopenharmony_ci /* A Link Status Event will be generated; the event handler 20378c2ecf20Sopenharmony_ci * will complete bringing the interface up 20388c2ecf20Sopenharmony_ci */ 20398c2ecf20Sopenharmony_ci } 20408c2ecf20Sopenharmony_ci} 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci/** 20438c2ecf20Sopenharmony_ci * ice_service_task - manage and run subtasks 20448c2ecf20Sopenharmony_ci * @work: pointer to work_struct contained by the PF struct 20458c2ecf20Sopenharmony_ci */ 20468c2ecf20Sopenharmony_cistatic void ice_service_task(struct work_struct *work) 20478c2ecf20Sopenharmony_ci{ 20488c2ecf20Sopenharmony_ci struct ice_pf *pf = container_of(work, struct ice_pf, serv_task); 20498c2ecf20Sopenharmony_ci unsigned long start_time = jiffies; 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci /* subtasks */ 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci /* process reset requests first */ 20548c2ecf20Sopenharmony_ci ice_reset_subtask(pf); 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_ci /* bail if a reset/recovery cycle is pending or rebuild failed */ 20578c2ecf20Sopenharmony_ci if (ice_is_reset_in_progress(pf->state) || 20588c2ecf20Sopenharmony_ci test_bit(__ICE_SUSPENDED, pf->state) || 20598c2ecf20Sopenharmony_ci test_bit(__ICE_NEEDS_RESTART, pf->state)) { 20608c2ecf20Sopenharmony_ci ice_service_task_complete(pf); 20618c2ecf20Sopenharmony_ci return; 20628c2ecf20Sopenharmony_ci } 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci ice_clean_adminq_subtask(pf); 20658c2ecf20Sopenharmony_ci ice_check_media_subtask(pf); 20668c2ecf20Sopenharmony_ci ice_check_for_hang_subtask(pf); 20678c2ecf20Sopenharmony_ci ice_sync_fltr_subtask(pf); 20688c2ecf20Sopenharmony_ci ice_handle_mdd_event(pf); 20698c2ecf20Sopenharmony_ci ice_watchdog_subtask(pf); 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci if (ice_is_safe_mode(pf)) { 20728c2ecf20Sopenharmony_ci ice_service_task_complete(pf); 20738c2ecf20Sopenharmony_ci return; 20748c2ecf20Sopenharmony_ci } 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci ice_process_vflr_event(pf); 20778c2ecf20Sopenharmony_ci ice_clean_mailboxq_subtask(pf); 20788c2ecf20Sopenharmony_ci ice_sync_arfs_fltrs(pf); 20798c2ecf20Sopenharmony_ci /* Clear __ICE_SERVICE_SCHED flag to allow scheduling next event */ 20808c2ecf20Sopenharmony_ci ice_service_task_complete(pf); 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci /* If the tasks have taken longer than one service timer period 20838c2ecf20Sopenharmony_ci * or there is more work to be done, reset the service timer to 20848c2ecf20Sopenharmony_ci * schedule the service task now. 20858c2ecf20Sopenharmony_ci */ 20868c2ecf20Sopenharmony_ci if (time_after(jiffies, (start_time + pf->serv_tmr_period)) || 20878c2ecf20Sopenharmony_ci test_bit(__ICE_MDD_EVENT_PENDING, pf->state) || 20888c2ecf20Sopenharmony_ci test_bit(__ICE_VFLR_EVENT_PENDING, pf->state) || 20898c2ecf20Sopenharmony_ci test_bit(__ICE_MAILBOXQ_EVENT_PENDING, pf->state) || 20908c2ecf20Sopenharmony_ci test_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state)) 20918c2ecf20Sopenharmony_ci mod_timer(&pf->serv_tmr, jiffies); 20928c2ecf20Sopenharmony_ci} 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci/** 20958c2ecf20Sopenharmony_ci * ice_set_ctrlq_len - helper function to set controlq length 20968c2ecf20Sopenharmony_ci * @hw: pointer to the HW instance 20978c2ecf20Sopenharmony_ci */ 20988c2ecf20Sopenharmony_cistatic void ice_set_ctrlq_len(struct ice_hw *hw) 20998c2ecf20Sopenharmony_ci{ 21008c2ecf20Sopenharmony_ci hw->adminq.num_rq_entries = ICE_AQ_LEN; 21018c2ecf20Sopenharmony_ci hw->adminq.num_sq_entries = ICE_AQ_LEN; 21028c2ecf20Sopenharmony_ci hw->adminq.rq_buf_size = ICE_AQ_MAX_BUF_LEN; 21038c2ecf20Sopenharmony_ci hw->adminq.sq_buf_size = ICE_AQ_MAX_BUF_LEN; 21048c2ecf20Sopenharmony_ci hw->mailboxq.num_rq_entries = PF_MBX_ARQLEN_ARQLEN_M; 21058c2ecf20Sopenharmony_ci hw->mailboxq.num_sq_entries = ICE_MBXSQ_LEN; 21068c2ecf20Sopenharmony_ci hw->mailboxq.rq_buf_size = ICE_MBXQ_MAX_BUF_LEN; 21078c2ecf20Sopenharmony_ci hw->mailboxq.sq_buf_size = ICE_MBXQ_MAX_BUF_LEN; 21088c2ecf20Sopenharmony_ci} 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci/** 21118c2ecf20Sopenharmony_ci * ice_schedule_reset - schedule a reset 21128c2ecf20Sopenharmony_ci * @pf: board private structure 21138c2ecf20Sopenharmony_ci * @reset: reset being requested 21148c2ecf20Sopenharmony_ci */ 21158c2ecf20Sopenharmony_ciint ice_schedule_reset(struct ice_pf *pf, enum ice_reset_req reset) 21168c2ecf20Sopenharmony_ci{ 21178c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci /* bail out if earlier reset has failed */ 21208c2ecf20Sopenharmony_ci if (test_bit(__ICE_RESET_FAILED, pf->state)) { 21218c2ecf20Sopenharmony_ci dev_dbg(dev, "earlier reset has failed\n"); 21228c2ecf20Sopenharmony_ci return -EIO; 21238c2ecf20Sopenharmony_ci } 21248c2ecf20Sopenharmony_ci /* bail if reset/recovery already in progress */ 21258c2ecf20Sopenharmony_ci if (ice_is_reset_in_progress(pf->state)) { 21268c2ecf20Sopenharmony_ci dev_dbg(dev, "Reset already in progress\n"); 21278c2ecf20Sopenharmony_ci return -EBUSY; 21288c2ecf20Sopenharmony_ci } 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci switch (reset) { 21318c2ecf20Sopenharmony_ci case ICE_RESET_PFR: 21328c2ecf20Sopenharmony_ci set_bit(__ICE_PFR_REQ, pf->state); 21338c2ecf20Sopenharmony_ci break; 21348c2ecf20Sopenharmony_ci case ICE_RESET_CORER: 21358c2ecf20Sopenharmony_ci set_bit(__ICE_CORER_REQ, pf->state); 21368c2ecf20Sopenharmony_ci break; 21378c2ecf20Sopenharmony_ci case ICE_RESET_GLOBR: 21388c2ecf20Sopenharmony_ci set_bit(__ICE_GLOBR_REQ, pf->state); 21398c2ecf20Sopenharmony_ci break; 21408c2ecf20Sopenharmony_ci default: 21418c2ecf20Sopenharmony_ci return -EINVAL; 21428c2ecf20Sopenharmony_ci } 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci ice_service_task_schedule(pf); 21458c2ecf20Sopenharmony_ci return 0; 21468c2ecf20Sopenharmony_ci} 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci/** 21498c2ecf20Sopenharmony_ci * ice_irq_affinity_notify - Callback for affinity changes 21508c2ecf20Sopenharmony_ci * @notify: context as to what irq was changed 21518c2ecf20Sopenharmony_ci * @mask: the new affinity mask 21528c2ecf20Sopenharmony_ci * 21538c2ecf20Sopenharmony_ci * This is a callback function used by the irq_set_affinity_notifier function 21548c2ecf20Sopenharmony_ci * so that we may register to receive changes to the irq affinity masks. 21558c2ecf20Sopenharmony_ci */ 21568c2ecf20Sopenharmony_cistatic void 21578c2ecf20Sopenharmony_ciice_irq_affinity_notify(struct irq_affinity_notify *notify, 21588c2ecf20Sopenharmony_ci const cpumask_t *mask) 21598c2ecf20Sopenharmony_ci{ 21608c2ecf20Sopenharmony_ci struct ice_q_vector *q_vector = 21618c2ecf20Sopenharmony_ci container_of(notify, struct ice_q_vector, affinity_notify); 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_ci cpumask_copy(&q_vector->affinity_mask, mask); 21648c2ecf20Sopenharmony_ci} 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci/** 21678c2ecf20Sopenharmony_ci * ice_irq_affinity_release - Callback for affinity notifier release 21688c2ecf20Sopenharmony_ci * @ref: internal core kernel usage 21698c2ecf20Sopenharmony_ci * 21708c2ecf20Sopenharmony_ci * This is a callback function used by the irq_set_affinity_notifier function 21718c2ecf20Sopenharmony_ci * to inform the current notification subscriber that they will no longer 21728c2ecf20Sopenharmony_ci * receive notifications. 21738c2ecf20Sopenharmony_ci */ 21748c2ecf20Sopenharmony_cistatic void ice_irq_affinity_release(struct kref __always_unused *ref) {} 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci/** 21778c2ecf20Sopenharmony_ci * ice_vsi_ena_irq - Enable IRQ for the given VSI 21788c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 21798c2ecf20Sopenharmony_ci */ 21808c2ecf20Sopenharmony_cistatic int ice_vsi_ena_irq(struct ice_vsi *vsi) 21818c2ecf20Sopenharmony_ci{ 21828c2ecf20Sopenharmony_ci struct ice_hw *hw = &vsi->back->hw; 21838c2ecf20Sopenharmony_ci int i; 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci ice_for_each_q_vector(vsi, i) 21868c2ecf20Sopenharmony_ci ice_irq_dynamic_ena(hw, vsi, vsi->q_vectors[i]); 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci ice_flush(hw); 21898c2ecf20Sopenharmony_ci return 0; 21908c2ecf20Sopenharmony_ci} 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci/** 21938c2ecf20Sopenharmony_ci * ice_vsi_req_irq_msix - get MSI-X vectors from the OS for the VSI 21948c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 21958c2ecf20Sopenharmony_ci * @basename: name for the vector 21968c2ecf20Sopenharmony_ci */ 21978c2ecf20Sopenharmony_cistatic int ice_vsi_req_irq_msix(struct ice_vsi *vsi, char *basename) 21988c2ecf20Sopenharmony_ci{ 21998c2ecf20Sopenharmony_ci int q_vectors = vsi->num_q_vectors; 22008c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 22018c2ecf20Sopenharmony_ci int base = vsi->base_vector; 22028c2ecf20Sopenharmony_ci struct device *dev; 22038c2ecf20Sopenharmony_ci int rx_int_idx = 0; 22048c2ecf20Sopenharmony_ci int tx_int_idx = 0; 22058c2ecf20Sopenharmony_ci int vector, err; 22068c2ecf20Sopenharmony_ci int irq_num; 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 22098c2ecf20Sopenharmony_ci for (vector = 0; vector < q_vectors; vector++) { 22108c2ecf20Sopenharmony_ci struct ice_q_vector *q_vector = vsi->q_vectors[vector]; 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci irq_num = pf->msix_entries[base + vector].vector; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci if (q_vector->tx.ring && q_vector->rx.ring) { 22158c2ecf20Sopenharmony_ci snprintf(q_vector->name, sizeof(q_vector->name) - 1, 22168c2ecf20Sopenharmony_ci "%s-%s-%d", basename, "TxRx", rx_int_idx++); 22178c2ecf20Sopenharmony_ci tx_int_idx++; 22188c2ecf20Sopenharmony_ci } else if (q_vector->rx.ring) { 22198c2ecf20Sopenharmony_ci snprintf(q_vector->name, sizeof(q_vector->name) - 1, 22208c2ecf20Sopenharmony_ci "%s-%s-%d", basename, "rx", rx_int_idx++); 22218c2ecf20Sopenharmony_ci } else if (q_vector->tx.ring) { 22228c2ecf20Sopenharmony_ci snprintf(q_vector->name, sizeof(q_vector->name) - 1, 22238c2ecf20Sopenharmony_ci "%s-%s-%d", basename, "tx", tx_int_idx++); 22248c2ecf20Sopenharmony_ci } else { 22258c2ecf20Sopenharmony_ci /* skip this unused q_vector */ 22268c2ecf20Sopenharmony_ci continue; 22278c2ecf20Sopenharmony_ci } 22288c2ecf20Sopenharmony_ci err = devm_request_irq(dev, irq_num, vsi->irq_handler, 0, 22298c2ecf20Sopenharmony_ci q_vector->name, q_vector); 22308c2ecf20Sopenharmony_ci if (err) { 22318c2ecf20Sopenharmony_ci netdev_err(vsi->netdev, "MSIX request_irq failed, error: %d\n", 22328c2ecf20Sopenharmony_ci err); 22338c2ecf20Sopenharmony_ci goto free_q_irqs; 22348c2ecf20Sopenharmony_ci } 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci /* register for affinity change notifications */ 22378c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_RFS_ACCEL)) { 22388c2ecf20Sopenharmony_ci struct irq_affinity_notify *affinity_notify; 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci affinity_notify = &q_vector->affinity_notify; 22418c2ecf20Sopenharmony_ci affinity_notify->notify = ice_irq_affinity_notify; 22428c2ecf20Sopenharmony_ci affinity_notify->release = ice_irq_affinity_release; 22438c2ecf20Sopenharmony_ci irq_set_affinity_notifier(irq_num, affinity_notify); 22448c2ecf20Sopenharmony_ci } 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci /* assign the mask for this irq */ 22478c2ecf20Sopenharmony_ci irq_set_affinity_hint(irq_num, &q_vector->affinity_mask); 22488c2ecf20Sopenharmony_ci } 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci vsi->irqs_ready = true; 22518c2ecf20Sopenharmony_ci return 0; 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_cifree_q_irqs: 22548c2ecf20Sopenharmony_ci while (vector) { 22558c2ecf20Sopenharmony_ci vector--; 22568c2ecf20Sopenharmony_ci irq_num = pf->msix_entries[base + vector].vector; 22578c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_RFS_ACCEL)) 22588c2ecf20Sopenharmony_ci irq_set_affinity_notifier(irq_num, NULL); 22598c2ecf20Sopenharmony_ci irq_set_affinity_hint(irq_num, NULL); 22608c2ecf20Sopenharmony_ci devm_free_irq(dev, irq_num, &vsi->q_vectors[vector]); 22618c2ecf20Sopenharmony_ci } 22628c2ecf20Sopenharmony_ci return err; 22638c2ecf20Sopenharmony_ci} 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci/** 22668c2ecf20Sopenharmony_ci * ice_xdp_alloc_setup_rings - Allocate and setup Tx rings for XDP 22678c2ecf20Sopenharmony_ci * @vsi: VSI to setup Tx rings used by XDP 22688c2ecf20Sopenharmony_ci * 22698c2ecf20Sopenharmony_ci * Return 0 on success and negative value on error 22708c2ecf20Sopenharmony_ci */ 22718c2ecf20Sopenharmony_cistatic int ice_xdp_alloc_setup_rings(struct ice_vsi *vsi) 22728c2ecf20Sopenharmony_ci{ 22738c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(vsi->back); 22748c2ecf20Sopenharmony_ci int i; 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci for (i = 0; i < vsi->num_xdp_txq; i++) { 22778c2ecf20Sopenharmony_ci u16 xdp_q_idx = vsi->alloc_txq + i; 22788c2ecf20Sopenharmony_ci struct ice_ring *xdp_ring; 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci xdp_ring = kzalloc(sizeof(*xdp_ring), GFP_KERNEL); 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci if (!xdp_ring) 22838c2ecf20Sopenharmony_ci goto free_xdp_rings; 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_ci xdp_ring->q_index = xdp_q_idx; 22868c2ecf20Sopenharmony_ci xdp_ring->reg_idx = vsi->txq_map[xdp_q_idx]; 22878c2ecf20Sopenharmony_ci xdp_ring->ring_active = false; 22888c2ecf20Sopenharmony_ci xdp_ring->vsi = vsi; 22898c2ecf20Sopenharmony_ci xdp_ring->netdev = NULL; 22908c2ecf20Sopenharmony_ci xdp_ring->dev = dev; 22918c2ecf20Sopenharmony_ci xdp_ring->count = vsi->num_tx_desc; 22928c2ecf20Sopenharmony_ci WRITE_ONCE(vsi->xdp_rings[i], xdp_ring); 22938c2ecf20Sopenharmony_ci if (ice_setup_tx_ring(xdp_ring)) 22948c2ecf20Sopenharmony_ci goto free_xdp_rings; 22958c2ecf20Sopenharmony_ci ice_set_ring_xdp(xdp_ring); 22968c2ecf20Sopenharmony_ci xdp_ring->xsk_pool = ice_xsk_pool(xdp_ring); 22978c2ecf20Sopenharmony_ci } 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci return 0; 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_cifree_xdp_rings: 23028c2ecf20Sopenharmony_ci for (; i >= 0; i--) 23038c2ecf20Sopenharmony_ci if (vsi->xdp_rings[i] && vsi->xdp_rings[i]->desc) 23048c2ecf20Sopenharmony_ci ice_free_tx_ring(vsi->xdp_rings[i]); 23058c2ecf20Sopenharmony_ci return -ENOMEM; 23068c2ecf20Sopenharmony_ci} 23078c2ecf20Sopenharmony_ci 23088c2ecf20Sopenharmony_ci/** 23098c2ecf20Sopenharmony_ci * ice_vsi_assign_bpf_prog - set or clear bpf prog pointer on VSI 23108c2ecf20Sopenharmony_ci * @vsi: VSI to set the bpf prog on 23118c2ecf20Sopenharmony_ci * @prog: the bpf prog pointer 23128c2ecf20Sopenharmony_ci */ 23138c2ecf20Sopenharmony_cistatic void ice_vsi_assign_bpf_prog(struct ice_vsi *vsi, struct bpf_prog *prog) 23148c2ecf20Sopenharmony_ci{ 23158c2ecf20Sopenharmony_ci struct bpf_prog *old_prog; 23168c2ecf20Sopenharmony_ci int i; 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci old_prog = xchg(&vsi->xdp_prog, prog); 23198c2ecf20Sopenharmony_ci if (old_prog) 23208c2ecf20Sopenharmony_ci bpf_prog_put(old_prog); 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci ice_for_each_rxq(vsi, i) 23238c2ecf20Sopenharmony_ci WRITE_ONCE(vsi->rx_rings[i]->xdp_prog, vsi->xdp_prog); 23248c2ecf20Sopenharmony_ci} 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci/** 23278c2ecf20Sopenharmony_ci * ice_prepare_xdp_rings - Allocate, configure and setup Tx rings for XDP 23288c2ecf20Sopenharmony_ci * @vsi: VSI to bring up Tx rings used by XDP 23298c2ecf20Sopenharmony_ci * @prog: bpf program that will be assigned to VSI 23308c2ecf20Sopenharmony_ci * 23318c2ecf20Sopenharmony_ci * Return 0 on success and negative value on error 23328c2ecf20Sopenharmony_ci */ 23338c2ecf20Sopenharmony_ciint ice_prepare_xdp_rings(struct ice_vsi *vsi, struct bpf_prog *prog) 23348c2ecf20Sopenharmony_ci{ 23358c2ecf20Sopenharmony_ci u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; 23368c2ecf20Sopenharmony_ci int xdp_rings_rem = vsi->num_xdp_txq; 23378c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 23388c2ecf20Sopenharmony_ci struct ice_qs_cfg xdp_qs_cfg = { 23398c2ecf20Sopenharmony_ci .qs_mutex = &pf->avail_q_mutex, 23408c2ecf20Sopenharmony_ci .pf_map = pf->avail_txqs, 23418c2ecf20Sopenharmony_ci .pf_map_size = pf->max_pf_txqs, 23428c2ecf20Sopenharmony_ci .q_count = vsi->num_xdp_txq, 23438c2ecf20Sopenharmony_ci .scatter_count = ICE_MAX_SCATTER_TXQS, 23448c2ecf20Sopenharmony_ci .vsi_map = vsi->txq_map, 23458c2ecf20Sopenharmony_ci .vsi_map_offset = vsi->alloc_txq, 23468c2ecf20Sopenharmony_ci .mapping_mode = ICE_VSI_MAP_CONTIG 23478c2ecf20Sopenharmony_ci }; 23488c2ecf20Sopenharmony_ci enum ice_status status; 23498c2ecf20Sopenharmony_ci struct device *dev; 23508c2ecf20Sopenharmony_ci int i, v_idx; 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 23538c2ecf20Sopenharmony_ci vsi->xdp_rings = devm_kcalloc(dev, vsi->num_xdp_txq, 23548c2ecf20Sopenharmony_ci sizeof(*vsi->xdp_rings), GFP_KERNEL); 23558c2ecf20Sopenharmony_ci if (!vsi->xdp_rings) 23568c2ecf20Sopenharmony_ci return -ENOMEM; 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci vsi->xdp_mapping_mode = xdp_qs_cfg.mapping_mode; 23598c2ecf20Sopenharmony_ci if (__ice_vsi_get_qs(&xdp_qs_cfg)) 23608c2ecf20Sopenharmony_ci goto err_map_xdp; 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci if (ice_xdp_alloc_setup_rings(vsi)) 23638c2ecf20Sopenharmony_ci goto clear_xdp_rings; 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci /* follow the logic from ice_vsi_map_rings_to_vectors */ 23668c2ecf20Sopenharmony_ci ice_for_each_q_vector(vsi, v_idx) { 23678c2ecf20Sopenharmony_ci struct ice_q_vector *q_vector = vsi->q_vectors[v_idx]; 23688c2ecf20Sopenharmony_ci int xdp_rings_per_v, q_id, q_base; 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_ci xdp_rings_per_v = DIV_ROUND_UP(xdp_rings_rem, 23718c2ecf20Sopenharmony_ci vsi->num_q_vectors - v_idx); 23728c2ecf20Sopenharmony_ci q_base = vsi->num_xdp_txq - xdp_rings_rem; 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci for (q_id = q_base; q_id < (q_base + xdp_rings_per_v); q_id++) { 23758c2ecf20Sopenharmony_ci struct ice_ring *xdp_ring = vsi->xdp_rings[q_id]; 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci xdp_ring->q_vector = q_vector; 23788c2ecf20Sopenharmony_ci xdp_ring->next = q_vector->tx.ring; 23798c2ecf20Sopenharmony_ci q_vector->tx.ring = xdp_ring; 23808c2ecf20Sopenharmony_ci } 23818c2ecf20Sopenharmony_ci xdp_rings_rem -= xdp_rings_per_v; 23828c2ecf20Sopenharmony_ci } 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ci /* omit the scheduler update if in reset path; XDP queues will be 23858c2ecf20Sopenharmony_ci * taken into account at the end of ice_vsi_rebuild, where 23868c2ecf20Sopenharmony_ci * ice_cfg_vsi_lan is being called 23878c2ecf20Sopenharmony_ci */ 23888c2ecf20Sopenharmony_ci if (ice_is_reset_in_progress(pf->state)) 23898c2ecf20Sopenharmony_ci return 0; 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci /* tell the Tx scheduler that right now we have 23928c2ecf20Sopenharmony_ci * additional queues 23938c2ecf20Sopenharmony_ci */ 23948c2ecf20Sopenharmony_ci for (i = 0; i < vsi->tc_cfg.numtc; i++) 23958c2ecf20Sopenharmony_ci max_txqs[i] = vsi->num_txq + vsi->num_xdp_txq; 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci status = ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc, 23988c2ecf20Sopenharmony_ci max_txqs); 23998c2ecf20Sopenharmony_ci if (status) { 24008c2ecf20Sopenharmony_ci dev_err(dev, "Failed VSI LAN queue config for XDP, error: %s\n", 24018c2ecf20Sopenharmony_ci ice_stat_str(status)); 24028c2ecf20Sopenharmony_ci goto clear_xdp_rings; 24038c2ecf20Sopenharmony_ci } 24048c2ecf20Sopenharmony_ci 24058c2ecf20Sopenharmony_ci /* assign the prog only when it's not already present on VSI; 24068c2ecf20Sopenharmony_ci * this flow is a subject of both ethtool -L and ndo_bpf flows; 24078c2ecf20Sopenharmony_ci * VSI rebuild that happens under ethtool -L can expose us to 24088c2ecf20Sopenharmony_ci * the bpf_prog refcount issues as we would be swapping same 24098c2ecf20Sopenharmony_ci * bpf_prog pointers from vsi->xdp_prog and calling bpf_prog_put 24108c2ecf20Sopenharmony_ci * on it as it would be treated as an 'old_prog'; for ndo_bpf 24118c2ecf20Sopenharmony_ci * this is not harmful as dev_xdp_install bumps the refcount 24128c2ecf20Sopenharmony_ci * before calling the op exposed by the driver; 24138c2ecf20Sopenharmony_ci */ 24148c2ecf20Sopenharmony_ci if (!ice_is_xdp_ena_vsi(vsi)) 24158c2ecf20Sopenharmony_ci ice_vsi_assign_bpf_prog(vsi, prog); 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci return 0; 24188c2ecf20Sopenharmony_ciclear_xdp_rings: 24198c2ecf20Sopenharmony_ci for (i = 0; i < vsi->num_xdp_txq; i++) 24208c2ecf20Sopenharmony_ci if (vsi->xdp_rings[i]) { 24218c2ecf20Sopenharmony_ci kfree_rcu(vsi->xdp_rings[i], rcu); 24228c2ecf20Sopenharmony_ci vsi->xdp_rings[i] = NULL; 24238c2ecf20Sopenharmony_ci } 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_cierr_map_xdp: 24268c2ecf20Sopenharmony_ci mutex_lock(&pf->avail_q_mutex); 24278c2ecf20Sopenharmony_ci for (i = 0; i < vsi->num_xdp_txq; i++) { 24288c2ecf20Sopenharmony_ci clear_bit(vsi->txq_map[i + vsi->alloc_txq], pf->avail_txqs); 24298c2ecf20Sopenharmony_ci vsi->txq_map[i + vsi->alloc_txq] = ICE_INVAL_Q_INDEX; 24308c2ecf20Sopenharmony_ci } 24318c2ecf20Sopenharmony_ci mutex_unlock(&pf->avail_q_mutex); 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci devm_kfree(dev, vsi->xdp_rings); 24348c2ecf20Sopenharmony_ci return -ENOMEM; 24358c2ecf20Sopenharmony_ci} 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci/** 24388c2ecf20Sopenharmony_ci * ice_destroy_xdp_rings - undo the configuration made by ice_prepare_xdp_rings 24398c2ecf20Sopenharmony_ci * @vsi: VSI to remove XDP rings 24408c2ecf20Sopenharmony_ci * 24418c2ecf20Sopenharmony_ci * Detach XDP rings from irq vectors, clean up the PF bitmap and free 24428c2ecf20Sopenharmony_ci * resources 24438c2ecf20Sopenharmony_ci */ 24448c2ecf20Sopenharmony_ciint ice_destroy_xdp_rings(struct ice_vsi *vsi) 24458c2ecf20Sopenharmony_ci{ 24468c2ecf20Sopenharmony_ci u16 max_txqs[ICE_MAX_TRAFFIC_CLASS] = { 0 }; 24478c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 24488c2ecf20Sopenharmony_ci int i, v_idx; 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci /* q_vectors are freed in reset path so there's no point in detaching 24518c2ecf20Sopenharmony_ci * rings; in case of rebuild being triggered not from reset bits 24528c2ecf20Sopenharmony_ci * in pf->state won't be set, so additionally check first q_vector 24538c2ecf20Sopenharmony_ci * against NULL 24548c2ecf20Sopenharmony_ci */ 24558c2ecf20Sopenharmony_ci if (ice_is_reset_in_progress(pf->state) || !vsi->q_vectors[0]) 24568c2ecf20Sopenharmony_ci goto free_qmap; 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_ci ice_for_each_q_vector(vsi, v_idx) { 24598c2ecf20Sopenharmony_ci struct ice_q_vector *q_vector = vsi->q_vectors[v_idx]; 24608c2ecf20Sopenharmony_ci struct ice_ring *ring; 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci ice_for_each_ring(ring, q_vector->tx) 24638c2ecf20Sopenharmony_ci if (!ring->tx_buf || !ice_ring_is_xdp(ring)) 24648c2ecf20Sopenharmony_ci break; 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci /* restore the value of last node prior to XDP setup */ 24678c2ecf20Sopenharmony_ci q_vector->tx.ring = ring; 24688c2ecf20Sopenharmony_ci } 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_cifree_qmap: 24718c2ecf20Sopenharmony_ci mutex_lock(&pf->avail_q_mutex); 24728c2ecf20Sopenharmony_ci for (i = 0; i < vsi->num_xdp_txq; i++) { 24738c2ecf20Sopenharmony_ci clear_bit(vsi->txq_map[i + vsi->alloc_txq], pf->avail_txqs); 24748c2ecf20Sopenharmony_ci vsi->txq_map[i + vsi->alloc_txq] = ICE_INVAL_Q_INDEX; 24758c2ecf20Sopenharmony_ci } 24768c2ecf20Sopenharmony_ci mutex_unlock(&pf->avail_q_mutex); 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci for (i = 0; i < vsi->num_xdp_txq; i++) 24798c2ecf20Sopenharmony_ci if (vsi->xdp_rings[i]) { 24808c2ecf20Sopenharmony_ci if (vsi->xdp_rings[i]->desc) { 24818c2ecf20Sopenharmony_ci synchronize_rcu(); 24828c2ecf20Sopenharmony_ci ice_free_tx_ring(vsi->xdp_rings[i]); 24838c2ecf20Sopenharmony_ci } 24848c2ecf20Sopenharmony_ci kfree_rcu(vsi->xdp_rings[i], rcu); 24858c2ecf20Sopenharmony_ci vsi->xdp_rings[i] = NULL; 24868c2ecf20Sopenharmony_ci } 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_ci devm_kfree(ice_pf_to_dev(pf), vsi->xdp_rings); 24898c2ecf20Sopenharmony_ci vsi->xdp_rings = NULL; 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci if (ice_is_reset_in_progress(pf->state) || !vsi->q_vectors[0]) 24928c2ecf20Sopenharmony_ci return 0; 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci ice_vsi_assign_bpf_prog(vsi, NULL); 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci /* notify Tx scheduler that we destroyed XDP queues and bring 24978c2ecf20Sopenharmony_ci * back the old number of child nodes 24988c2ecf20Sopenharmony_ci */ 24998c2ecf20Sopenharmony_ci for (i = 0; i < vsi->tc_cfg.numtc; i++) 25008c2ecf20Sopenharmony_ci max_txqs[i] = vsi->num_txq; 25018c2ecf20Sopenharmony_ci 25028c2ecf20Sopenharmony_ci /* change number of XDP Tx queues to 0 */ 25038c2ecf20Sopenharmony_ci vsi->num_xdp_txq = 0; 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci return ice_cfg_vsi_lan(vsi->port_info, vsi->idx, vsi->tc_cfg.ena_tc, 25068c2ecf20Sopenharmony_ci max_txqs); 25078c2ecf20Sopenharmony_ci} 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_ci/** 25108c2ecf20Sopenharmony_ci * ice_xdp_setup_prog - Add or remove XDP eBPF program 25118c2ecf20Sopenharmony_ci * @vsi: VSI to setup XDP for 25128c2ecf20Sopenharmony_ci * @prog: XDP program 25138c2ecf20Sopenharmony_ci * @extack: netlink extended ack 25148c2ecf20Sopenharmony_ci */ 25158c2ecf20Sopenharmony_cistatic int 25168c2ecf20Sopenharmony_ciice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog, 25178c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 25188c2ecf20Sopenharmony_ci{ 25198c2ecf20Sopenharmony_ci int frame_size = vsi->netdev->mtu + ICE_ETH_PKT_HDR_PAD; 25208c2ecf20Sopenharmony_ci bool if_running = netif_running(vsi->netdev); 25218c2ecf20Sopenharmony_ci int ret = 0, xdp_ring_err = 0; 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_ci if (frame_size > vsi->rx_buf_len) { 25248c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "MTU too large for loading XDP"); 25258c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 25268c2ecf20Sopenharmony_ci } 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci /* need to stop netdev while setting up the program for Rx rings */ 25298c2ecf20Sopenharmony_ci if (if_running && !test_and_set_bit(__ICE_DOWN, vsi->state)) { 25308c2ecf20Sopenharmony_ci ret = ice_down(vsi); 25318c2ecf20Sopenharmony_ci if (ret) { 25328c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Preparing device for XDP attach failed"); 25338c2ecf20Sopenharmony_ci return ret; 25348c2ecf20Sopenharmony_ci } 25358c2ecf20Sopenharmony_ci } 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_ci if (!ice_is_xdp_ena_vsi(vsi) && prog) { 25388c2ecf20Sopenharmony_ci vsi->num_xdp_txq = vsi->alloc_rxq; 25398c2ecf20Sopenharmony_ci xdp_ring_err = ice_prepare_xdp_rings(vsi, prog); 25408c2ecf20Sopenharmony_ci if (xdp_ring_err) 25418c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Setting up XDP Tx resources failed"); 25428c2ecf20Sopenharmony_ci } else if (ice_is_xdp_ena_vsi(vsi) && !prog) { 25438c2ecf20Sopenharmony_ci xdp_ring_err = ice_destroy_xdp_rings(vsi); 25448c2ecf20Sopenharmony_ci if (xdp_ring_err) 25458c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Freeing XDP Tx resources failed"); 25468c2ecf20Sopenharmony_ci } else { 25478c2ecf20Sopenharmony_ci /* safe to call even when prog == vsi->xdp_prog as 25488c2ecf20Sopenharmony_ci * dev_xdp_install in net/core/dev.c incremented prog's 25498c2ecf20Sopenharmony_ci * refcount so corresponding bpf_prog_put won't cause 25508c2ecf20Sopenharmony_ci * underflow 25518c2ecf20Sopenharmony_ci */ 25528c2ecf20Sopenharmony_ci ice_vsi_assign_bpf_prog(vsi, prog); 25538c2ecf20Sopenharmony_ci } 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci if (if_running) 25568c2ecf20Sopenharmony_ci ret = ice_up(vsi); 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci if (!ret && prog && vsi->xsk_pools) { 25598c2ecf20Sopenharmony_ci int i; 25608c2ecf20Sopenharmony_ci 25618c2ecf20Sopenharmony_ci ice_for_each_rxq(vsi, i) { 25628c2ecf20Sopenharmony_ci struct ice_ring *rx_ring = vsi->rx_rings[i]; 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci if (rx_ring->xsk_pool) 25658c2ecf20Sopenharmony_ci napi_schedule(&rx_ring->q_vector->napi); 25668c2ecf20Sopenharmony_ci } 25678c2ecf20Sopenharmony_ci } 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_ci return (ret || xdp_ring_err) ? -ENOMEM : 0; 25708c2ecf20Sopenharmony_ci} 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci/** 25738c2ecf20Sopenharmony_ci * ice_xdp_safe_mode - XDP handler for safe mode 25748c2ecf20Sopenharmony_ci * @dev: netdevice 25758c2ecf20Sopenharmony_ci * @xdp: XDP command 25768c2ecf20Sopenharmony_ci */ 25778c2ecf20Sopenharmony_cistatic int ice_xdp_safe_mode(struct net_device __always_unused *dev, 25788c2ecf20Sopenharmony_ci struct netdev_bpf *xdp) 25798c2ecf20Sopenharmony_ci{ 25808c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(xdp->extack, 25818c2ecf20Sopenharmony_ci "Please provide working DDP firmware package in order to use XDP\n" 25828c2ecf20Sopenharmony_ci "Refer to Documentation/networking/device_drivers/ethernet/intel/ice.rst"); 25838c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 25848c2ecf20Sopenharmony_ci} 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_ci/** 25878c2ecf20Sopenharmony_ci * ice_xdp - implements XDP handler 25888c2ecf20Sopenharmony_ci * @dev: netdevice 25898c2ecf20Sopenharmony_ci * @xdp: XDP command 25908c2ecf20Sopenharmony_ci */ 25918c2ecf20Sopenharmony_cistatic int ice_xdp(struct net_device *dev, struct netdev_bpf *xdp) 25928c2ecf20Sopenharmony_ci{ 25938c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(dev); 25948c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_ci if (vsi->type != ICE_VSI_PF) { 25978c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(xdp->extack, "XDP can be loaded only on PF VSI"); 25988c2ecf20Sopenharmony_ci return -EINVAL; 25998c2ecf20Sopenharmony_ci } 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_ci switch (xdp->command) { 26028c2ecf20Sopenharmony_ci case XDP_SETUP_PROG: 26038c2ecf20Sopenharmony_ci return ice_xdp_setup_prog(vsi, xdp->prog, xdp->extack); 26048c2ecf20Sopenharmony_ci case XDP_SETUP_XSK_POOL: 26058c2ecf20Sopenharmony_ci return ice_xsk_pool_setup(vsi, xdp->xsk.pool, 26068c2ecf20Sopenharmony_ci xdp->xsk.queue_id); 26078c2ecf20Sopenharmony_ci default: 26088c2ecf20Sopenharmony_ci return -EINVAL; 26098c2ecf20Sopenharmony_ci } 26108c2ecf20Sopenharmony_ci} 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci/** 26138c2ecf20Sopenharmony_ci * ice_ena_misc_vector - enable the non-queue interrupts 26148c2ecf20Sopenharmony_ci * @pf: board private structure 26158c2ecf20Sopenharmony_ci */ 26168c2ecf20Sopenharmony_cistatic void ice_ena_misc_vector(struct ice_pf *pf) 26178c2ecf20Sopenharmony_ci{ 26188c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 26198c2ecf20Sopenharmony_ci u32 val; 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci /* Disable anti-spoof detection interrupt to prevent spurious event 26228c2ecf20Sopenharmony_ci * interrupts during a function reset. Anti-spoof functionally is 26238c2ecf20Sopenharmony_ci * still supported. 26248c2ecf20Sopenharmony_ci */ 26258c2ecf20Sopenharmony_ci val = rd32(hw, GL_MDCK_TX_TDPU); 26268c2ecf20Sopenharmony_ci val |= GL_MDCK_TX_TDPU_RCU_ANTISPOOF_ITR_DIS_M; 26278c2ecf20Sopenharmony_ci wr32(hw, GL_MDCK_TX_TDPU, val); 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci /* clear things first */ 26308c2ecf20Sopenharmony_ci wr32(hw, PFINT_OICR_ENA, 0); /* disable all */ 26318c2ecf20Sopenharmony_ci rd32(hw, PFINT_OICR); /* read to clear */ 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci val = (PFINT_OICR_ECC_ERR_M | 26348c2ecf20Sopenharmony_ci PFINT_OICR_MAL_DETECT_M | 26358c2ecf20Sopenharmony_ci PFINT_OICR_GRST_M | 26368c2ecf20Sopenharmony_ci PFINT_OICR_PCI_EXCEPTION_M | 26378c2ecf20Sopenharmony_ci PFINT_OICR_VFLR_M | 26388c2ecf20Sopenharmony_ci PFINT_OICR_HMC_ERR_M | 26398c2ecf20Sopenharmony_ci PFINT_OICR_PE_CRITERR_M); 26408c2ecf20Sopenharmony_ci 26418c2ecf20Sopenharmony_ci wr32(hw, PFINT_OICR_ENA, val); 26428c2ecf20Sopenharmony_ci 26438c2ecf20Sopenharmony_ci /* SW_ITR_IDX = 0, but don't change INTENA */ 26448c2ecf20Sopenharmony_ci wr32(hw, GLINT_DYN_CTL(pf->oicr_idx), 26458c2ecf20Sopenharmony_ci GLINT_DYN_CTL_SW_ITR_INDX_M | GLINT_DYN_CTL_INTENA_MSK_M); 26468c2ecf20Sopenharmony_ci} 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci/** 26498c2ecf20Sopenharmony_ci * ice_misc_intr - misc interrupt handler 26508c2ecf20Sopenharmony_ci * @irq: interrupt number 26518c2ecf20Sopenharmony_ci * @data: pointer to a q_vector 26528c2ecf20Sopenharmony_ci */ 26538c2ecf20Sopenharmony_cistatic irqreturn_t ice_misc_intr(int __always_unused irq, void *data) 26548c2ecf20Sopenharmony_ci{ 26558c2ecf20Sopenharmony_ci struct ice_pf *pf = (struct ice_pf *)data; 26568c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 26578c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 26588c2ecf20Sopenharmony_ci struct device *dev; 26598c2ecf20Sopenharmony_ci u32 oicr, ena_mask; 26608c2ecf20Sopenharmony_ci 26618c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 26628c2ecf20Sopenharmony_ci set_bit(__ICE_ADMINQ_EVENT_PENDING, pf->state); 26638c2ecf20Sopenharmony_ci set_bit(__ICE_MAILBOXQ_EVENT_PENDING, pf->state); 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci oicr = rd32(hw, PFINT_OICR); 26668c2ecf20Sopenharmony_ci ena_mask = rd32(hw, PFINT_OICR_ENA); 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci if (oicr & PFINT_OICR_SWINT_M) { 26698c2ecf20Sopenharmony_ci ena_mask &= ~PFINT_OICR_SWINT_M; 26708c2ecf20Sopenharmony_ci pf->sw_int_count++; 26718c2ecf20Sopenharmony_ci } 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci if (oicr & PFINT_OICR_MAL_DETECT_M) { 26748c2ecf20Sopenharmony_ci ena_mask &= ~PFINT_OICR_MAL_DETECT_M; 26758c2ecf20Sopenharmony_ci set_bit(__ICE_MDD_EVENT_PENDING, pf->state); 26768c2ecf20Sopenharmony_ci } 26778c2ecf20Sopenharmony_ci if (oicr & PFINT_OICR_VFLR_M) { 26788c2ecf20Sopenharmony_ci /* disable any further VFLR event notifications */ 26798c2ecf20Sopenharmony_ci if (test_bit(__ICE_VF_RESETS_DISABLED, pf->state)) { 26808c2ecf20Sopenharmony_ci u32 reg = rd32(hw, PFINT_OICR_ENA); 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci reg &= ~PFINT_OICR_VFLR_M; 26838c2ecf20Sopenharmony_ci wr32(hw, PFINT_OICR_ENA, reg); 26848c2ecf20Sopenharmony_ci } else { 26858c2ecf20Sopenharmony_ci ena_mask &= ~PFINT_OICR_VFLR_M; 26868c2ecf20Sopenharmony_ci set_bit(__ICE_VFLR_EVENT_PENDING, pf->state); 26878c2ecf20Sopenharmony_ci } 26888c2ecf20Sopenharmony_ci } 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci if (oicr & PFINT_OICR_GRST_M) { 26918c2ecf20Sopenharmony_ci u32 reset; 26928c2ecf20Sopenharmony_ci 26938c2ecf20Sopenharmony_ci /* we have a reset warning */ 26948c2ecf20Sopenharmony_ci ena_mask &= ~PFINT_OICR_GRST_M; 26958c2ecf20Sopenharmony_ci reset = (rd32(hw, GLGEN_RSTAT) & GLGEN_RSTAT_RESET_TYPE_M) >> 26968c2ecf20Sopenharmony_ci GLGEN_RSTAT_RESET_TYPE_S; 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_ci if (reset == ICE_RESET_CORER) 26998c2ecf20Sopenharmony_ci pf->corer_count++; 27008c2ecf20Sopenharmony_ci else if (reset == ICE_RESET_GLOBR) 27018c2ecf20Sopenharmony_ci pf->globr_count++; 27028c2ecf20Sopenharmony_ci else if (reset == ICE_RESET_EMPR) 27038c2ecf20Sopenharmony_ci pf->empr_count++; 27048c2ecf20Sopenharmony_ci else 27058c2ecf20Sopenharmony_ci dev_dbg(dev, "Invalid reset type %d\n", reset); 27068c2ecf20Sopenharmony_ci 27078c2ecf20Sopenharmony_ci /* If a reset cycle isn't already in progress, we set a bit in 27088c2ecf20Sopenharmony_ci * pf->state so that the service task can start a reset/rebuild. 27098c2ecf20Sopenharmony_ci * We also make note of which reset happened so that peer 27108c2ecf20Sopenharmony_ci * devices/drivers can be informed. 27118c2ecf20Sopenharmony_ci */ 27128c2ecf20Sopenharmony_ci if (!test_and_set_bit(__ICE_RESET_OICR_RECV, pf->state)) { 27138c2ecf20Sopenharmony_ci if (reset == ICE_RESET_CORER) 27148c2ecf20Sopenharmony_ci set_bit(__ICE_CORER_RECV, pf->state); 27158c2ecf20Sopenharmony_ci else if (reset == ICE_RESET_GLOBR) 27168c2ecf20Sopenharmony_ci set_bit(__ICE_GLOBR_RECV, pf->state); 27178c2ecf20Sopenharmony_ci else 27188c2ecf20Sopenharmony_ci set_bit(__ICE_EMPR_RECV, pf->state); 27198c2ecf20Sopenharmony_ci 27208c2ecf20Sopenharmony_ci /* There are couple of different bits at play here. 27218c2ecf20Sopenharmony_ci * hw->reset_ongoing indicates whether the hardware is 27228c2ecf20Sopenharmony_ci * in reset. This is set to true when a reset interrupt 27238c2ecf20Sopenharmony_ci * is received and set back to false after the driver 27248c2ecf20Sopenharmony_ci * has determined that the hardware is out of reset. 27258c2ecf20Sopenharmony_ci * 27268c2ecf20Sopenharmony_ci * __ICE_RESET_OICR_RECV in pf->state indicates 27278c2ecf20Sopenharmony_ci * that a post reset rebuild is required before the 27288c2ecf20Sopenharmony_ci * driver is operational again. This is set above. 27298c2ecf20Sopenharmony_ci * 27308c2ecf20Sopenharmony_ci * As this is the start of the reset/rebuild cycle, set 27318c2ecf20Sopenharmony_ci * both to indicate that. 27328c2ecf20Sopenharmony_ci */ 27338c2ecf20Sopenharmony_ci hw->reset_ongoing = true; 27348c2ecf20Sopenharmony_ci } 27358c2ecf20Sopenharmony_ci } 27368c2ecf20Sopenharmony_ci 27378c2ecf20Sopenharmony_ci if (oicr & PFINT_OICR_HMC_ERR_M) { 27388c2ecf20Sopenharmony_ci ena_mask &= ~PFINT_OICR_HMC_ERR_M; 27398c2ecf20Sopenharmony_ci dev_dbg(dev, "HMC Error interrupt - info 0x%x, data 0x%x\n", 27408c2ecf20Sopenharmony_ci rd32(hw, PFHMC_ERRORINFO), 27418c2ecf20Sopenharmony_ci rd32(hw, PFHMC_ERRORDATA)); 27428c2ecf20Sopenharmony_ci } 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci /* Report any remaining unexpected interrupts */ 27458c2ecf20Sopenharmony_ci oicr &= ena_mask; 27468c2ecf20Sopenharmony_ci if (oicr) { 27478c2ecf20Sopenharmony_ci dev_dbg(dev, "unhandled interrupt oicr=0x%08x\n", oicr); 27488c2ecf20Sopenharmony_ci /* If a critical error is pending there is no choice but to 27498c2ecf20Sopenharmony_ci * reset the device. 27508c2ecf20Sopenharmony_ci */ 27518c2ecf20Sopenharmony_ci if (oicr & (PFINT_OICR_PE_CRITERR_M | 27528c2ecf20Sopenharmony_ci PFINT_OICR_PCI_EXCEPTION_M | 27538c2ecf20Sopenharmony_ci PFINT_OICR_ECC_ERR_M)) { 27548c2ecf20Sopenharmony_ci set_bit(__ICE_PFR_REQ, pf->state); 27558c2ecf20Sopenharmony_ci ice_service_task_schedule(pf); 27568c2ecf20Sopenharmony_ci } 27578c2ecf20Sopenharmony_ci } 27588c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci ice_service_task_schedule(pf); 27618c2ecf20Sopenharmony_ci ice_irq_dynamic_ena(hw, NULL, NULL); 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci return ret; 27648c2ecf20Sopenharmony_ci} 27658c2ecf20Sopenharmony_ci 27668c2ecf20Sopenharmony_ci/** 27678c2ecf20Sopenharmony_ci * ice_dis_ctrlq_interrupts - disable control queue interrupts 27688c2ecf20Sopenharmony_ci * @hw: pointer to HW structure 27698c2ecf20Sopenharmony_ci */ 27708c2ecf20Sopenharmony_cistatic void ice_dis_ctrlq_interrupts(struct ice_hw *hw) 27718c2ecf20Sopenharmony_ci{ 27728c2ecf20Sopenharmony_ci /* disable Admin queue Interrupt causes */ 27738c2ecf20Sopenharmony_ci wr32(hw, PFINT_FW_CTL, 27748c2ecf20Sopenharmony_ci rd32(hw, PFINT_FW_CTL) & ~PFINT_FW_CTL_CAUSE_ENA_M); 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci /* disable Mailbox queue Interrupt causes */ 27778c2ecf20Sopenharmony_ci wr32(hw, PFINT_MBX_CTL, 27788c2ecf20Sopenharmony_ci rd32(hw, PFINT_MBX_CTL) & ~PFINT_MBX_CTL_CAUSE_ENA_M); 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_ci /* disable Control queue Interrupt causes */ 27818c2ecf20Sopenharmony_ci wr32(hw, PFINT_OICR_CTL, 27828c2ecf20Sopenharmony_ci rd32(hw, PFINT_OICR_CTL) & ~PFINT_OICR_CTL_CAUSE_ENA_M); 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci ice_flush(hw); 27858c2ecf20Sopenharmony_ci} 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ci/** 27888c2ecf20Sopenharmony_ci * ice_free_irq_msix_misc - Unroll misc vector setup 27898c2ecf20Sopenharmony_ci * @pf: board private structure 27908c2ecf20Sopenharmony_ci */ 27918c2ecf20Sopenharmony_cistatic void ice_free_irq_msix_misc(struct ice_pf *pf) 27928c2ecf20Sopenharmony_ci{ 27938c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci ice_dis_ctrlq_interrupts(hw); 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci /* disable OICR interrupt */ 27988c2ecf20Sopenharmony_ci wr32(hw, PFINT_OICR_ENA, 0); 27998c2ecf20Sopenharmony_ci ice_flush(hw); 28008c2ecf20Sopenharmony_ci 28018c2ecf20Sopenharmony_ci if (pf->msix_entries) { 28028c2ecf20Sopenharmony_ci synchronize_irq(pf->msix_entries[pf->oicr_idx].vector); 28038c2ecf20Sopenharmony_ci devm_free_irq(ice_pf_to_dev(pf), 28048c2ecf20Sopenharmony_ci pf->msix_entries[pf->oicr_idx].vector, pf); 28058c2ecf20Sopenharmony_ci } 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_ci pf->num_avail_sw_msix += 1; 28088c2ecf20Sopenharmony_ci ice_free_res(pf->irq_tracker, pf->oicr_idx, ICE_RES_MISC_VEC_ID); 28098c2ecf20Sopenharmony_ci} 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci/** 28128c2ecf20Sopenharmony_ci * ice_ena_ctrlq_interrupts - enable control queue interrupts 28138c2ecf20Sopenharmony_ci * @hw: pointer to HW structure 28148c2ecf20Sopenharmony_ci * @reg_idx: HW vector index to associate the control queue interrupts with 28158c2ecf20Sopenharmony_ci */ 28168c2ecf20Sopenharmony_cistatic void ice_ena_ctrlq_interrupts(struct ice_hw *hw, u16 reg_idx) 28178c2ecf20Sopenharmony_ci{ 28188c2ecf20Sopenharmony_ci u32 val; 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_ci val = ((reg_idx & PFINT_OICR_CTL_MSIX_INDX_M) | 28218c2ecf20Sopenharmony_ci PFINT_OICR_CTL_CAUSE_ENA_M); 28228c2ecf20Sopenharmony_ci wr32(hw, PFINT_OICR_CTL, val); 28238c2ecf20Sopenharmony_ci 28248c2ecf20Sopenharmony_ci /* enable Admin queue Interrupt causes */ 28258c2ecf20Sopenharmony_ci val = ((reg_idx & PFINT_FW_CTL_MSIX_INDX_M) | 28268c2ecf20Sopenharmony_ci PFINT_FW_CTL_CAUSE_ENA_M); 28278c2ecf20Sopenharmony_ci wr32(hw, PFINT_FW_CTL, val); 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci /* enable Mailbox queue Interrupt causes */ 28308c2ecf20Sopenharmony_ci val = ((reg_idx & PFINT_MBX_CTL_MSIX_INDX_M) | 28318c2ecf20Sopenharmony_ci PFINT_MBX_CTL_CAUSE_ENA_M); 28328c2ecf20Sopenharmony_ci wr32(hw, PFINT_MBX_CTL, val); 28338c2ecf20Sopenharmony_ci 28348c2ecf20Sopenharmony_ci ice_flush(hw); 28358c2ecf20Sopenharmony_ci} 28368c2ecf20Sopenharmony_ci 28378c2ecf20Sopenharmony_ci/** 28388c2ecf20Sopenharmony_ci * ice_req_irq_msix_misc - Setup the misc vector to handle non queue events 28398c2ecf20Sopenharmony_ci * @pf: board private structure 28408c2ecf20Sopenharmony_ci * 28418c2ecf20Sopenharmony_ci * This sets up the handler for MSIX 0, which is used to manage the 28428c2ecf20Sopenharmony_ci * non-queue interrupts, e.g. AdminQ and errors. This is not used 28438c2ecf20Sopenharmony_ci * when in MSI or Legacy interrupt mode. 28448c2ecf20Sopenharmony_ci */ 28458c2ecf20Sopenharmony_cistatic int ice_req_irq_msix_misc(struct ice_pf *pf) 28468c2ecf20Sopenharmony_ci{ 28478c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 28488c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 28498c2ecf20Sopenharmony_ci int oicr_idx, err = 0; 28508c2ecf20Sopenharmony_ci 28518c2ecf20Sopenharmony_ci if (!pf->int_name[0]) 28528c2ecf20Sopenharmony_ci snprintf(pf->int_name, sizeof(pf->int_name) - 1, "%s-%s:misc", 28538c2ecf20Sopenharmony_ci dev_driver_string(dev), dev_name(dev)); 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_ci /* Do not request IRQ but do enable OICR interrupt since settings are 28568c2ecf20Sopenharmony_ci * lost during reset. Note that this function is called only during 28578c2ecf20Sopenharmony_ci * rebuild path and not while reset is in progress. 28588c2ecf20Sopenharmony_ci */ 28598c2ecf20Sopenharmony_ci if (ice_is_reset_in_progress(pf->state)) 28608c2ecf20Sopenharmony_ci goto skip_req_irq; 28618c2ecf20Sopenharmony_ci 28628c2ecf20Sopenharmony_ci /* reserve one vector in irq_tracker for misc interrupts */ 28638c2ecf20Sopenharmony_ci oicr_idx = ice_get_res(pf, pf->irq_tracker, 1, ICE_RES_MISC_VEC_ID); 28648c2ecf20Sopenharmony_ci if (oicr_idx < 0) 28658c2ecf20Sopenharmony_ci return oicr_idx; 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_ci pf->num_avail_sw_msix -= 1; 28688c2ecf20Sopenharmony_ci pf->oicr_idx = (u16)oicr_idx; 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci err = devm_request_irq(dev, pf->msix_entries[pf->oicr_idx].vector, 28718c2ecf20Sopenharmony_ci ice_misc_intr, 0, pf->int_name, pf); 28728c2ecf20Sopenharmony_ci if (err) { 28738c2ecf20Sopenharmony_ci dev_err(dev, "devm_request_irq for %s failed: %d\n", 28748c2ecf20Sopenharmony_ci pf->int_name, err); 28758c2ecf20Sopenharmony_ci ice_free_res(pf->irq_tracker, 1, ICE_RES_MISC_VEC_ID); 28768c2ecf20Sopenharmony_ci pf->num_avail_sw_msix += 1; 28778c2ecf20Sopenharmony_ci return err; 28788c2ecf20Sopenharmony_ci } 28798c2ecf20Sopenharmony_ci 28808c2ecf20Sopenharmony_ciskip_req_irq: 28818c2ecf20Sopenharmony_ci ice_ena_misc_vector(pf); 28828c2ecf20Sopenharmony_ci 28838c2ecf20Sopenharmony_ci ice_ena_ctrlq_interrupts(hw, pf->oicr_idx); 28848c2ecf20Sopenharmony_ci wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->oicr_idx), 28858c2ecf20Sopenharmony_ci ITR_REG_ALIGN(ICE_ITR_8K) >> ICE_ITR_GRAN_S); 28868c2ecf20Sopenharmony_ci 28878c2ecf20Sopenharmony_ci ice_flush(hw); 28888c2ecf20Sopenharmony_ci ice_irq_dynamic_ena(hw, NULL, NULL); 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_ci return 0; 28918c2ecf20Sopenharmony_ci} 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci/** 28948c2ecf20Sopenharmony_ci * ice_napi_add - register NAPI handler for the VSI 28958c2ecf20Sopenharmony_ci * @vsi: VSI for which NAPI handler is to be registered 28968c2ecf20Sopenharmony_ci * 28978c2ecf20Sopenharmony_ci * This function is only called in the driver's load path. Registering the NAPI 28988c2ecf20Sopenharmony_ci * handler is done in ice_vsi_alloc_q_vector() for all other cases (i.e. resume, 28998c2ecf20Sopenharmony_ci * reset/rebuild, etc.) 29008c2ecf20Sopenharmony_ci */ 29018c2ecf20Sopenharmony_cistatic void ice_napi_add(struct ice_vsi *vsi) 29028c2ecf20Sopenharmony_ci{ 29038c2ecf20Sopenharmony_ci int v_idx; 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci if (!vsi->netdev) 29068c2ecf20Sopenharmony_ci return; 29078c2ecf20Sopenharmony_ci 29088c2ecf20Sopenharmony_ci ice_for_each_q_vector(vsi, v_idx) 29098c2ecf20Sopenharmony_ci netif_napi_add(vsi->netdev, &vsi->q_vectors[v_idx]->napi, 29108c2ecf20Sopenharmony_ci ice_napi_poll, NAPI_POLL_WEIGHT); 29118c2ecf20Sopenharmony_ci} 29128c2ecf20Sopenharmony_ci 29138c2ecf20Sopenharmony_ci/** 29148c2ecf20Sopenharmony_ci * ice_set_ops - set netdev and ethtools ops for the given netdev 29158c2ecf20Sopenharmony_ci * @netdev: netdev instance 29168c2ecf20Sopenharmony_ci */ 29178c2ecf20Sopenharmony_cistatic void ice_set_ops(struct net_device *netdev) 29188c2ecf20Sopenharmony_ci{ 29198c2ecf20Sopenharmony_ci struct ice_pf *pf = ice_netdev_to_pf(netdev); 29208c2ecf20Sopenharmony_ci 29218c2ecf20Sopenharmony_ci if (ice_is_safe_mode(pf)) { 29228c2ecf20Sopenharmony_ci netdev->netdev_ops = &ice_netdev_safe_mode_ops; 29238c2ecf20Sopenharmony_ci ice_set_ethtool_safe_mode_ops(netdev); 29248c2ecf20Sopenharmony_ci return; 29258c2ecf20Sopenharmony_ci } 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci netdev->netdev_ops = &ice_netdev_ops; 29288c2ecf20Sopenharmony_ci netdev->udp_tunnel_nic_info = &pf->hw.udp_tunnel_nic; 29298c2ecf20Sopenharmony_ci ice_set_ethtool_ops(netdev); 29308c2ecf20Sopenharmony_ci} 29318c2ecf20Sopenharmony_ci 29328c2ecf20Sopenharmony_ci/** 29338c2ecf20Sopenharmony_ci * ice_set_netdev_features - set features for the given netdev 29348c2ecf20Sopenharmony_ci * @netdev: netdev instance 29358c2ecf20Sopenharmony_ci */ 29368c2ecf20Sopenharmony_cistatic void ice_set_netdev_features(struct net_device *netdev) 29378c2ecf20Sopenharmony_ci{ 29388c2ecf20Sopenharmony_ci struct ice_pf *pf = ice_netdev_to_pf(netdev); 29398c2ecf20Sopenharmony_ci netdev_features_t csumo_features; 29408c2ecf20Sopenharmony_ci netdev_features_t vlano_features; 29418c2ecf20Sopenharmony_ci netdev_features_t dflt_features; 29428c2ecf20Sopenharmony_ci netdev_features_t tso_features; 29438c2ecf20Sopenharmony_ci 29448c2ecf20Sopenharmony_ci if (ice_is_safe_mode(pf)) { 29458c2ecf20Sopenharmony_ci /* safe mode */ 29468c2ecf20Sopenharmony_ci netdev->features = NETIF_F_SG | NETIF_F_HIGHDMA; 29478c2ecf20Sopenharmony_ci netdev->hw_features = netdev->features; 29488c2ecf20Sopenharmony_ci return; 29498c2ecf20Sopenharmony_ci } 29508c2ecf20Sopenharmony_ci 29518c2ecf20Sopenharmony_ci dflt_features = NETIF_F_SG | 29528c2ecf20Sopenharmony_ci NETIF_F_HIGHDMA | 29538c2ecf20Sopenharmony_ci NETIF_F_NTUPLE | 29548c2ecf20Sopenharmony_ci NETIF_F_RXHASH; 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ci csumo_features = NETIF_F_RXCSUM | 29578c2ecf20Sopenharmony_ci NETIF_F_IP_CSUM | 29588c2ecf20Sopenharmony_ci NETIF_F_SCTP_CRC | 29598c2ecf20Sopenharmony_ci NETIF_F_IPV6_CSUM; 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_ci vlano_features = NETIF_F_HW_VLAN_CTAG_FILTER | 29628c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX | 29638c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX; 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci tso_features = NETIF_F_TSO | 29668c2ecf20Sopenharmony_ci NETIF_F_TSO_ECN | 29678c2ecf20Sopenharmony_ci NETIF_F_TSO6 | 29688c2ecf20Sopenharmony_ci NETIF_F_GSO_GRE | 29698c2ecf20Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL | 29708c2ecf20Sopenharmony_ci NETIF_F_GSO_GRE_CSUM | 29718c2ecf20Sopenharmony_ci NETIF_F_GSO_UDP_TUNNEL_CSUM | 29728c2ecf20Sopenharmony_ci NETIF_F_GSO_PARTIAL | 29738c2ecf20Sopenharmony_ci NETIF_F_GSO_IPXIP4 | 29748c2ecf20Sopenharmony_ci NETIF_F_GSO_IPXIP6 | 29758c2ecf20Sopenharmony_ci NETIF_F_GSO_UDP_L4; 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_ci netdev->gso_partial_features |= NETIF_F_GSO_UDP_TUNNEL_CSUM | 29788c2ecf20Sopenharmony_ci NETIF_F_GSO_GRE_CSUM; 29798c2ecf20Sopenharmony_ci /* set features that user can change */ 29808c2ecf20Sopenharmony_ci netdev->hw_features = dflt_features | csumo_features | 29818c2ecf20Sopenharmony_ci vlano_features | tso_features; 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ci /* add support for HW_CSUM on packets with MPLS header */ 29848c2ecf20Sopenharmony_ci netdev->mpls_features = NETIF_F_HW_CSUM; 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_ci /* enable features */ 29878c2ecf20Sopenharmony_ci netdev->features |= netdev->hw_features; 29888c2ecf20Sopenharmony_ci /* encap and VLAN devices inherit default, csumo and tso features */ 29898c2ecf20Sopenharmony_ci netdev->hw_enc_features |= dflt_features | csumo_features | 29908c2ecf20Sopenharmony_ci tso_features; 29918c2ecf20Sopenharmony_ci netdev->vlan_features |= dflt_features | csumo_features | 29928c2ecf20Sopenharmony_ci tso_features; 29938c2ecf20Sopenharmony_ci} 29948c2ecf20Sopenharmony_ci 29958c2ecf20Sopenharmony_ci/** 29968c2ecf20Sopenharmony_ci * ice_cfg_netdev - Allocate, configure and register a netdev 29978c2ecf20Sopenharmony_ci * @vsi: the VSI associated with the new netdev 29988c2ecf20Sopenharmony_ci * 29998c2ecf20Sopenharmony_ci * Returns 0 on success, negative value on failure 30008c2ecf20Sopenharmony_ci */ 30018c2ecf20Sopenharmony_cistatic int ice_cfg_netdev(struct ice_vsi *vsi) 30028c2ecf20Sopenharmony_ci{ 30038c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 30048c2ecf20Sopenharmony_ci struct ice_netdev_priv *np; 30058c2ecf20Sopenharmony_ci struct net_device *netdev; 30068c2ecf20Sopenharmony_ci u8 mac_addr[ETH_ALEN]; 30078c2ecf20Sopenharmony_ci int err; 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci err = ice_devlink_create_port(vsi); 30108c2ecf20Sopenharmony_ci if (err) 30118c2ecf20Sopenharmony_ci return err; 30128c2ecf20Sopenharmony_ci 30138c2ecf20Sopenharmony_ci netdev = alloc_etherdev_mqs(sizeof(*np), vsi->alloc_txq, 30148c2ecf20Sopenharmony_ci vsi->alloc_rxq); 30158c2ecf20Sopenharmony_ci if (!netdev) { 30168c2ecf20Sopenharmony_ci err = -ENOMEM; 30178c2ecf20Sopenharmony_ci goto err_destroy_devlink_port; 30188c2ecf20Sopenharmony_ci } 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci vsi->netdev = netdev; 30218c2ecf20Sopenharmony_ci np = netdev_priv(netdev); 30228c2ecf20Sopenharmony_ci np->vsi = vsi; 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ci ice_set_netdev_features(netdev); 30258c2ecf20Sopenharmony_ci 30268c2ecf20Sopenharmony_ci ice_set_ops(netdev); 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_PF) { 30298c2ecf20Sopenharmony_ci SET_NETDEV_DEV(netdev, ice_pf_to_dev(pf)); 30308c2ecf20Sopenharmony_ci ether_addr_copy(mac_addr, vsi->port_info->mac.perm_addr); 30318c2ecf20Sopenharmony_ci ether_addr_copy(netdev->dev_addr, mac_addr); 30328c2ecf20Sopenharmony_ci ether_addr_copy(netdev->perm_addr, mac_addr); 30338c2ecf20Sopenharmony_ci } 30348c2ecf20Sopenharmony_ci 30358c2ecf20Sopenharmony_ci netdev->priv_flags |= IFF_UNICAST_FLT; 30368c2ecf20Sopenharmony_ci 30378c2ecf20Sopenharmony_ci /* Setup netdev TC information */ 30388c2ecf20Sopenharmony_ci ice_vsi_cfg_netdev_tc(vsi, vsi->tc_cfg.ena_tc); 30398c2ecf20Sopenharmony_ci 30408c2ecf20Sopenharmony_ci /* setup watchdog timeout value to be 5 second */ 30418c2ecf20Sopenharmony_ci netdev->watchdog_timeo = 5 * HZ; 30428c2ecf20Sopenharmony_ci 30438c2ecf20Sopenharmony_ci netdev->min_mtu = ETH_MIN_MTU; 30448c2ecf20Sopenharmony_ci netdev->max_mtu = ICE_MAX_MTU; 30458c2ecf20Sopenharmony_ci 30468c2ecf20Sopenharmony_ci err = register_netdev(vsi->netdev); 30478c2ecf20Sopenharmony_ci if (err) 30488c2ecf20Sopenharmony_ci goto err_free_netdev; 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_ci devlink_port_type_eth_set(&vsi->devlink_port, vsi->netdev); 30518c2ecf20Sopenharmony_ci 30528c2ecf20Sopenharmony_ci netif_carrier_off(vsi->netdev); 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci /* make sure transmit queues start off as stopped */ 30558c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(vsi->netdev); 30568c2ecf20Sopenharmony_ci 30578c2ecf20Sopenharmony_ci return 0; 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_cierr_free_netdev: 30608c2ecf20Sopenharmony_ci free_netdev(vsi->netdev); 30618c2ecf20Sopenharmony_ci vsi->netdev = NULL; 30628c2ecf20Sopenharmony_cierr_destroy_devlink_port: 30638c2ecf20Sopenharmony_ci ice_devlink_destroy_port(vsi); 30648c2ecf20Sopenharmony_ci return err; 30658c2ecf20Sopenharmony_ci} 30668c2ecf20Sopenharmony_ci 30678c2ecf20Sopenharmony_ci/** 30688c2ecf20Sopenharmony_ci * ice_fill_rss_lut - Fill the RSS lookup table with default values 30698c2ecf20Sopenharmony_ci * @lut: Lookup table 30708c2ecf20Sopenharmony_ci * @rss_table_size: Lookup table size 30718c2ecf20Sopenharmony_ci * @rss_size: Range of queue number for hashing 30728c2ecf20Sopenharmony_ci */ 30738c2ecf20Sopenharmony_civoid ice_fill_rss_lut(u8 *lut, u16 rss_table_size, u16 rss_size) 30748c2ecf20Sopenharmony_ci{ 30758c2ecf20Sopenharmony_ci u16 i; 30768c2ecf20Sopenharmony_ci 30778c2ecf20Sopenharmony_ci for (i = 0; i < rss_table_size; i++) 30788c2ecf20Sopenharmony_ci lut[i] = i % rss_size; 30798c2ecf20Sopenharmony_ci} 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_ci/** 30828c2ecf20Sopenharmony_ci * ice_pf_vsi_setup - Set up a PF VSI 30838c2ecf20Sopenharmony_ci * @pf: board private structure 30848c2ecf20Sopenharmony_ci * @pi: pointer to the port_info instance 30858c2ecf20Sopenharmony_ci * 30868c2ecf20Sopenharmony_ci * Returns pointer to the successfully allocated VSI software struct 30878c2ecf20Sopenharmony_ci * on success, otherwise returns NULL on failure. 30888c2ecf20Sopenharmony_ci */ 30898c2ecf20Sopenharmony_cistatic struct ice_vsi * 30908c2ecf20Sopenharmony_ciice_pf_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi) 30918c2ecf20Sopenharmony_ci{ 30928c2ecf20Sopenharmony_ci return ice_vsi_setup(pf, pi, ICE_VSI_PF, ICE_INVAL_VFID); 30938c2ecf20Sopenharmony_ci} 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci/** 30968c2ecf20Sopenharmony_ci * ice_ctrl_vsi_setup - Set up a control VSI 30978c2ecf20Sopenharmony_ci * @pf: board private structure 30988c2ecf20Sopenharmony_ci * @pi: pointer to the port_info instance 30998c2ecf20Sopenharmony_ci * 31008c2ecf20Sopenharmony_ci * Returns pointer to the successfully allocated VSI software struct 31018c2ecf20Sopenharmony_ci * on success, otherwise returns NULL on failure. 31028c2ecf20Sopenharmony_ci */ 31038c2ecf20Sopenharmony_cistatic struct ice_vsi * 31048c2ecf20Sopenharmony_ciice_ctrl_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi) 31058c2ecf20Sopenharmony_ci{ 31068c2ecf20Sopenharmony_ci return ice_vsi_setup(pf, pi, ICE_VSI_CTRL, ICE_INVAL_VFID); 31078c2ecf20Sopenharmony_ci} 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_ci/** 31108c2ecf20Sopenharmony_ci * ice_lb_vsi_setup - Set up a loopback VSI 31118c2ecf20Sopenharmony_ci * @pf: board private structure 31128c2ecf20Sopenharmony_ci * @pi: pointer to the port_info instance 31138c2ecf20Sopenharmony_ci * 31148c2ecf20Sopenharmony_ci * Returns pointer to the successfully allocated VSI software struct 31158c2ecf20Sopenharmony_ci * on success, otherwise returns NULL on failure. 31168c2ecf20Sopenharmony_ci */ 31178c2ecf20Sopenharmony_cistruct ice_vsi * 31188c2ecf20Sopenharmony_ciice_lb_vsi_setup(struct ice_pf *pf, struct ice_port_info *pi) 31198c2ecf20Sopenharmony_ci{ 31208c2ecf20Sopenharmony_ci return ice_vsi_setup(pf, pi, ICE_VSI_LB, ICE_INVAL_VFID); 31218c2ecf20Sopenharmony_ci} 31228c2ecf20Sopenharmony_ci 31238c2ecf20Sopenharmony_ci/** 31248c2ecf20Sopenharmony_ci * ice_vlan_rx_add_vid - Add a VLAN ID filter to HW offload 31258c2ecf20Sopenharmony_ci * @netdev: network interface to be adjusted 31268c2ecf20Sopenharmony_ci * @proto: unused protocol 31278c2ecf20Sopenharmony_ci * @vid: VLAN ID to be added 31288c2ecf20Sopenharmony_ci * 31298c2ecf20Sopenharmony_ci * net_device_ops implementation for adding VLAN IDs 31308c2ecf20Sopenharmony_ci */ 31318c2ecf20Sopenharmony_cistatic int 31328c2ecf20Sopenharmony_ciice_vlan_rx_add_vid(struct net_device *netdev, __always_unused __be16 proto, 31338c2ecf20Sopenharmony_ci u16 vid) 31348c2ecf20Sopenharmony_ci{ 31358c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 31368c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 31378c2ecf20Sopenharmony_ci int ret; 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci if (vid >= VLAN_N_VID) { 31408c2ecf20Sopenharmony_ci netdev_err(netdev, "VLAN id requested %d is out of range %d\n", 31418c2ecf20Sopenharmony_ci vid, VLAN_N_VID); 31428c2ecf20Sopenharmony_ci return -EINVAL; 31438c2ecf20Sopenharmony_ci } 31448c2ecf20Sopenharmony_ci 31458c2ecf20Sopenharmony_ci if (vsi->info.pvid) 31468c2ecf20Sopenharmony_ci return -EINVAL; 31478c2ecf20Sopenharmony_ci 31488c2ecf20Sopenharmony_ci /* VLAN 0 is added by default during load/reset */ 31498c2ecf20Sopenharmony_ci if (!vid) 31508c2ecf20Sopenharmony_ci return 0; 31518c2ecf20Sopenharmony_ci 31528c2ecf20Sopenharmony_ci /* Enable VLAN pruning when a VLAN other than 0 is added */ 31538c2ecf20Sopenharmony_ci if (!ice_vsi_is_vlan_pruning_ena(vsi)) { 31548c2ecf20Sopenharmony_ci ret = ice_cfg_vlan_pruning(vsi, true, false); 31558c2ecf20Sopenharmony_ci if (ret) 31568c2ecf20Sopenharmony_ci return ret; 31578c2ecf20Sopenharmony_ci } 31588c2ecf20Sopenharmony_ci 31598c2ecf20Sopenharmony_ci /* Add a switch rule for this VLAN ID so its corresponding VLAN tagged 31608c2ecf20Sopenharmony_ci * packets aren't pruned by the device's internal switch on Rx 31618c2ecf20Sopenharmony_ci */ 31628c2ecf20Sopenharmony_ci ret = ice_vsi_add_vlan(vsi, vid, ICE_FWD_TO_VSI); 31638c2ecf20Sopenharmony_ci if (!ret) { 31648c2ecf20Sopenharmony_ci vsi->vlan_ena = true; 31658c2ecf20Sopenharmony_ci set_bit(ICE_VSI_FLAG_VLAN_FLTR_CHANGED, vsi->flags); 31668c2ecf20Sopenharmony_ci } 31678c2ecf20Sopenharmony_ci 31688c2ecf20Sopenharmony_ci return ret; 31698c2ecf20Sopenharmony_ci} 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci/** 31728c2ecf20Sopenharmony_ci * ice_vlan_rx_kill_vid - Remove a VLAN ID filter from HW offload 31738c2ecf20Sopenharmony_ci * @netdev: network interface to be adjusted 31748c2ecf20Sopenharmony_ci * @proto: unused protocol 31758c2ecf20Sopenharmony_ci * @vid: VLAN ID to be removed 31768c2ecf20Sopenharmony_ci * 31778c2ecf20Sopenharmony_ci * net_device_ops implementation for removing VLAN IDs 31788c2ecf20Sopenharmony_ci */ 31798c2ecf20Sopenharmony_cistatic int 31808c2ecf20Sopenharmony_ciice_vlan_rx_kill_vid(struct net_device *netdev, __always_unused __be16 proto, 31818c2ecf20Sopenharmony_ci u16 vid) 31828c2ecf20Sopenharmony_ci{ 31838c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 31848c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 31858c2ecf20Sopenharmony_ci int ret; 31868c2ecf20Sopenharmony_ci 31878c2ecf20Sopenharmony_ci if (vsi->info.pvid) 31888c2ecf20Sopenharmony_ci return -EINVAL; 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_ci /* don't allow removal of VLAN 0 */ 31918c2ecf20Sopenharmony_ci if (!vid) 31928c2ecf20Sopenharmony_ci return 0; 31938c2ecf20Sopenharmony_ci 31948c2ecf20Sopenharmony_ci /* Make sure ice_vsi_kill_vlan is successful before updating VLAN 31958c2ecf20Sopenharmony_ci * information 31968c2ecf20Sopenharmony_ci */ 31978c2ecf20Sopenharmony_ci ret = ice_vsi_kill_vlan(vsi, vid); 31988c2ecf20Sopenharmony_ci if (ret) 31998c2ecf20Sopenharmony_ci return ret; 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_ci /* Disable pruning when VLAN 0 is the only VLAN rule */ 32028c2ecf20Sopenharmony_ci if (vsi->num_vlan == 1 && ice_vsi_is_vlan_pruning_ena(vsi)) 32038c2ecf20Sopenharmony_ci ret = ice_cfg_vlan_pruning(vsi, false, false); 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_ci vsi->vlan_ena = false; 32068c2ecf20Sopenharmony_ci set_bit(ICE_VSI_FLAG_VLAN_FLTR_CHANGED, vsi->flags); 32078c2ecf20Sopenharmony_ci return ret; 32088c2ecf20Sopenharmony_ci} 32098c2ecf20Sopenharmony_ci 32108c2ecf20Sopenharmony_ci/** 32118c2ecf20Sopenharmony_ci * ice_setup_pf_sw - Setup the HW switch on startup or after reset 32128c2ecf20Sopenharmony_ci * @pf: board private structure 32138c2ecf20Sopenharmony_ci * 32148c2ecf20Sopenharmony_ci * Returns 0 on success, negative value on failure 32158c2ecf20Sopenharmony_ci */ 32168c2ecf20Sopenharmony_cistatic int ice_setup_pf_sw(struct ice_pf *pf) 32178c2ecf20Sopenharmony_ci{ 32188c2ecf20Sopenharmony_ci struct ice_vsi *vsi; 32198c2ecf20Sopenharmony_ci int status = 0; 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_ci if (ice_is_reset_in_progress(pf->state)) 32228c2ecf20Sopenharmony_ci return -EBUSY; 32238c2ecf20Sopenharmony_ci 32248c2ecf20Sopenharmony_ci vsi = ice_pf_vsi_setup(pf, pf->hw.port_info); 32258c2ecf20Sopenharmony_ci if (!vsi) 32268c2ecf20Sopenharmony_ci return -ENOMEM; 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_ci status = ice_cfg_netdev(vsi); 32298c2ecf20Sopenharmony_ci if (status) { 32308c2ecf20Sopenharmony_ci status = -ENODEV; 32318c2ecf20Sopenharmony_ci goto unroll_vsi_setup; 32328c2ecf20Sopenharmony_ci } 32338c2ecf20Sopenharmony_ci /* netdev has to be configured before setting frame size */ 32348c2ecf20Sopenharmony_ci ice_vsi_cfg_frame_size(vsi); 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_ci /* Setup DCB netlink interface */ 32378c2ecf20Sopenharmony_ci ice_dcbnl_setup(vsi); 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_ci /* registering the NAPI handler requires both the queues and 32408c2ecf20Sopenharmony_ci * netdev to be created, which are done in ice_pf_vsi_setup() 32418c2ecf20Sopenharmony_ci * and ice_cfg_netdev() respectively 32428c2ecf20Sopenharmony_ci */ 32438c2ecf20Sopenharmony_ci ice_napi_add(vsi); 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_ci status = ice_set_cpu_rx_rmap(vsi); 32468c2ecf20Sopenharmony_ci if (status) { 32478c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(pf), "Failed to set CPU Rx map VSI %d error %d\n", 32488c2ecf20Sopenharmony_ci vsi->vsi_num, status); 32498c2ecf20Sopenharmony_ci status = -EINVAL; 32508c2ecf20Sopenharmony_ci goto unroll_napi_add; 32518c2ecf20Sopenharmony_ci } 32528c2ecf20Sopenharmony_ci status = ice_init_mac_fltr(pf); 32538c2ecf20Sopenharmony_ci if (status) 32548c2ecf20Sopenharmony_ci goto free_cpu_rx_map; 32558c2ecf20Sopenharmony_ci 32568c2ecf20Sopenharmony_ci return status; 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_cifree_cpu_rx_map: 32598c2ecf20Sopenharmony_ci ice_free_cpu_rx_rmap(vsi); 32608c2ecf20Sopenharmony_ci 32618c2ecf20Sopenharmony_ciunroll_napi_add: 32628c2ecf20Sopenharmony_ci if (vsi) { 32638c2ecf20Sopenharmony_ci ice_napi_del(vsi); 32648c2ecf20Sopenharmony_ci if (vsi->netdev) { 32658c2ecf20Sopenharmony_ci if (vsi->netdev->reg_state == NETREG_REGISTERED) 32668c2ecf20Sopenharmony_ci unregister_netdev(vsi->netdev); 32678c2ecf20Sopenharmony_ci free_netdev(vsi->netdev); 32688c2ecf20Sopenharmony_ci vsi->netdev = NULL; 32698c2ecf20Sopenharmony_ci } 32708c2ecf20Sopenharmony_ci } 32718c2ecf20Sopenharmony_ci 32728c2ecf20Sopenharmony_ciunroll_vsi_setup: 32738c2ecf20Sopenharmony_ci ice_vsi_release(vsi); 32748c2ecf20Sopenharmony_ci return status; 32758c2ecf20Sopenharmony_ci} 32768c2ecf20Sopenharmony_ci 32778c2ecf20Sopenharmony_ci/** 32788c2ecf20Sopenharmony_ci * ice_get_avail_q_count - Get count of queues in use 32798c2ecf20Sopenharmony_ci * @pf_qmap: bitmap to get queue use count from 32808c2ecf20Sopenharmony_ci * @lock: pointer to a mutex that protects access to pf_qmap 32818c2ecf20Sopenharmony_ci * @size: size of the bitmap 32828c2ecf20Sopenharmony_ci */ 32838c2ecf20Sopenharmony_cistatic u16 32848c2ecf20Sopenharmony_ciice_get_avail_q_count(unsigned long *pf_qmap, struct mutex *lock, u16 size) 32858c2ecf20Sopenharmony_ci{ 32868c2ecf20Sopenharmony_ci unsigned long bit; 32878c2ecf20Sopenharmony_ci u16 count = 0; 32888c2ecf20Sopenharmony_ci 32898c2ecf20Sopenharmony_ci mutex_lock(lock); 32908c2ecf20Sopenharmony_ci for_each_clear_bit(bit, pf_qmap, size) 32918c2ecf20Sopenharmony_ci count++; 32928c2ecf20Sopenharmony_ci mutex_unlock(lock); 32938c2ecf20Sopenharmony_ci 32948c2ecf20Sopenharmony_ci return count; 32958c2ecf20Sopenharmony_ci} 32968c2ecf20Sopenharmony_ci 32978c2ecf20Sopenharmony_ci/** 32988c2ecf20Sopenharmony_ci * ice_get_avail_txq_count - Get count of Tx queues in use 32998c2ecf20Sopenharmony_ci * @pf: pointer to an ice_pf instance 33008c2ecf20Sopenharmony_ci */ 33018c2ecf20Sopenharmony_ciu16 ice_get_avail_txq_count(struct ice_pf *pf) 33028c2ecf20Sopenharmony_ci{ 33038c2ecf20Sopenharmony_ci return ice_get_avail_q_count(pf->avail_txqs, &pf->avail_q_mutex, 33048c2ecf20Sopenharmony_ci pf->max_pf_txqs); 33058c2ecf20Sopenharmony_ci} 33068c2ecf20Sopenharmony_ci 33078c2ecf20Sopenharmony_ci/** 33088c2ecf20Sopenharmony_ci * ice_get_avail_rxq_count - Get count of Rx queues in use 33098c2ecf20Sopenharmony_ci * @pf: pointer to an ice_pf instance 33108c2ecf20Sopenharmony_ci */ 33118c2ecf20Sopenharmony_ciu16 ice_get_avail_rxq_count(struct ice_pf *pf) 33128c2ecf20Sopenharmony_ci{ 33138c2ecf20Sopenharmony_ci return ice_get_avail_q_count(pf->avail_rxqs, &pf->avail_q_mutex, 33148c2ecf20Sopenharmony_ci pf->max_pf_rxqs); 33158c2ecf20Sopenharmony_ci} 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci/** 33188c2ecf20Sopenharmony_ci * ice_deinit_pf - Unrolls initialziations done by ice_init_pf 33198c2ecf20Sopenharmony_ci * @pf: board private structure to initialize 33208c2ecf20Sopenharmony_ci */ 33218c2ecf20Sopenharmony_cistatic void ice_deinit_pf(struct ice_pf *pf) 33228c2ecf20Sopenharmony_ci{ 33238c2ecf20Sopenharmony_ci ice_service_task_stop(pf); 33248c2ecf20Sopenharmony_ci mutex_destroy(&pf->sw_mutex); 33258c2ecf20Sopenharmony_ci mutex_destroy(&pf->tc_mutex); 33268c2ecf20Sopenharmony_ci mutex_destroy(&pf->avail_q_mutex); 33278c2ecf20Sopenharmony_ci 33288c2ecf20Sopenharmony_ci if (pf->avail_txqs) { 33298c2ecf20Sopenharmony_ci bitmap_free(pf->avail_txqs); 33308c2ecf20Sopenharmony_ci pf->avail_txqs = NULL; 33318c2ecf20Sopenharmony_ci } 33328c2ecf20Sopenharmony_ci 33338c2ecf20Sopenharmony_ci if (pf->avail_rxqs) { 33348c2ecf20Sopenharmony_ci bitmap_free(pf->avail_rxqs); 33358c2ecf20Sopenharmony_ci pf->avail_rxqs = NULL; 33368c2ecf20Sopenharmony_ci } 33378c2ecf20Sopenharmony_ci} 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci/** 33408c2ecf20Sopenharmony_ci * ice_set_pf_caps - set PFs capability flags 33418c2ecf20Sopenharmony_ci * @pf: pointer to the PF instance 33428c2ecf20Sopenharmony_ci */ 33438c2ecf20Sopenharmony_cistatic void ice_set_pf_caps(struct ice_pf *pf) 33448c2ecf20Sopenharmony_ci{ 33458c2ecf20Sopenharmony_ci struct ice_hw_func_caps *func_caps = &pf->hw.func_caps; 33468c2ecf20Sopenharmony_ci 33478c2ecf20Sopenharmony_ci clear_bit(ICE_FLAG_DCB_CAPABLE, pf->flags); 33488c2ecf20Sopenharmony_ci if (func_caps->common_cap.dcb) 33498c2ecf20Sopenharmony_ci set_bit(ICE_FLAG_DCB_CAPABLE, pf->flags); 33508c2ecf20Sopenharmony_ci clear_bit(ICE_FLAG_SRIOV_CAPABLE, pf->flags); 33518c2ecf20Sopenharmony_ci if (func_caps->common_cap.sr_iov_1_1) { 33528c2ecf20Sopenharmony_ci set_bit(ICE_FLAG_SRIOV_CAPABLE, pf->flags); 33538c2ecf20Sopenharmony_ci pf->num_vfs_supported = min_t(int, func_caps->num_allocd_vfs, 33548c2ecf20Sopenharmony_ci ICE_MAX_VF_COUNT); 33558c2ecf20Sopenharmony_ci } 33568c2ecf20Sopenharmony_ci clear_bit(ICE_FLAG_RSS_ENA, pf->flags); 33578c2ecf20Sopenharmony_ci if (func_caps->common_cap.rss_table_size) 33588c2ecf20Sopenharmony_ci set_bit(ICE_FLAG_RSS_ENA, pf->flags); 33598c2ecf20Sopenharmony_ci 33608c2ecf20Sopenharmony_ci clear_bit(ICE_FLAG_FD_ENA, pf->flags); 33618c2ecf20Sopenharmony_ci if (func_caps->fd_fltr_guar > 0 || func_caps->fd_fltr_best_effort > 0) { 33628c2ecf20Sopenharmony_ci u16 unused; 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_ci /* ctrl_vsi_idx will be set to a valid value when flow director 33658c2ecf20Sopenharmony_ci * is setup by ice_init_fdir 33668c2ecf20Sopenharmony_ci */ 33678c2ecf20Sopenharmony_ci pf->ctrl_vsi_idx = ICE_NO_VSI; 33688c2ecf20Sopenharmony_ci set_bit(ICE_FLAG_FD_ENA, pf->flags); 33698c2ecf20Sopenharmony_ci /* force guaranteed filter pool for PF */ 33708c2ecf20Sopenharmony_ci ice_alloc_fd_guar_item(&pf->hw, &unused, 33718c2ecf20Sopenharmony_ci func_caps->fd_fltr_guar); 33728c2ecf20Sopenharmony_ci /* force shared filter pool for PF */ 33738c2ecf20Sopenharmony_ci ice_alloc_fd_shrd_item(&pf->hw, &unused, 33748c2ecf20Sopenharmony_ci func_caps->fd_fltr_best_effort); 33758c2ecf20Sopenharmony_ci } 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_ci pf->max_pf_txqs = func_caps->common_cap.num_txq; 33788c2ecf20Sopenharmony_ci pf->max_pf_rxqs = func_caps->common_cap.num_rxq; 33798c2ecf20Sopenharmony_ci} 33808c2ecf20Sopenharmony_ci 33818c2ecf20Sopenharmony_ci/** 33828c2ecf20Sopenharmony_ci * ice_init_pf - Initialize general software structures (struct ice_pf) 33838c2ecf20Sopenharmony_ci * @pf: board private structure to initialize 33848c2ecf20Sopenharmony_ci */ 33858c2ecf20Sopenharmony_cistatic int ice_init_pf(struct ice_pf *pf) 33868c2ecf20Sopenharmony_ci{ 33878c2ecf20Sopenharmony_ci ice_set_pf_caps(pf); 33888c2ecf20Sopenharmony_ci 33898c2ecf20Sopenharmony_ci mutex_init(&pf->sw_mutex); 33908c2ecf20Sopenharmony_ci mutex_init(&pf->tc_mutex); 33918c2ecf20Sopenharmony_ci 33928c2ecf20Sopenharmony_ci INIT_HLIST_HEAD(&pf->aq_wait_list); 33938c2ecf20Sopenharmony_ci spin_lock_init(&pf->aq_wait_lock); 33948c2ecf20Sopenharmony_ci init_waitqueue_head(&pf->aq_wait_queue); 33958c2ecf20Sopenharmony_ci 33968c2ecf20Sopenharmony_ci /* setup service timer and periodic service task */ 33978c2ecf20Sopenharmony_ci timer_setup(&pf->serv_tmr, ice_service_timer, 0); 33988c2ecf20Sopenharmony_ci pf->serv_tmr_period = HZ; 33998c2ecf20Sopenharmony_ci INIT_WORK(&pf->serv_task, ice_service_task); 34008c2ecf20Sopenharmony_ci clear_bit(__ICE_SERVICE_SCHED, pf->state); 34018c2ecf20Sopenharmony_ci 34028c2ecf20Sopenharmony_ci mutex_init(&pf->avail_q_mutex); 34038c2ecf20Sopenharmony_ci pf->avail_txqs = bitmap_zalloc(pf->max_pf_txqs, GFP_KERNEL); 34048c2ecf20Sopenharmony_ci if (!pf->avail_txqs) 34058c2ecf20Sopenharmony_ci return -ENOMEM; 34068c2ecf20Sopenharmony_ci 34078c2ecf20Sopenharmony_ci pf->avail_rxqs = bitmap_zalloc(pf->max_pf_rxqs, GFP_KERNEL); 34088c2ecf20Sopenharmony_ci if (!pf->avail_rxqs) { 34098c2ecf20Sopenharmony_ci bitmap_free(pf->avail_txqs); 34108c2ecf20Sopenharmony_ci pf->avail_txqs = NULL; 34118c2ecf20Sopenharmony_ci return -ENOMEM; 34128c2ecf20Sopenharmony_ci } 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_ci return 0; 34158c2ecf20Sopenharmony_ci} 34168c2ecf20Sopenharmony_ci 34178c2ecf20Sopenharmony_ci/** 34188c2ecf20Sopenharmony_ci * ice_ena_msix_range - Request a range of MSIX vectors from the OS 34198c2ecf20Sopenharmony_ci * @pf: board private structure 34208c2ecf20Sopenharmony_ci * 34218c2ecf20Sopenharmony_ci * compute the number of MSIX vectors required (v_budget) and request from 34228c2ecf20Sopenharmony_ci * the OS. Return the number of vectors reserved or negative on failure 34238c2ecf20Sopenharmony_ci */ 34248c2ecf20Sopenharmony_cistatic int ice_ena_msix_range(struct ice_pf *pf) 34258c2ecf20Sopenharmony_ci{ 34268c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 34278c2ecf20Sopenharmony_ci int v_left, v_actual, v_budget = 0; 34288c2ecf20Sopenharmony_ci int needed, err, i; 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci v_left = pf->hw.func_caps.common_cap.num_msix_vectors; 34318c2ecf20Sopenharmony_ci 34328c2ecf20Sopenharmony_ci /* reserve one vector for miscellaneous handler */ 34338c2ecf20Sopenharmony_ci needed = 1; 34348c2ecf20Sopenharmony_ci if (v_left < needed) 34358c2ecf20Sopenharmony_ci goto no_hw_vecs_left_err; 34368c2ecf20Sopenharmony_ci v_budget += needed; 34378c2ecf20Sopenharmony_ci v_left -= needed; 34388c2ecf20Sopenharmony_ci 34398c2ecf20Sopenharmony_ci /* reserve vectors for LAN traffic */ 34408c2ecf20Sopenharmony_ci needed = min_t(int, num_online_cpus(), v_left); 34418c2ecf20Sopenharmony_ci if (v_left < needed) 34428c2ecf20Sopenharmony_ci goto no_hw_vecs_left_err; 34438c2ecf20Sopenharmony_ci pf->num_lan_msix = needed; 34448c2ecf20Sopenharmony_ci v_budget += needed; 34458c2ecf20Sopenharmony_ci v_left -= needed; 34468c2ecf20Sopenharmony_ci 34478c2ecf20Sopenharmony_ci /* reserve one vector for flow director */ 34488c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_FD_ENA, pf->flags)) { 34498c2ecf20Sopenharmony_ci needed = ICE_FDIR_MSIX; 34508c2ecf20Sopenharmony_ci if (v_left < needed) 34518c2ecf20Sopenharmony_ci goto no_hw_vecs_left_err; 34528c2ecf20Sopenharmony_ci v_budget += needed; 34538c2ecf20Sopenharmony_ci v_left -= needed; 34548c2ecf20Sopenharmony_ci } 34558c2ecf20Sopenharmony_ci 34568c2ecf20Sopenharmony_ci pf->msix_entries = devm_kcalloc(dev, v_budget, 34578c2ecf20Sopenharmony_ci sizeof(*pf->msix_entries), GFP_KERNEL); 34588c2ecf20Sopenharmony_ci 34598c2ecf20Sopenharmony_ci if (!pf->msix_entries) { 34608c2ecf20Sopenharmony_ci err = -ENOMEM; 34618c2ecf20Sopenharmony_ci goto exit_err; 34628c2ecf20Sopenharmony_ci } 34638c2ecf20Sopenharmony_ci 34648c2ecf20Sopenharmony_ci for (i = 0; i < v_budget; i++) 34658c2ecf20Sopenharmony_ci pf->msix_entries[i].entry = i; 34668c2ecf20Sopenharmony_ci 34678c2ecf20Sopenharmony_ci /* actually reserve the vectors */ 34688c2ecf20Sopenharmony_ci v_actual = pci_enable_msix_range(pf->pdev, pf->msix_entries, 34698c2ecf20Sopenharmony_ci ICE_MIN_MSIX, v_budget); 34708c2ecf20Sopenharmony_ci 34718c2ecf20Sopenharmony_ci if (v_actual < 0) { 34728c2ecf20Sopenharmony_ci dev_err(dev, "unable to reserve MSI-X vectors\n"); 34738c2ecf20Sopenharmony_ci err = v_actual; 34748c2ecf20Sopenharmony_ci goto msix_err; 34758c2ecf20Sopenharmony_ci } 34768c2ecf20Sopenharmony_ci 34778c2ecf20Sopenharmony_ci if (v_actual < v_budget) { 34788c2ecf20Sopenharmony_ci dev_warn(dev, "not enough OS MSI-X vectors. requested = %d, obtained = %d\n", 34798c2ecf20Sopenharmony_ci v_budget, v_actual); 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_ci if (v_actual < ICE_MIN_MSIX) { 34828c2ecf20Sopenharmony_ci /* error if we can't get minimum vectors */ 34838c2ecf20Sopenharmony_ci pci_disable_msix(pf->pdev); 34848c2ecf20Sopenharmony_ci err = -ERANGE; 34858c2ecf20Sopenharmony_ci goto msix_err; 34868c2ecf20Sopenharmony_ci } else { 34878c2ecf20Sopenharmony_ci pf->num_lan_msix = ICE_MIN_LAN_TXRX_MSIX; 34888c2ecf20Sopenharmony_ci } 34898c2ecf20Sopenharmony_ci } 34908c2ecf20Sopenharmony_ci 34918c2ecf20Sopenharmony_ci return v_actual; 34928c2ecf20Sopenharmony_ci 34938c2ecf20Sopenharmony_cimsix_err: 34948c2ecf20Sopenharmony_ci devm_kfree(dev, pf->msix_entries); 34958c2ecf20Sopenharmony_ci goto exit_err; 34968c2ecf20Sopenharmony_ci 34978c2ecf20Sopenharmony_cino_hw_vecs_left_err: 34988c2ecf20Sopenharmony_ci dev_err(dev, "not enough device MSI-X vectors. requested = %d, available = %d\n", 34998c2ecf20Sopenharmony_ci needed, v_left); 35008c2ecf20Sopenharmony_ci err = -ERANGE; 35018c2ecf20Sopenharmony_ciexit_err: 35028c2ecf20Sopenharmony_ci pf->num_lan_msix = 0; 35038c2ecf20Sopenharmony_ci return err; 35048c2ecf20Sopenharmony_ci} 35058c2ecf20Sopenharmony_ci 35068c2ecf20Sopenharmony_ci/** 35078c2ecf20Sopenharmony_ci * ice_dis_msix - Disable MSI-X interrupt setup in OS 35088c2ecf20Sopenharmony_ci * @pf: board private structure 35098c2ecf20Sopenharmony_ci */ 35108c2ecf20Sopenharmony_cistatic void ice_dis_msix(struct ice_pf *pf) 35118c2ecf20Sopenharmony_ci{ 35128c2ecf20Sopenharmony_ci pci_disable_msix(pf->pdev); 35138c2ecf20Sopenharmony_ci devm_kfree(ice_pf_to_dev(pf), pf->msix_entries); 35148c2ecf20Sopenharmony_ci pf->msix_entries = NULL; 35158c2ecf20Sopenharmony_ci} 35168c2ecf20Sopenharmony_ci 35178c2ecf20Sopenharmony_ci/** 35188c2ecf20Sopenharmony_ci * ice_clear_interrupt_scheme - Undo things done by ice_init_interrupt_scheme 35198c2ecf20Sopenharmony_ci * @pf: board private structure 35208c2ecf20Sopenharmony_ci */ 35218c2ecf20Sopenharmony_cistatic void ice_clear_interrupt_scheme(struct ice_pf *pf) 35228c2ecf20Sopenharmony_ci{ 35238c2ecf20Sopenharmony_ci ice_dis_msix(pf); 35248c2ecf20Sopenharmony_ci 35258c2ecf20Sopenharmony_ci if (pf->irq_tracker) { 35268c2ecf20Sopenharmony_ci devm_kfree(ice_pf_to_dev(pf), pf->irq_tracker); 35278c2ecf20Sopenharmony_ci pf->irq_tracker = NULL; 35288c2ecf20Sopenharmony_ci } 35298c2ecf20Sopenharmony_ci} 35308c2ecf20Sopenharmony_ci 35318c2ecf20Sopenharmony_ci/** 35328c2ecf20Sopenharmony_ci * ice_init_interrupt_scheme - Determine proper interrupt scheme 35338c2ecf20Sopenharmony_ci * @pf: board private structure to initialize 35348c2ecf20Sopenharmony_ci */ 35358c2ecf20Sopenharmony_cistatic int ice_init_interrupt_scheme(struct ice_pf *pf) 35368c2ecf20Sopenharmony_ci{ 35378c2ecf20Sopenharmony_ci int vectors; 35388c2ecf20Sopenharmony_ci 35398c2ecf20Sopenharmony_ci vectors = ice_ena_msix_range(pf); 35408c2ecf20Sopenharmony_ci 35418c2ecf20Sopenharmony_ci if (vectors < 0) 35428c2ecf20Sopenharmony_ci return vectors; 35438c2ecf20Sopenharmony_ci 35448c2ecf20Sopenharmony_ci /* set up vector assignment tracking */ 35458c2ecf20Sopenharmony_ci pf->irq_tracker = 35468c2ecf20Sopenharmony_ci devm_kzalloc(ice_pf_to_dev(pf), sizeof(*pf->irq_tracker) + 35478c2ecf20Sopenharmony_ci (sizeof(u16) * vectors), GFP_KERNEL); 35488c2ecf20Sopenharmony_ci if (!pf->irq_tracker) { 35498c2ecf20Sopenharmony_ci ice_dis_msix(pf); 35508c2ecf20Sopenharmony_ci return -ENOMEM; 35518c2ecf20Sopenharmony_ci } 35528c2ecf20Sopenharmony_ci 35538c2ecf20Sopenharmony_ci /* populate SW interrupts pool with number of OS granted IRQs. */ 35548c2ecf20Sopenharmony_ci pf->num_avail_sw_msix = (u16)vectors; 35558c2ecf20Sopenharmony_ci pf->irq_tracker->num_entries = (u16)vectors; 35568c2ecf20Sopenharmony_ci pf->irq_tracker->end = pf->irq_tracker->num_entries; 35578c2ecf20Sopenharmony_ci 35588c2ecf20Sopenharmony_ci return 0; 35598c2ecf20Sopenharmony_ci} 35608c2ecf20Sopenharmony_ci 35618c2ecf20Sopenharmony_ci/** 35628c2ecf20Sopenharmony_ci * ice_is_wol_supported - check if WoL is supported 35638c2ecf20Sopenharmony_ci * @hw: pointer to hardware info 35648c2ecf20Sopenharmony_ci * 35658c2ecf20Sopenharmony_ci * Check if WoL is supported based on the HW configuration. 35668c2ecf20Sopenharmony_ci * Returns true if NVM supports and enables WoL for this port, false otherwise 35678c2ecf20Sopenharmony_ci */ 35688c2ecf20Sopenharmony_cibool ice_is_wol_supported(struct ice_hw *hw) 35698c2ecf20Sopenharmony_ci{ 35708c2ecf20Sopenharmony_ci u16 wol_ctrl; 35718c2ecf20Sopenharmony_ci 35728c2ecf20Sopenharmony_ci /* A bit set to 1 in the NVM Software Reserved Word 2 (WoL control 35738c2ecf20Sopenharmony_ci * word) indicates WoL is not supported on the corresponding PF ID. 35748c2ecf20Sopenharmony_ci */ 35758c2ecf20Sopenharmony_ci if (ice_read_sr_word(hw, ICE_SR_NVM_WOL_CFG, &wol_ctrl)) 35768c2ecf20Sopenharmony_ci return false; 35778c2ecf20Sopenharmony_ci 35788c2ecf20Sopenharmony_ci return !(BIT(hw->port_info->lport) & wol_ctrl); 35798c2ecf20Sopenharmony_ci} 35808c2ecf20Sopenharmony_ci 35818c2ecf20Sopenharmony_ci/** 35828c2ecf20Sopenharmony_ci * ice_vsi_recfg_qs - Change the number of queues on a VSI 35838c2ecf20Sopenharmony_ci * @vsi: VSI being changed 35848c2ecf20Sopenharmony_ci * @new_rx: new number of Rx queues 35858c2ecf20Sopenharmony_ci * @new_tx: new number of Tx queues 35868c2ecf20Sopenharmony_ci * 35878c2ecf20Sopenharmony_ci * Only change the number of queues if new_tx, or new_rx is non-0. 35888c2ecf20Sopenharmony_ci * 35898c2ecf20Sopenharmony_ci * Returns 0 on success. 35908c2ecf20Sopenharmony_ci */ 35918c2ecf20Sopenharmony_ciint ice_vsi_recfg_qs(struct ice_vsi *vsi, int new_rx, int new_tx) 35928c2ecf20Sopenharmony_ci{ 35938c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 35948c2ecf20Sopenharmony_ci int err = 0, timeout = 50; 35958c2ecf20Sopenharmony_ci 35968c2ecf20Sopenharmony_ci if (!new_rx && !new_tx) 35978c2ecf20Sopenharmony_ci return -EINVAL; 35988c2ecf20Sopenharmony_ci 35998c2ecf20Sopenharmony_ci while (test_and_set_bit(__ICE_CFG_BUSY, pf->state)) { 36008c2ecf20Sopenharmony_ci timeout--; 36018c2ecf20Sopenharmony_ci if (!timeout) 36028c2ecf20Sopenharmony_ci return -EBUSY; 36038c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 36048c2ecf20Sopenharmony_ci } 36058c2ecf20Sopenharmony_ci 36068c2ecf20Sopenharmony_ci if (new_tx) 36078c2ecf20Sopenharmony_ci vsi->req_txq = (u16)new_tx; 36088c2ecf20Sopenharmony_ci if (new_rx) 36098c2ecf20Sopenharmony_ci vsi->req_rxq = (u16)new_rx; 36108c2ecf20Sopenharmony_ci 36118c2ecf20Sopenharmony_ci /* set for the next time the netdev is started */ 36128c2ecf20Sopenharmony_ci if (!netif_running(vsi->netdev)) { 36138c2ecf20Sopenharmony_ci ice_vsi_rebuild(vsi, false); 36148c2ecf20Sopenharmony_ci dev_dbg(ice_pf_to_dev(pf), "Link is down, queue count change happens when link is brought up\n"); 36158c2ecf20Sopenharmony_ci goto done; 36168c2ecf20Sopenharmony_ci } 36178c2ecf20Sopenharmony_ci 36188c2ecf20Sopenharmony_ci ice_vsi_close(vsi); 36198c2ecf20Sopenharmony_ci ice_vsi_rebuild(vsi, false); 36208c2ecf20Sopenharmony_ci ice_pf_dcb_recfg(pf); 36218c2ecf20Sopenharmony_ci ice_vsi_open(vsi); 36228c2ecf20Sopenharmony_cidone: 36238c2ecf20Sopenharmony_ci clear_bit(__ICE_CFG_BUSY, pf->state); 36248c2ecf20Sopenharmony_ci return err; 36258c2ecf20Sopenharmony_ci} 36268c2ecf20Sopenharmony_ci 36278c2ecf20Sopenharmony_ci/** 36288c2ecf20Sopenharmony_ci * ice_set_safe_mode_vlan_cfg - configure PF VSI to allow all VLANs in safe mode 36298c2ecf20Sopenharmony_ci * @pf: PF to configure 36308c2ecf20Sopenharmony_ci * 36318c2ecf20Sopenharmony_ci * No VLAN offloads/filtering are advertised in safe mode so make sure the PF 36328c2ecf20Sopenharmony_ci * VSI can still Tx/Rx VLAN tagged packets. 36338c2ecf20Sopenharmony_ci */ 36348c2ecf20Sopenharmony_cistatic void ice_set_safe_mode_vlan_cfg(struct ice_pf *pf) 36358c2ecf20Sopenharmony_ci{ 36368c2ecf20Sopenharmony_ci struct ice_vsi *vsi = ice_get_main_vsi(pf); 36378c2ecf20Sopenharmony_ci struct ice_vsi_ctx *ctxt; 36388c2ecf20Sopenharmony_ci enum ice_status status; 36398c2ecf20Sopenharmony_ci struct ice_hw *hw; 36408c2ecf20Sopenharmony_ci 36418c2ecf20Sopenharmony_ci if (!vsi) 36428c2ecf20Sopenharmony_ci return; 36438c2ecf20Sopenharmony_ci 36448c2ecf20Sopenharmony_ci ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); 36458c2ecf20Sopenharmony_ci if (!ctxt) 36468c2ecf20Sopenharmony_ci return; 36478c2ecf20Sopenharmony_ci 36488c2ecf20Sopenharmony_ci hw = &pf->hw; 36498c2ecf20Sopenharmony_ci ctxt->info = vsi->info; 36508c2ecf20Sopenharmony_ci 36518c2ecf20Sopenharmony_ci ctxt->info.valid_sections = 36528c2ecf20Sopenharmony_ci cpu_to_le16(ICE_AQ_VSI_PROP_VLAN_VALID | 36538c2ecf20Sopenharmony_ci ICE_AQ_VSI_PROP_SECURITY_VALID | 36548c2ecf20Sopenharmony_ci ICE_AQ_VSI_PROP_SW_VALID); 36558c2ecf20Sopenharmony_ci 36568c2ecf20Sopenharmony_ci /* disable VLAN anti-spoof */ 36578c2ecf20Sopenharmony_ci ctxt->info.sec_flags &= ~(ICE_AQ_VSI_SEC_TX_VLAN_PRUNE_ENA << 36588c2ecf20Sopenharmony_ci ICE_AQ_VSI_SEC_TX_PRUNE_ENA_S); 36598c2ecf20Sopenharmony_ci 36608c2ecf20Sopenharmony_ci /* disable VLAN pruning and keep all other settings */ 36618c2ecf20Sopenharmony_ci ctxt->info.sw_flags2 &= ~ICE_AQ_VSI_SW_FLAG_RX_VLAN_PRUNE_ENA; 36628c2ecf20Sopenharmony_ci 36638c2ecf20Sopenharmony_ci /* allow all VLANs on Tx and don't strip on Rx */ 36648c2ecf20Sopenharmony_ci ctxt->info.vlan_flags = ICE_AQ_VSI_VLAN_MODE_ALL | 36658c2ecf20Sopenharmony_ci ICE_AQ_VSI_VLAN_EMOD_NOTHING; 36668c2ecf20Sopenharmony_ci 36678c2ecf20Sopenharmony_ci status = ice_update_vsi(hw, vsi->idx, ctxt, NULL); 36688c2ecf20Sopenharmony_ci if (status) { 36698c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "Failed to update VSI for safe mode VLANs, err %s aq_err %s\n", 36708c2ecf20Sopenharmony_ci ice_stat_str(status), 36718c2ecf20Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 36728c2ecf20Sopenharmony_ci } else { 36738c2ecf20Sopenharmony_ci vsi->info.sec_flags = ctxt->info.sec_flags; 36748c2ecf20Sopenharmony_ci vsi->info.sw_flags2 = ctxt->info.sw_flags2; 36758c2ecf20Sopenharmony_ci vsi->info.vlan_flags = ctxt->info.vlan_flags; 36768c2ecf20Sopenharmony_ci } 36778c2ecf20Sopenharmony_ci 36788c2ecf20Sopenharmony_ci kfree(ctxt); 36798c2ecf20Sopenharmony_ci} 36808c2ecf20Sopenharmony_ci 36818c2ecf20Sopenharmony_ci/** 36828c2ecf20Sopenharmony_ci * ice_log_pkg_init - log result of DDP package load 36838c2ecf20Sopenharmony_ci * @hw: pointer to hardware info 36848c2ecf20Sopenharmony_ci * @status: status of package load 36858c2ecf20Sopenharmony_ci */ 36868c2ecf20Sopenharmony_cistatic void 36878c2ecf20Sopenharmony_ciice_log_pkg_init(struct ice_hw *hw, enum ice_status *status) 36888c2ecf20Sopenharmony_ci{ 36898c2ecf20Sopenharmony_ci struct ice_pf *pf = (struct ice_pf *)hw->back; 36908c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 36918c2ecf20Sopenharmony_ci 36928c2ecf20Sopenharmony_ci switch (*status) { 36938c2ecf20Sopenharmony_ci case ICE_SUCCESS: 36948c2ecf20Sopenharmony_ci /* The package download AdminQ command returned success because 36958c2ecf20Sopenharmony_ci * this download succeeded or ICE_ERR_AQ_NO_WORK since there is 36968c2ecf20Sopenharmony_ci * already a package loaded on the device. 36978c2ecf20Sopenharmony_ci */ 36988c2ecf20Sopenharmony_ci if (hw->pkg_ver.major == hw->active_pkg_ver.major && 36998c2ecf20Sopenharmony_ci hw->pkg_ver.minor == hw->active_pkg_ver.minor && 37008c2ecf20Sopenharmony_ci hw->pkg_ver.update == hw->active_pkg_ver.update && 37018c2ecf20Sopenharmony_ci hw->pkg_ver.draft == hw->active_pkg_ver.draft && 37028c2ecf20Sopenharmony_ci !memcmp(hw->pkg_name, hw->active_pkg_name, 37038c2ecf20Sopenharmony_ci sizeof(hw->pkg_name))) { 37048c2ecf20Sopenharmony_ci if (hw->pkg_dwnld_status == ICE_AQ_RC_EEXIST) 37058c2ecf20Sopenharmony_ci dev_info(dev, "DDP package already present on device: %s version %d.%d.%d.%d\n", 37068c2ecf20Sopenharmony_ci hw->active_pkg_name, 37078c2ecf20Sopenharmony_ci hw->active_pkg_ver.major, 37088c2ecf20Sopenharmony_ci hw->active_pkg_ver.minor, 37098c2ecf20Sopenharmony_ci hw->active_pkg_ver.update, 37108c2ecf20Sopenharmony_ci hw->active_pkg_ver.draft); 37118c2ecf20Sopenharmony_ci else 37128c2ecf20Sopenharmony_ci dev_info(dev, "The DDP package was successfully loaded: %s version %d.%d.%d.%d\n", 37138c2ecf20Sopenharmony_ci hw->active_pkg_name, 37148c2ecf20Sopenharmony_ci hw->active_pkg_ver.major, 37158c2ecf20Sopenharmony_ci hw->active_pkg_ver.minor, 37168c2ecf20Sopenharmony_ci hw->active_pkg_ver.update, 37178c2ecf20Sopenharmony_ci hw->active_pkg_ver.draft); 37188c2ecf20Sopenharmony_ci } else if (hw->active_pkg_ver.major != ICE_PKG_SUPP_VER_MAJ || 37198c2ecf20Sopenharmony_ci hw->active_pkg_ver.minor != ICE_PKG_SUPP_VER_MNR) { 37208c2ecf20Sopenharmony_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", 37218c2ecf20Sopenharmony_ci hw->active_pkg_name, 37228c2ecf20Sopenharmony_ci hw->active_pkg_ver.major, 37238c2ecf20Sopenharmony_ci hw->active_pkg_ver.minor, 37248c2ecf20Sopenharmony_ci ICE_PKG_SUPP_VER_MAJ, ICE_PKG_SUPP_VER_MNR); 37258c2ecf20Sopenharmony_ci *status = ICE_ERR_NOT_SUPPORTED; 37268c2ecf20Sopenharmony_ci } else if (hw->active_pkg_ver.major == ICE_PKG_SUPP_VER_MAJ && 37278c2ecf20Sopenharmony_ci hw->active_pkg_ver.minor == ICE_PKG_SUPP_VER_MNR) { 37288c2ecf20Sopenharmony_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", 37298c2ecf20Sopenharmony_ci hw->active_pkg_name, 37308c2ecf20Sopenharmony_ci hw->active_pkg_ver.major, 37318c2ecf20Sopenharmony_ci hw->active_pkg_ver.minor, 37328c2ecf20Sopenharmony_ci hw->active_pkg_ver.update, 37338c2ecf20Sopenharmony_ci hw->active_pkg_ver.draft, 37348c2ecf20Sopenharmony_ci hw->pkg_name, 37358c2ecf20Sopenharmony_ci hw->pkg_ver.major, 37368c2ecf20Sopenharmony_ci hw->pkg_ver.minor, 37378c2ecf20Sopenharmony_ci hw->pkg_ver.update, 37388c2ecf20Sopenharmony_ci hw->pkg_ver.draft); 37398c2ecf20Sopenharmony_ci } else { 37408c2ecf20Sopenharmony_ci dev_err(dev, "An unknown error occurred when loading the DDP package, please reboot the system. If the problem persists, update the NVM. Entering Safe Mode.\n"); 37418c2ecf20Sopenharmony_ci *status = ICE_ERR_NOT_SUPPORTED; 37428c2ecf20Sopenharmony_ci } 37438c2ecf20Sopenharmony_ci break; 37448c2ecf20Sopenharmony_ci case ICE_ERR_FW_DDP_MISMATCH: 37458c2ecf20Sopenharmony_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"); 37468c2ecf20Sopenharmony_ci break; 37478c2ecf20Sopenharmony_ci case ICE_ERR_BUF_TOO_SHORT: 37488c2ecf20Sopenharmony_ci case ICE_ERR_CFG: 37498c2ecf20Sopenharmony_ci dev_err(dev, "The DDP package file is invalid. Entering Safe Mode.\n"); 37508c2ecf20Sopenharmony_ci break; 37518c2ecf20Sopenharmony_ci case ICE_ERR_NOT_SUPPORTED: 37528c2ecf20Sopenharmony_ci /* Package File version not supported */ 37538c2ecf20Sopenharmony_ci if (hw->pkg_ver.major > ICE_PKG_SUPP_VER_MAJ || 37548c2ecf20Sopenharmony_ci (hw->pkg_ver.major == ICE_PKG_SUPP_VER_MAJ && 37558c2ecf20Sopenharmony_ci hw->pkg_ver.minor > ICE_PKG_SUPP_VER_MNR)) 37568c2ecf20Sopenharmony_ci dev_err(dev, "The DDP package file version is higher than the driver supports. Please use an updated driver. Entering Safe Mode.\n"); 37578c2ecf20Sopenharmony_ci else if (hw->pkg_ver.major < ICE_PKG_SUPP_VER_MAJ || 37588c2ecf20Sopenharmony_ci (hw->pkg_ver.major == ICE_PKG_SUPP_VER_MAJ && 37598c2ecf20Sopenharmony_ci hw->pkg_ver.minor < ICE_PKG_SUPP_VER_MNR)) 37608c2ecf20Sopenharmony_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", 37618c2ecf20Sopenharmony_ci ICE_PKG_SUPP_VER_MAJ, ICE_PKG_SUPP_VER_MNR); 37628c2ecf20Sopenharmony_ci break; 37638c2ecf20Sopenharmony_ci case ICE_ERR_AQ_ERROR: 37648c2ecf20Sopenharmony_ci switch (hw->pkg_dwnld_status) { 37658c2ecf20Sopenharmony_ci case ICE_AQ_RC_ENOSEC: 37668c2ecf20Sopenharmony_ci case ICE_AQ_RC_EBADSIG: 37678c2ecf20Sopenharmony_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"); 37688c2ecf20Sopenharmony_ci return; 37698c2ecf20Sopenharmony_ci case ICE_AQ_RC_ESVN: 37708c2ecf20Sopenharmony_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"); 37718c2ecf20Sopenharmony_ci return; 37728c2ecf20Sopenharmony_ci case ICE_AQ_RC_EBADMAN: 37738c2ecf20Sopenharmony_ci case ICE_AQ_RC_EBADBUF: 37748c2ecf20Sopenharmony_ci dev_err(dev, "An error occurred on the device while loading the DDP package. The device will be reset.\n"); 37758c2ecf20Sopenharmony_ci /* poll for reset to complete */ 37768c2ecf20Sopenharmony_ci if (ice_check_reset(hw)) 37778c2ecf20Sopenharmony_ci dev_err(dev, "Error resetting device. Please reload the driver\n"); 37788c2ecf20Sopenharmony_ci return; 37798c2ecf20Sopenharmony_ci default: 37808c2ecf20Sopenharmony_ci break; 37818c2ecf20Sopenharmony_ci } 37828c2ecf20Sopenharmony_ci fallthrough; 37838c2ecf20Sopenharmony_ci default: 37848c2ecf20Sopenharmony_ci dev_err(dev, "An unknown error (%d) occurred when loading the DDP package. Entering Safe Mode.\n", 37858c2ecf20Sopenharmony_ci *status); 37868c2ecf20Sopenharmony_ci break; 37878c2ecf20Sopenharmony_ci } 37888c2ecf20Sopenharmony_ci} 37898c2ecf20Sopenharmony_ci 37908c2ecf20Sopenharmony_ci/** 37918c2ecf20Sopenharmony_ci * ice_load_pkg - load/reload the DDP Package file 37928c2ecf20Sopenharmony_ci * @firmware: firmware structure when firmware requested or NULL for reload 37938c2ecf20Sopenharmony_ci * @pf: pointer to the PF instance 37948c2ecf20Sopenharmony_ci * 37958c2ecf20Sopenharmony_ci * Called on probe and post CORER/GLOBR rebuild to load DDP Package and 37968c2ecf20Sopenharmony_ci * initialize HW tables. 37978c2ecf20Sopenharmony_ci */ 37988c2ecf20Sopenharmony_cistatic void 37998c2ecf20Sopenharmony_ciice_load_pkg(const struct firmware *firmware, struct ice_pf *pf) 38008c2ecf20Sopenharmony_ci{ 38018c2ecf20Sopenharmony_ci enum ice_status status = ICE_ERR_PARAM; 38028c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 38038c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 38048c2ecf20Sopenharmony_ci 38058c2ecf20Sopenharmony_ci /* Load DDP Package */ 38068c2ecf20Sopenharmony_ci if (firmware && !hw->pkg_copy) { 38078c2ecf20Sopenharmony_ci status = ice_copy_and_init_pkg(hw, firmware->data, 38088c2ecf20Sopenharmony_ci firmware->size); 38098c2ecf20Sopenharmony_ci ice_log_pkg_init(hw, &status); 38108c2ecf20Sopenharmony_ci } else if (!firmware && hw->pkg_copy) { 38118c2ecf20Sopenharmony_ci /* Reload package during rebuild after CORER/GLOBR reset */ 38128c2ecf20Sopenharmony_ci status = ice_init_pkg(hw, hw->pkg_copy, hw->pkg_size); 38138c2ecf20Sopenharmony_ci ice_log_pkg_init(hw, &status); 38148c2ecf20Sopenharmony_ci } else { 38158c2ecf20Sopenharmony_ci dev_err(dev, "The DDP package file failed to load. Entering Safe Mode.\n"); 38168c2ecf20Sopenharmony_ci } 38178c2ecf20Sopenharmony_ci 38188c2ecf20Sopenharmony_ci if (status) { 38198c2ecf20Sopenharmony_ci /* Safe Mode */ 38208c2ecf20Sopenharmony_ci clear_bit(ICE_FLAG_ADV_FEATURES, pf->flags); 38218c2ecf20Sopenharmony_ci return; 38228c2ecf20Sopenharmony_ci } 38238c2ecf20Sopenharmony_ci 38248c2ecf20Sopenharmony_ci /* Successful download package is the precondition for advanced 38258c2ecf20Sopenharmony_ci * features, hence setting the ICE_FLAG_ADV_FEATURES flag 38268c2ecf20Sopenharmony_ci */ 38278c2ecf20Sopenharmony_ci set_bit(ICE_FLAG_ADV_FEATURES, pf->flags); 38288c2ecf20Sopenharmony_ci} 38298c2ecf20Sopenharmony_ci 38308c2ecf20Sopenharmony_ci/** 38318c2ecf20Sopenharmony_ci * ice_verify_cacheline_size - verify driver's assumption of 64 Byte cache lines 38328c2ecf20Sopenharmony_ci * @pf: pointer to the PF structure 38338c2ecf20Sopenharmony_ci * 38348c2ecf20Sopenharmony_ci * There is no error returned here because the driver should be able to handle 38358c2ecf20Sopenharmony_ci * 128 Byte cache lines, so we only print a warning in case issues are seen, 38368c2ecf20Sopenharmony_ci * specifically with Tx. 38378c2ecf20Sopenharmony_ci */ 38388c2ecf20Sopenharmony_cistatic void ice_verify_cacheline_size(struct ice_pf *pf) 38398c2ecf20Sopenharmony_ci{ 38408c2ecf20Sopenharmony_ci if (rd32(&pf->hw, GLPCI_CNF2) & GLPCI_CNF2_CACHELINE_SIZE_M) 38418c2ecf20Sopenharmony_ci dev_warn(ice_pf_to_dev(pf), "%d Byte cache line assumption is invalid, driver may have Tx timeouts!\n", 38428c2ecf20Sopenharmony_ci ICE_CACHE_LINE_BYTES); 38438c2ecf20Sopenharmony_ci} 38448c2ecf20Sopenharmony_ci 38458c2ecf20Sopenharmony_ci/** 38468c2ecf20Sopenharmony_ci * ice_send_version - update firmware with driver version 38478c2ecf20Sopenharmony_ci * @pf: PF struct 38488c2ecf20Sopenharmony_ci * 38498c2ecf20Sopenharmony_ci * Returns ICE_SUCCESS on success, else error code 38508c2ecf20Sopenharmony_ci */ 38518c2ecf20Sopenharmony_cistatic enum ice_status ice_send_version(struct ice_pf *pf) 38528c2ecf20Sopenharmony_ci{ 38538c2ecf20Sopenharmony_ci struct ice_driver_ver dv; 38548c2ecf20Sopenharmony_ci 38558c2ecf20Sopenharmony_ci dv.major_ver = 0xff; 38568c2ecf20Sopenharmony_ci dv.minor_ver = 0xff; 38578c2ecf20Sopenharmony_ci dv.build_ver = 0xff; 38588c2ecf20Sopenharmony_ci dv.subbuild_ver = 0; 38598c2ecf20Sopenharmony_ci strscpy((char *)dv.driver_string, UTS_RELEASE, 38608c2ecf20Sopenharmony_ci sizeof(dv.driver_string)); 38618c2ecf20Sopenharmony_ci return ice_aq_send_driver_ver(&pf->hw, &dv, NULL); 38628c2ecf20Sopenharmony_ci} 38638c2ecf20Sopenharmony_ci 38648c2ecf20Sopenharmony_ci/** 38658c2ecf20Sopenharmony_ci * ice_init_fdir - Initialize flow director VSI and configuration 38668c2ecf20Sopenharmony_ci * @pf: pointer to the PF instance 38678c2ecf20Sopenharmony_ci * 38688c2ecf20Sopenharmony_ci * returns 0 on success, negative on error 38698c2ecf20Sopenharmony_ci */ 38708c2ecf20Sopenharmony_cistatic int ice_init_fdir(struct ice_pf *pf) 38718c2ecf20Sopenharmony_ci{ 38728c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 38738c2ecf20Sopenharmony_ci struct ice_vsi *ctrl_vsi; 38748c2ecf20Sopenharmony_ci int err; 38758c2ecf20Sopenharmony_ci 38768c2ecf20Sopenharmony_ci /* Side Band Flow Director needs to have a control VSI. 38778c2ecf20Sopenharmony_ci * Allocate it and store it in the PF. 38788c2ecf20Sopenharmony_ci */ 38798c2ecf20Sopenharmony_ci ctrl_vsi = ice_ctrl_vsi_setup(pf, pf->hw.port_info); 38808c2ecf20Sopenharmony_ci if (!ctrl_vsi) { 38818c2ecf20Sopenharmony_ci dev_dbg(dev, "could not create control VSI\n"); 38828c2ecf20Sopenharmony_ci return -ENOMEM; 38838c2ecf20Sopenharmony_ci } 38848c2ecf20Sopenharmony_ci 38858c2ecf20Sopenharmony_ci err = ice_vsi_open_ctrl(ctrl_vsi); 38868c2ecf20Sopenharmony_ci if (err) { 38878c2ecf20Sopenharmony_ci dev_dbg(dev, "could not open control VSI\n"); 38888c2ecf20Sopenharmony_ci goto err_vsi_open; 38898c2ecf20Sopenharmony_ci } 38908c2ecf20Sopenharmony_ci 38918c2ecf20Sopenharmony_ci mutex_init(&pf->hw.fdir_fltr_lock); 38928c2ecf20Sopenharmony_ci 38938c2ecf20Sopenharmony_ci err = ice_fdir_create_dflt_rules(pf); 38948c2ecf20Sopenharmony_ci if (err) 38958c2ecf20Sopenharmony_ci goto err_fdir_rule; 38968c2ecf20Sopenharmony_ci 38978c2ecf20Sopenharmony_ci return 0; 38988c2ecf20Sopenharmony_ci 38998c2ecf20Sopenharmony_cierr_fdir_rule: 39008c2ecf20Sopenharmony_ci ice_fdir_release_flows(&pf->hw); 39018c2ecf20Sopenharmony_ci ice_vsi_close(ctrl_vsi); 39028c2ecf20Sopenharmony_cierr_vsi_open: 39038c2ecf20Sopenharmony_ci ice_vsi_release(ctrl_vsi); 39048c2ecf20Sopenharmony_ci if (pf->ctrl_vsi_idx != ICE_NO_VSI) { 39058c2ecf20Sopenharmony_ci pf->vsi[pf->ctrl_vsi_idx] = NULL; 39068c2ecf20Sopenharmony_ci pf->ctrl_vsi_idx = ICE_NO_VSI; 39078c2ecf20Sopenharmony_ci } 39088c2ecf20Sopenharmony_ci return err; 39098c2ecf20Sopenharmony_ci} 39108c2ecf20Sopenharmony_ci 39118c2ecf20Sopenharmony_ci/** 39128c2ecf20Sopenharmony_ci * ice_get_opt_fw_name - return optional firmware file name or NULL 39138c2ecf20Sopenharmony_ci * @pf: pointer to the PF instance 39148c2ecf20Sopenharmony_ci */ 39158c2ecf20Sopenharmony_cistatic char *ice_get_opt_fw_name(struct ice_pf *pf) 39168c2ecf20Sopenharmony_ci{ 39178c2ecf20Sopenharmony_ci /* Optional firmware name same as default with additional dash 39188c2ecf20Sopenharmony_ci * followed by a EUI-64 identifier (PCIe Device Serial Number) 39198c2ecf20Sopenharmony_ci */ 39208c2ecf20Sopenharmony_ci struct pci_dev *pdev = pf->pdev; 39218c2ecf20Sopenharmony_ci char *opt_fw_filename; 39228c2ecf20Sopenharmony_ci u64 dsn; 39238c2ecf20Sopenharmony_ci 39248c2ecf20Sopenharmony_ci /* Determine the name of the optional file using the DSN (two 39258c2ecf20Sopenharmony_ci * dwords following the start of the DSN Capability). 39268c2ecf20Sopenharmony_ci */ 39278c2ecf20Sopenharmony_ci dsn = pci_get_dsn(pdev); 39288c2ecf20Sopenharmony_ci if (!dsn) 39298c2ecf20Sopenharmony_ci return NULL; 39308c2ecf20Sopenharmony_ci 39318c2ecf20Sopenharmony_ci opt_fw_filename = kzalloc(NAME_MAX, GFP_KERNEL); 39328c2ecf20Sopenharmony_ci if (!opt_fw_filename) 39338c2ecf20Sopenharmony_ci return NULL; 39348c2ecf20Sopenharmony_ci 39358c2ecf20Sopenharmony_ci snprintf(opt_fw_filename, NAME_MAX, "%sice-%016llx.pkg", 39368c2ecf20Sopenharmony_ci ICE_DDP_PKG_PATH, dsn); 39378c2ecf20Sopenharmony_ci 39388c2ecf20Sopenharmony_ci return opt_fw_filename; 39398c2ecf20Sopenharmony_ci} 39408c2ecf20Sopenharmony_ci 39418c2ecf20Sopenharmony_ci/** 39428c2ecf20Sopenharmony_ci * ice_request_fw - Device initialization routine 39438c2ecf20Sopenharmony_ci * @pf: pointer to the PF instance 39448c2ecf20Sopenharmony_ci */ 39458c2ecf20Sopenharmony_cistatic void ice_request_fw(struct ice_pf *pf) 39468c2ecf20Sopenharmony_ci{ 39478c2ecf20Sopenharmony_ci char *opt_fw_filename = ice_get_opt_fw_name(pf); 39488c2ecf20Sopenharmony_ci const struct firmware *firmware = NULL; 39498c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 39508c2ecf20Sopenharmony_ci int err = 0; 39518c2ecf20Sopenharmony_ci 39528c2ecf20Sopenharmony_ci /* optional device-specific DDP (if present) overrides the default DDP 39538c2ecf20Sopenharmony_ci * package file. kernel logs a debug message if the file doesn't exist, 39548c2ecf20Sopenharmony_ci * and warning messages for other errors. 39558c2ecf20Sopenharmony_ci */ 39568c2ecf20Sopenharmony_ci if (opt_fw_filename) { 39578c2ecf20Sopenharmony_ci err = firmware_request_nowarn(&firmware, opt_fw_filename, dev); 39588c2ecf20Sopenharmony_ci if (err) { 39598c2ecf20Sopenharmony_ci kfree(opt_fw_filename); 39608c2ecf20Sopenharmony_ci goto dflt_pkg_load; 39618c2ecf20Sopenharmony_ci } 39628c2ecf20Sopenharmony_ci 39638c2ecf20Sopenharmony_ci /* request for firmware was successful. Download to device */ 39648c2ecf20Sopenharmony_ci ice_load_pkg(firmware, pf); 39658c2ecf20Sopenharmony_ci kfree(opt_fw_filename); 39668c2ecf20Sopenharmony_ci release_firmware(firmware); 39678c2ecf20Sopenharmony_ci return; 39688c2ecf20Sopenharmony_ci } 39698c2ecf20Sopenharmony_ci 39708c2ecf20Sopenharmony_cidflt_pkg_load: 39718c2ecf20Sopenharmony_ci err = request_firmware(&firmware, ICE_DDP_PKG_FILE, dev); 39728c2ecf20Sopenharmony_ci if (err) { 39738c2ecf20Sopenharmony_ci dev_err(dev, "The DDP package file was not found or could not be read. Entering Safe Mode\n"); 39748c2ecf20Sopenharmony_ci return; 39758c2ecf20Sopenharmony_ci } 39768c2ecf20Sopenharmony_ci 39778c2ecf20Sopenharmony_ci /* request for firmware was successful. Download to device */ 39788c2ecf20Sopenharmony_ci ice_load_pkg(firmware, pf); 39798c2ecf20Sopenharmony_ci release_firmware(firmware); 39808c2ecf20Sopenharmony_ci} 39818c2ecf20Sopenharmony_ci 39828c2ecf20Sopenharmony_ci/** 39838c2ecf20Sopenharmony_ci * ice_print_wake_reason - show the wake up cause in the log 39848c2ecf20Sopenharmony_ci * @pf: pointer to the PF struct 39858c2ecf20Sopenharmony_ci */ 39868c2ecf20Sopenharmony_cistatic void ice_print_wake_reason(struct ice_pf *pf) 39878c2ecf20Sopenharmony_ci{ 39888c2ecf20Sopenharmony_ci u32 wus = pf->wakeup_reason; 39898c2ecf20Sopenharmony_ci const char *wake_str; 39908c2ecf20Sopenharmony_ci 39918c2ecf20Sopenharmony_ci /* if no wake event, nothing to print */ 39928c2ecf20Sopenharmony_ci if (!wus) 39938c2ecf20Sopenharmony_ci return; 39948c2ecf20Sopenharmony_ci 39958c2ecf20Sopenharmony_ci if (wus & PFPM_WUS_LNKC_M) 39968c2ecf20Sopenharmony_ci wake_str = "Link\n"; 39978c2ecf20Sopenharmony_ci else if (wus & PFPM_WUS_MAG_M) 39988c2ecf20Sopenharmony_ci wake_str = "Magic Packet\n"; 39998c2ecf20Sopenharmony_ci else if (wus & PFPM_WUS_MNG_M) 40008c2ecf20Sopenharmony_ci wake_str = "Management\n"; 40018c2ecf20Sopenharmony_ci else if (wus & PFPM_WUS_FW_RST_WK_M) 40028c2ecf20Sopenharmony_ci wake_str = "Firmware Reset\n"; 40038c2ecf20Sopenharmony_ci else 40048c2ecf20Sopenharmony_ci wake_str = "Unknown\n"; 40058c2ecf20Sopenharmony_ci 40068c2ecf20Sopenharmony_ci dev_info(ice_pf_to_dev(pf), "Wake reason: %s", wake_str); 40078c2ecf20Sopenharmony_ci} 40088c2ecf20Sopenharmony_ci 40098c2ecf20Sopenharmony_ci/** 40108c2ecf20Sopenharmony_ci * ice_probe - Device initialization routine 40118c2ecf20Sopenharmony_ci * @pdev: PCI device information struct 40128c2ecf20Sopenharmony_ci * @ent: entry in ice_pci_tbl 40138c2ecf20Sopenharmony_ci * 40148c2ecf20Sopenharmony_ci * Returns 0 on success, negative on failure 40158c2ecf20Sopenharmony_ci */ 40168c2ecf20Sopenharmony_cistatic int 40178c2ecf20Sopenharmony_ciice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent) 40188c2ecf20Sopenharmony_ci{ 40198c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 40208c2ecf20Sopenharmony_ci struct ice_pf *pf; 40218c2ecf20Sopenharmony_ci struct ice_hw *hw; 40228c2ecf20Sopenharmony_ci int i, err; 40238c2ecf20Sopenharmony_ci 40248c2ecf20Sopenharmony_ci if (pdev->is_virtfn) { 40258c2ecf20Sopenharmony_ci dev_err(dev, "can't probe a virtual function\n"); 40268c2ecf20Sopenharmony_ci return -EINVAL; 40278c2ecf20Sopenharmony_ci } 40288c2ecf20Sopenharmony_ci 40298c2ecf20Sopenharmony_ci /* when under a kdump kernel initiate a reset before enabling the 40308c2ecf20Sopenharmony_ci * device in order to clear out any pending DMA transactions. These 40318c2ecf20Sopenharmony_ci * transactions can cause some systems to machine check when doing 40328c2ecf20Sopenharmony_ci * the pcim_enable_device() below. 40338c2ecf20Sopenharmony_ci */ 40348c2ecf20Sopenharmony_ci if (is_kdump_kernel()) { 40358c2ecf20Sopenharmony_ci pci_save_state(pdev); 40368c2ecf20Sopenharmony_ci pci_clear_master(pdev); 40378c2ecf20Sopenharmony_ci err = pcie_flr(pdev); 40388c2ecf20Sopenharmony_ci if (err) 40398c2ecf20Sopenharmony_ci return err; 40408c2ecf20Sopenharmony_ci pci_restore_state(pdev); 40418c2ecf20Sopenharmony_ci } 40428c2ecf20Sopenharmony_ci 40438c2ecf20Sopenharmony_ci /* this driver uses devres, see 40448c2ecf20Sopenharmony_ci * Documentation/driver-api/driver-model/devres.rst 40458c2ecf20Sopenharmony_ci */ 40468c2ecf20Sopenharmony_ci err = pcim_enable_device(pdev); 40478c2ecf20Sopenharmony_ci if (err) 40488c2ecf20Sopenharmony_ci return err; 40498c2ecf20Sopenharmony_ci 40508c2ecf20Sopenharmony_ci err = pcim_iomap_regions(pdev, BIT(ICE_BAR0), pci_name(pdev)); 40518c2ecf20Sopenharmony_ci if (err) { 40528c2ecf20Sopenharmony_ci dev_err(dev, "BAR0 I/O map error %d\n", err); 40538c2ecf20Sopenharmony_ci return err; 40548c2ecf20Sopenharmony_ci } 40558c2ecf20Sopenharmony_ci 40568c2ecf20Sopenharmony_ci pf = ice_allocate_pf(dev); 40578c2ecf20Sopenharmony_ci if (!pf) 40588c2ecf20Sopenharmony_ci return -ENOMEM; 40598c2ecf20Sopenharmony_ci 40608c2ecf20Sopenharmony_ci /* set up for high or low DMA */ 40618c2ecf20Sopenharmony_ci err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); 40628c2ecf20Sopenharmony_ci if (err) 40638c2ecf20Sopenharmony_ci err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); 40648c2ecf20Sopenharmony_ci if (err) { 40658c2ecf20Sopenharmony_ci dev_err(dev, "DMA configuration failed: 0x%x\n", err); 40668c2ecf20Sopenharmony_ci return err; 40678c2ecf20Sopenharmony_ci } 40688c2ecf20Sopenharmony_ci 40698c2ecf20Sopenharmony_ci pci_enable_pcie_error_reporting(pdev); 40708c2ecf20Sopenharmony_ci pci_set_master(pdev); 40718c2ecf20Sopenharmony_ci 40728c2ecf20Sopenharmony_ci pf->pdev = pdev; 40738c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, pf); 40748c2ecf20Sopenharmony_ci set_bit(__ICE_DOWN, pf->state); 40758c2ecf20Sopenharmony_ci /* Disable service task until DOWN bit is cleared */ 40768c2ecf20Sopenharmony_ci set_bit(__ICE_SERVICE_DIS, pf->state); 40778c2ecf20Sopenharmony_ci 40788c2ecf20Sopenharmony_ci hw = &pf->hw; 40798c2ecf20Sopenharmony_ci hw->hw_addr = pcim_iomap_table(pdev)[ICE_BAR0]; 40808c2ecf20Sopenharmony_ci pci_save_state(pdev); 40818c2ecf20Sopenharmony_ci 40828c2ecf20Sopenharmony_ci hw->back = pf; 40838c2ecf20Sopenharmony_ci hw->vendor_id = pdev->vendor; 40848c2ecf20Sopenharmony_ci hw->device_id = pdev->device; 40858c2ecf20Sopenharmony_ci pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id); 40868c2ecf20Sopenharmony_ci hw->subsystem_vendor_id = pdev->subsystem_vendor; 40878c2ecf20Sopenharmony_ci hw->subsystem_device_id = pdev->subsystem_device; 40888c2ecf20Sopenharmony_ci hw->bus.device = PCI_SLOT(pdev->devfn); 40898c2ecf20Sopenharmony_ci hw->bus.func = PCI_FUNC(pdev->devfn); 40908c2ecf20Sopenharmony_ci ice_set_ctrlq_len(hw); 40918c2ecf20Sopenharmony_ci 40928c2ecf20Sopenharmony_ci pf->msg_enable = netif_msg_init(debug, ICE_DFLT_NETIF_M); 40938c2ecf20Sopenharmony_ci 40948c2ecf20Sopenharmony_ci err = ice_devlink_register(pf); 40958c2ecf20Sopenharmony_ci if (err) { 40968c2ecf20Sopenharmony_ci dev_err(dev, "ice_devlink_register failed: %d\n", err); 40978c2ecf20Sopenharmony_ci goto err_exit_unroll; 40988c2ecf20Sopenharmony_ci } 40998c2ecf20Sopenharmony_ci 41008c2ecf20Sopenharmony_ci#ifndef CONFIG_DYNAMIC_DEBUG 41018c2ecf20Sopenharmony_ci if (debug < -1) 41028c2ecf20Sopenharmony_ci hw->debug_mask = debug; 41038c2ecf20Sopenharmony_ci#endif 41048c2ecf20Sopenharmony_ci 41058c2ecf20Sopenharmony_ci err = ice_init_hw(hw); 41068c2ecf20Sopenharmony_ci if (err) { 41078c2ecf20Sopenharmony_ci dev_err(dev, "ice_init_hw failed: %d\n", err); 41088c2ecf20Sopenharmony_ci err = -EIO; 41098c2ecf20Sopenharmony_ci goto err_exit_unroll; 41108c2ecf20Sopenharmony_ci } 41118c2ecf20Sopenharmony_ci 41128c2ecf20Sopenharmony_ci ice_request_fw(pf); 41138c2ecf20Sopenharmony_ci 41148c2ecf20Sopenharmony_ci /* if ice_request_fw fails, ICE_FLAG_ADV_FEATURES bit won't be 41158c2ecf20Sopenharmony_ci * set in pf->state, which will cause ice_is_safe_mode to return 41168c2ecf20Sopenharmony_ci * true 41178c2ecf20Sopenharmony_ci */ 41188c2ecf20Sopenharmony_ci if (ice_is_safe_mode(pf)) { 41198c2ecf20Sopenharmony_ci dev_err(dev, "Package download failed. Advanced features disabled - Device now in Safe Mode\n"); 41208c2ecf20Sopenharmony_ci /* we already got function/device capabilities but these don't 41218c2ecf20Sopenharmony_ci * reflect what the driver needs to do in safe mode. Instead of 41228c2ecf20Sopenharmony_ci * adding conditional logic everywhere to ignore these 41238c2ecf20Sopenharmony_ci * device/function capabilities, override them. 41248c2ecf20Sopenharmony_ci */ 41258c2ecf20Sopenharmony_ci ice_set_safe_mode_caps(hw); 41268c2ecf20Sopenharmony_ci } 41278c2ecf20Sopenharmony_ci 41288c2ecf20Sopenharmony_ci err = ice_init_pf(pf); 41298c2ecf20Sopenharmony_ci if (err) { 41308c2ecf20Sopenharmony_ci dev_err(dev, "ice_init_pf failed: %d\n", err); 41318c2ecf20Sopenharmony_ci goto err_init_pf_unroll; 41328c2ecf20Sopenharmony_ci } 41338c2ecf20Sopenharmony_ci 41348c2ecf20Sopenharmony_ci ice_devlink_init_regions(pf); 41358c2ecf20Sopenharmony_ci 41368c2ecf20Sopenharmony_ci pf->hw.udp_tunnel_nic.set_port = ice_udp_tunnel_set_port; 41378c2ecf20Sopenharmony_ci pf->hw.udp_tunnel_nic.unset_port = ice_udp_tunnel_unset_port; 41388c2ecf20Sopenharmony_ci pf->hw.udp_tunnel_nic.flags = UDP_TUNNEL_NIC_INFO_MAY_SLEEP; 41398c2ecf20Sopenharmony_ci pf->hw.udp_tunnel_nic.shared = &pf->hw.udp_tunnel_shared; 41408c2ecf20Sopenharmony_ci i = 0; 41418c2ecf20Sopenharmony_ci if (pf->hw.tnl.valid_count[TNL_VXLAN]) { 41428c2ecf20Sopenharmony_ci pf->hw.udp_tunnel_nic.tables[i].n_entries = 41438c2ecf20Sopenharmony_ci pf->hw.tnl.valid_count[TNL_VXLAN]; 41448c2ecf20Sopenharmony_ci pf->hw.udp_tunnel_nic.tables[i].tunnel_types = 41458c2ecf20Sopenharmony_ci UDP_TUNNEL_TYPE_VXLAN; 41468c2ecf20Sopenharmony_ci i++; 41478c2ecf20Sopenharmony_ci } 41488c2ecf20Sopenharmony_ci if (pf->hw.tnl.valid_count[TNL_GENEVE]) { 41498c2ecf20Sopenharmony_ci pf->hw.udp_tunnel_nic.tables[i].n_entries = 41508c2ecf20Sopenharmony_ci pf->hw.tnl.valid_count[TNL_GENEVE]; 41518c2ecf20Sopenharmony_ci pf->hw.udp_tunnel_nic.tables[i].tunnel_types = 41528c2ecf20Sopenharmony_ci UDP_TUNNEL_TYPE_GENEVE; 41538c2ecf20Sopenharmony_ci i++; 41548c2ecf20Sopenharmony_ci } 41558c2ecf20Sopenharmony_ci 41568c2ecf20Sopenharmony_ci pf->num_alloc_vsi = hw->func_caps.guar_num_vsi; 41578c2ecf20Sopenharmony_ci if (!pf->num_alloc_vsi) { 41588c2ecf20Sopenharmony_ci err = -EIO; 41598c2ecf20Sopenharmony_ci goto err_init_pf_unroll; 41608c2ecf20Sopenharmony_ci } 41618c2ecf20Sopenharmony_ci if (pf->num_alloc_vsi > UDP_TUNNEL_NIC_MAX_SHARING_DEVICES) { 41628c2ecf20Sopenharmony_ci dev_warn(&pf->pdev->dev, 41638c2ecf20Sopenharmony_ci "limiting the VSI count due to UDP tunnel limitation %d > %d\n", 41648c2ecf20Sopenharmony_ci pf->num_alloc_vsi, UDP_TUNNEL_NIC_MAX_SHARING_DEVICES); 41658c2ecf20Sopenharmony_ci pf->num_alloc_vsi = UDP_TUNNEL_NIC_MAX_SHARING_DEVICES; 41668c2ecf20Sopenharmony_ci } 41678c2ecf20Sopenharmony_ci 41688c2ecf20Sopenharmony_ci pf->vsi = devm_kcalloc(dev, pf->num_alloc_vsi, sizeof(*pf->vsi), 41698c2ecf20Sopenharmony_ci GFP_KERNEL); 41708c2ecf20Sopenharmony_ci if (!pf->vsi) { 41718c2ecf20Sopenharmony_ci err = -ENOMEM; 41728c2ecf20Sopenharmony_ci goto err_init_pf_unroll; 41738c2ecf20Sopenharmony_ci } 41748c2ecf20Sopenharmony_ci 41758c2ecf20Sopenharmony_ci err = ice_init_interrupt_scheme(pf); 41768c2ecf20Sopenharmony_ci if (err) { 41778c2ecf20Sopenharmony_ci dev_err(dev, "ice_init_interrupt_scheme failed: %d\n", err); 41788c2ecf20Sopenharmony_ci err = -EIO; 41798c2ecf20Sopenharmony_ci goto err_init_vsi_unroll; 41808c2ecf20Sopenharmony_ci } 41818c2ecf20Sopenharmony_ci 41828c2ecf20Sopenharmony_ci /* In case of MSIX we are going to setup the misc vector right here 41838c2ecf20Sopenharmony_ci * to handle admin queue events etc. In case of legacy and MSI 41848c2ecf20Sopenharmony_ci * the misc functionality and queue processing is combined in 41858c2ecf20Sopenharmony_ci * the same vector and that gets setup at open. 41868c2ecf20Sopenharmony_ci */ 41878c2ecf20Sopenharmony_ci err = ice_req_irq_msix_misc(pf); 41888c2ecf20Sopenharmony_ci if (err) { 41898c2ecf20Sopenharmony_ci dev_err(dev, "setup of misc vector failed: %d\n", err); 41908c2ecf20Sopenharmony_ci goto err_init_interrupt_unroll; 41918c2ecf20Sopenharmony_ci } 41928c2ecf20Sopenharmony_ci 41938c2ecf20Sopenharmony_ci /* create switch struct for the switch element created by FW on boot */ 41948c2ecf20Sopenharmony_ci pf->first_sw = devm_kzalloc(dev, sizeof(*pf->first_sw), GFP_KERNEL); 41958c2ecf20Sopenharmony_ci if (!pf->first_sw) { 41968c2ecf20Sopenharmony_ci err = -ENOMEM; 41978c2ecf20Sopenharmony_ci goto err_msix_misc_unroll; 41988c2ecf20Sopenharmony_ci } 41998c2ecf20Sopenharmony_ci 42008c2ecf20Sopenharmony_ci if (hw->evb_veb) 42018c2ecf20Sopenharmony_ci pf->first_sw->bridge_mode = BRIDGE_MODE_VEB; 42028c2ecf20Sopenharmony_ci else 42038c2ecf20Sopenharmony_ci pf->first_sw->bridge_mode = BRIDGE_MODE_VEPA; 42048c2ecf20Sopenharmony_ci 42058c2ecf20Sopenharmony_ci pf->first_sw->pf = pf; 42068c2ecf20Sopenharmony_ci 42078c2ecf20Sopenharmony_ci /* record the sw_id available for later use */ 42088c2ecf20Sopenharmony_ci pf->first_sw->sw_id = hw->port_info->sw_id; 42098c2ecf20Sopenharmony_ci 42108c2ecf20Sopenharmony_ci err = ice_setup_pf_sw(pf); 42118c2ecf20Sopenharmony_ci if (err) { 42128c2ecf20Sopenharmony_ci dev_err(dev, "probe failed due to setup PF switch: %d\n", err); 42138c2ecf20Sopenharmony_ci goto err_alloc_sw_unroll; 42148c2ecf20Sopenharmony_ci } 42158c2ecf20Sopenharmony_ci 42168c2ecf20Sopenharmony_ci clear_bit(__ICE_SERVICE_DIS, pf->state); 42178c2ecf20Sopenharmony_ci 42188c2ecf20Sopenharmony_ci /* tell the firmware we are up */ 42198c2ecf20Sopenharmony_ci err = ice_send_version(pf); 42208c2ecf20Sopenharmony_ci if (err) { 42218c2ecf20Sopenharmony_ci dev_err(dev, "probe failed sending driver version %s. error: %d\n", 42228c2ecf20Sopenharmony_ci UTS_RELEASE, err); 42238c2ecf20Sopenharmony_ci goto err_send_version_unroll; 42248c2ecf20Sopenharmony_ci } 42258c2ecf20Sopenharmony_ci 42268c2ecf20Sopenharmony_ci /* since everything is good, start the service timer */ 42278c2ecf20Sopenharmony_ci mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period)); 42288c2ecf20Sopenharmony_ci 42298c2ecf20Sopenharmony_ci err = ice_init_link_events(pf->hw.port_info); 42308c2ecf20Sopenharmony_ci if (err) { 42318c2ecf20Sopenharmony_ci dev_err(dev, "ice_init_link_events failed: %d\n", err); 42328c2ecf20Sopenharmony_ci goto err_send_version_unroll; 42338c2ecf20Sopenharmony_ci } 42348c2ecf20Sopenharmony_ci 42358c2ecf20Sopenharmony_ci /* not a fatal error if this fails */ 42368c2ecf20Sopenharmony_ci err = ice_init_nvm_phy_type(pf->hw.port_info); 42378c2ecf20Sopenharmony_ci if (err) 42388c2ecf20Sopenharmony_ci dev_err(dev, "ice_init_nvm_phy_type failed: %d\n", err); 42398c2ecf20Sopenharmony_ci 42408c2ecf20Sopenharmony_ci /* not a fatal error if this fails */ 42418c2ecf20Sopenharmony_ci err = ice_update_link_info(pf->hw.port_info); 42428c2ecf20Sopenharmony_ci if (err) 42438c2ecf20Sopenharmony_ci dev_err(dev, "ice_update_link_info failed: %d\n", err); 42448c2ecf20Sopenharmony_ci 42458c2ecf20Sopenharmony_ci ice_init_link_dflt_override(pf->hw.port_info); 42468c2ecf20Sopenharmony_ci 42478c2ecf20Sopenharmony_ci /* if media available, initialize PHY settings */ 42488c2ecf20Sopenharmony_ci if (pf->hw.port_info->phy.link_info.link_info & 42498c2ecf20Sopenharmony_ci ICE_AQ_MEDIA_AVAILABLE) { 42508c2ecf20Sopenharmony_ci /* not a fatal error if this fails */ 42518c2ecf20Sopenharmony_ci err = ice_init_phy_user_cfg(pf->hw.port_info); 42528c2ecf20Sopenharmony_ci if (err) 42538c2ecf20Sopenharmony_ci dev_err(dev, "ice_init_phy_user_cfg failed: %d\n", err); 42548c2ecf20Sopenharmony_ci 42558c2ecf20Sopenharmony_ci if (!test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, pf->flags)) { 42568c2ecf20Sopenharmony_ci struct ice_vsi *vsi = ice_get_main_vsi(pf); 42578c2ecf20Sopenharmony_ci 42588c2ecf20Sopenharmony_ci if (vsi) 42598c2ecf20Sopenharmony_ci ice_configure_phy(vsi); 42608c2ecf20Sopenharmony_ci } 42618c2ecf20Sopenharmony_ci } else { 42628c2ecf20Sopenharmony_ci set_bit(ICE_FLAG_NO_MEDIA, pf->flags); 42638c2ecf20Sopenharmony_ci } 42648c2ecf20Sopenharmony_ci 42658c2ecf20Sopenharmony_ci ice_verify_cacheline_size(pf); 42668c2ecf20Sopenharmony_ci 42678c2ecf20Sopenharmony_ci /* Save wakeup reason register for later use */ 42688c2ecf20Sopenharmony_ci pf->wakeup_reason = rd32(hw, PFPM_WUS); 42698c2ecf20Sopenharmony_ci 42708c2ecf20Sopenharmony_ci /* check for a power management event */ 42718c2ecf20Sopenharmony_ci ice_print_wake_reason(pf); 42728c2ecf20Sopenharmony_ci 42738c2ecf20Sopenharmony_ci /* clear wake status, all bits */ 42748c2ecf20Sopenharmony_ci wr32(hw, PFPM_WUS, U32_MAX); 42758c2ecf20Sopenharmony_ci 42768c2ecf20Sopenharmony_ci /* Disable WoL at init, wait for user to enable */ 42778c2ecf20Sopenharmony_ci device_set_wakeup_enable(dev, false); 42788c2ecf20Sopenharmony_ci 42798c2ecf20Sopenharmony_ci if (ice_is_safe_mode(pf)) { 42808c2ecf20Sopenharmony_ci ice_set_safe_mode_vlan_cfg(pf); 42818c2ecf20Sopenharmony_ci goto probe_done; 42828c2ecf20Sopenharmony_ci } 42838c2ecf20Sopenharmony_ci 42848c2ecf20Sopenharmony_ci /* initialize DDP driven features */ 42858c2ecf20Sopenharmony_ci 42868c2ecf20Sopenharmony_ci /* Note: Flow director init failure is non-fatal to load */ 42878c2ecf20Sopenharmony_ci if (ice_init_fdir(pf)) 42888c2ecf20Sopenharmony_ci dev_err(dev, "could not initialize flow director\n"); 42898c2ecf20Sopenharmony_ci 42908c2ecf20Sopenharmony_ci /* Note: DCB init failure is non-fatal to load */ 42918c2ecf20Sopenharmony_ci if (ice_init_pf_dcb(pf, false)) { 42928c2ecf20Sopenharmony_ci clear_bit(ICE_FLAG_DCB_CAPABLE, pf->flags); 42938c2ecf20Sopenharmony_ci clear_bit(ICE_FLAG_DCB_ENA, pf->flags); 42948c2ecf20Sopenharmony_ci } else { 42958c2ecf20Sopenharmony_ci ice_cfg_lldp_mib_change(&pf->hw, true); 42968c2ecf20Sopenharmony_ci } 42978c2ecf20Sopenharmony_ci 42988c2ecf20Sopenharmony_ci /* print PCI link speed and width */ 42998c2ecf20Sopenharmony_ci pcie_print_link_status(pf->pdev); 43008c2ecf20Sopenharmony_ci 43018c2ecf20Sopenharmony_ciprobe_done: 43028c2ecf20Sopenharmony_ci /* ready to go, so clear down state bit */ 43038c2ecf20Sopenharmony_ci clear_bit(__ICE_DOWN, pf->state); 43048c2ecf20Sopenharmony_ci return 0; 43058c2ecf20Sopenharmony_ci 43068c2ecf20Sopenharmony_cierr_send_version_unroll: 43078c2ecf20Sopenharmony_ci ice_vsi_release_all(pf); 43088c2ecf20Sopenharmony_cierr_alloc_sw_unroll: 43098c2ecf20Sopenharmony_ci set_bit(__ICE_SERVICE_DIS, pf->state); 43108c2ecf20Sopenharmony_ci set_bit(__ICE_DOWN, pf->state); 43118c2ecf20Sopenharmony_ci devm_kfree(dev, pf->first_sw); 43128c2ecf20Sopenharmony_cierr_msix_misc_unroll: 43138c2ecf20Sopenharmony_ci ice_free_irq_msix_misc(pf); 43148c2ecf20Sopenharmony_cierr_init_interrupt_unroll: 43158c2ecf20Sopenharmony_ci ice_clear_interrupt_scheme(pf); 43168c2ecf20Sopenharmony_cierr_init_vsi_unroll: 43178c2ecf20Sopenharmony_ci devm_kfree(dev, pf->vsi); 43188c2ecf20Sopenharmony_cierr_init_pf_unroll: 43198c2ecf20Sopenharmony_ci ice_deinit_pf(pf); 43208c2ecf20Sopenharmony_ci ice_devlink_destroy_regions(pf); 43218c2ecf20Sopenharmony_ci ice_deinit_hw(hw); 43228c2ecf20Sopenharmony_cierr_exit_unroll: 43238c2ecf20Sopenharmony_ci ice_devlink_unregister(pf); 43248c2ecf20Sopenharmony_ci pci_disable_pcie_error_reporting(pdev); 43258c2ecf20Sopenharmony_ci pci_disable_device(pdev); 43268c2ecf20Sopenharmony_ci return err; 43278c2ecf20Sopenharmony_ci} 43288c2ecf20Sopenharmony_ci 43298c2ecf20Sopenharmony_ci/** 43308c2ecf20Sopenharmony_ci * ice_set_wake - enable or disable Wake on LAN 43318c2ecf20Sopenharmony_ci * @pf: pointer to the PF struct 43328c2ecf20Sopenharmony_ci * 43338c2ecf20Sopenharmony_ci * Simple helper for WoL control 43348c2ecf20Sopenharmony_ci */ 43358c2ecf20Sopenharmony_cistatic void ice_set_wake(struct ice_pf *pf) 43368c2ecf20Sopenharmony_ci{ 43378c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 43388c2ecf20Sopenharmony_ci bool wol = pf->wol_ena; 43398c2ecf20Sopenharmony_ci 43408c2ecf20Sopenharmony_ci /* clear wake state, otherwise new wake events won't fire */ 43418c2ecf20Sopenharmony_ci wr32(hw, PFPM_WUS, U32_MAX); 43428c2ecf20Sopenharmony_ci 43438c2ecf20Sopenharmony_ci /* enable / disable APM wake up, no RMW needed */ 43448c2ecf20Sopenharmony_ci wr32(hw, PFPM_APM, wol ? PFPM_APM_APME_M : 0); 43458c2ecf20Sopenharmony_ci 43468c2ecf20Sopenharmony_ci /* set magic packet filter enabled */ 43478c2ecf20Sopenharmony_ci wr32(hw, PFPM_WUFC, wol ? PFPM_WUFC_MAG_M : 0); 43488c2ecf20Sopenharmony_ci} 43498c2ecf20Sopenharmony_ci 43508c2ecf20Sopenharmony_ci/** 43518c2ecf20Sopenharmony_ci * ice_setup_magic_mc_wake - setup device to wake on multicast magic packet 43528c2ecf20Sopenharmony_ci * @pf: pointer to the PF struct 43538c2ecf20Sopenharmony_ci * 43548c2ecf20Sopenharmony_ci * Issue firmware command to enable multicast magic wake, making 43558c2ecf20Sopenharmony_ci * sure that any locally administered address (LAA) is used for 43568c2ecf20Sopenharmony_ci * wake, and that PF reset doesn't undo the LAA. 43578c2ecf20Sopenharmony_ci */ 43588c2ecf20Sopenharmony_cistatic void ice_setup_mc_magic_wake(struct ice_pf *pf) 43598c2ecf20Sopenharmony_ci{ 43608c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 43618c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 43628c2ecf20Sopenharmony_ci enum ice_status status; 43638c2ecf20Sopenharmony_ci u8 mac_addr[ETH_ALEN]; 43648c2ecf20Sopenharmony_ci struct ice_vsi *vsi; 43658c2ecf20Sopenharmony_ci u8 flags; 43668c2ecf20Sopenharmony_ci 43678c2ecf20Sopenharmony_ci if (!pf->wol_ena) 43688c2ecf20Sopenharmony_ci return; 43698c2ecf20Sopenharmony_ci 43708c2ecf20Sopenharmony_ci vsi = ice_get_main_vsi(pf); 43718c2ecf20Sopenharmony_ci if (!vsi) 43728c2ecf20Sopenharmony_ci return; 43738c2ecf20Sopenharmony_ci 43748c2ecf20Sopenharmony_ci /* Get current MAC address in case it's an LAA */ 43758c2ecf20Sopenharmony_ci if (vsi->netdev) 43768c2ecf20Sopenharmony_ci ether_addr_copy(mac_addr, vsi->netdev->dev_addr); 43778c2ecf20Sopenharmony_ci else 43788c2ecf20Sopenharmony_ci ether_addr_copy(mac_addr, vsi->port_info->mac.perm_addr); 43798c2ecf20Sopenharmony_ci 43808c2ecf20Sopenharmony_ci flags = ICE_AQC_MAN_MAC_WR_MC_MAG_EN | 43818c2ecf20Sopenharmony_ci ICE_AQC_MAN_MAC_UPDATE_LAA_WOL | 43828c2ecf20Sopenharmony_ci ICE_AQC_MAN_MAC_WR_WOL_LAA_PFR_KEEP; 43838c2ecf20Sopenharmony_ci 43848c2ecf20Sopenharmony_ci status = ice_aq_manage_mac_write(hw, mac_addr, flags, NULL); 43858c2ecf20Sopenharmony_ci if (status) 43868c2ecf20Sopenharmony_ci dev_err(dev, "Failed to enable Multicast Magic Packet wake, err %s aq_err %s\n", 43878c2ecf20Sopenharmony_ci ice_stat_str(status), 43888c2ecf20Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 43898c2ecf20Sopenharmony_ci} 43908c2ecf20Sopenharmony_ci 43918c2ecf20Sopenharmony_ci/** 43928c2ecf20Sopenharmony_ci * ice_remove - Device removal routine 43938c2ecf20Sopenharmony_ci * @pdev: PCI device information struct 43948c2ecf20Sopenharmony_ci */ 43958c2ecf20Sopenharmony_cistatic void ice_remove(struct pci_dev *pdev) 43968c2ecf20Sopenharmony_ci{ 43978c2ecf20Sopenharmony_ci struct ice_pf *pf = pci_get_drvdata(pdev); 43988c2ecf20Sopenharmony_ci int i; 43998c2ecf20Sopenharmony_ci 44008c2ecf20Sopenharmony_ci for (i = 0; i < ICE_MAX_RESET_WAIT; i++) { 44018c2ecf20Sopenharmony_ci if (!ice_is_reset_in_progress(pf->state)) 44028c2ecf20Sopenharmony_ci break; 44038c2ecf20Sopenharmony_ci msleep(100); 44048c2ecf20Sopenharmony_ci } 44058c2ecf20Sopenharmony_ci 44068c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_SRIOV_ENA, pf->flags)) { 44078c2ecf20Sopenharmony_ci set_bit(__ICE_VF_RESETS_DISABLED, pf->state); 44088c2ecf20Sopenharmony_ci ice_free_vfs(pf); 44098c2ecf20Sopenharmony_ci } 44108c2ecf20Sopenharmony_ci 44118c2ecf20Sopenharmony_ci set_bit(__ICE_DOWN, pf->state); 44128c2ecf20Sopenharmony_ci ice_service_task_stop(pf); 44138c2ecf20Sopenharmony_ci 44148c2ecf20Sopenharmony_ci ice_aq_cancel_waiting_tasks(pf); 44158c2ecf20Sopenharmony_ci 44168c2ecf20Sopenharmony_ci mutex_destroy(&(&pf->hw)->fdir_fltr_lock); 44178c2ecf20Sopenharmony_ci if (!ice_is_safe_mode(pf)) 44188c2ecf20Sopenharmony_ci ice_remove_arfs(pf); 44198c2ecf20Sopenharmony_ci ice_setup_mc_magic_wake(pf); 44208c2ecf20Sopenharmony_ci ice_vsi_release_all(pf); 44218c2ecf20Sopenharmony_ci ice_set_wake(pf); 44228c2ecf20Sopenharmony_ci ice_free_irq_msix_misc(pf); 44238c2ecf20Sopenharmony_ci ice_for_each_vsi(pf, i) { 44248c2ecf20Sopenharmony_ci if (!pf->vsi[i]) 44258c2ecf20Sopenharmony_ci continue; 44268c2ecf20Sopenharmony_ci ice_vsi_free_q_vectors(pf->vsi[i]); 44278c2ecf20Sopenharmony_ci } 44288c2ecf20Sopenharmony_ci ice_deinit_pf(pf); 44298c2ecf20Sopenharmony_ci ice_devlink_destroy_regions(pf); 44308c2ecf20Sopenharmony_ci ice_deinit_hw(&pf->hw); 44318c2ecf20Sopenharmony_ci ice_devlink_unregister(pf); 44328c2ecf20Sopenharmony_ci 44338c2ecf20Sopenharmony_ci /* Issue a PFR as part of the prescribed driver unload flow. Do not 44348c2ecf20Sopenharmony_ci * do it via ice_schedule_reset() since there is no need to rebuild 44358c2ecf20Sopenharmony_ci * and the service task is already stopped. 44368c2ecf20Sopenharmony_ci */ 44378c2ecf20Sopenharmony_ci ice_reset(&pf->hw, ICE_RESET_PFR); 44388c2ecf20Sopenharmony_ci pci_wait_for_pending_transaction(pdev); 44398c2ecf20Sopenharmony_ci ice_clear_interrupt_scheme(pf); 44408c2ecf20Sopenharmony_ci pci_disable_pcie_error_reporting(pdev); 44418c2ecf20Sopenharmony_ci pci_disable_device(pdev); 44428c2ecf20Sopenharmony_ci} 44438c2ecf20Sopenharmony_ci 44448c2ecf20Sopenharmony_ci/** 44458c2ecf20Sopenharmony_ci * ice_shutdown - PCI callback for shutting down device 44468c2ecf20Sopenharmony_ci * @pdev: PCI device information struct 44478c2ecf20Sopenharmony_ci */ 44488c2ecf20Sopenharmony_cistatic void ice_shutdown(struct pci_dev *pdev) 44498c2ecf20Sopenharmony_ci{ 44508c2ecf20Sopenharmony_ci struct ice_pf *pf = pci_get_drvdata(pdev); 44518c2ecf20Sopenharmony_ci 44528c2ecf20Sopenharmony_ci ice_remove(pdev); 44538c2ecf20Sopenharmony_ci 44548c2ecf20Sopenharmony_ci if (system_state == SYSTEM_POWER_OFF) { 44558c2ecf20Sopenharmony_ci pci_wake_from_d3(pdev, pf->wol_ena); 44568c2ecf20Sopenharmony_ci pci_set_power_state(pdev, PCI_D3hot); 44578c2ecf20Sopenharmony_ci } 44588c2ecf20Sopenharmony_ci} 44598c2ecf20Sopenharmony_ci 44608c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 44618c2ecf20Sopenharmony_ci/** 44628c2ecf20Sopenharmony_ci * ice_prepare_for_shutdown - prep for PCI shutdown 44638c2ecf20Sopenharmony_ci * @pf: board private structure 44648c2ecf20Sopenharmony_ci * 44658c2ecf20Sopenharmony_ci * Inform or close all dependent features in prep for PCI device shutdown 44668c2ecf20Sopenharmony_ci */ 44678c2ecf20Sopenharmony_cistatic void ice_prepare_for_shutdown(struct ice_pf *pf) 44688c2ecf20Sopenharmony_ci{ 44698c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 44708c2ecf20Sopenharmony_ci u32 v; 44718c2ecf20Sopenharmony_ci 44728c2ecf20Sopenharmony_ci /* Notify VFs of impending reset */ 44738c2ecf20Sopenharmony_ci if (ice_check_sq_alive(hw, &hw->mailboxq)) 44748c2ecf20Sopenharmony_ci ice_vc_notify_reset(pf); 44758c2ecf20Sopenharmony_ci 44768c2ecf20Sopenharmony_ci dev_dbg(ice_pf_to_dev(pf), "Tearing down internal switch for shutdown\n"); 44778c2ecf20Sopenharmony_ci 44788c2ecf20Sopenharmony_ci /* disable the VSIs and their queues that are not already DOWN */ 44798c2ecf20Sopenharmony_ci ice_pf_dis_all_vsi(pf, false); 44808c2ecf20Sopenharmony_ci 44818c2ecf20Sopenharmony_ci ice_for_each_vsi(pf, v) 44828c2ecf20Sopenharmony_ci if (pf->vsi[v]) 44838c2ecf20Sopenharmony_ci pf->vsi[v]->vsi_num = 0; 44848c2ecf20Sopenharmony_ci 44858c2ecf20Sopenharmony_ci ice_shutdown_all_ctrlq(hw); 44868c2ecf20Sopenharmony_ci} 44878c2ecf20Sopenharmony_ci 44888c2ecf20Sopenharmony_ci/** 44898c2ecf20Sopenharmony_ci * ice_reinit_interrupt_scheme - Reinitialize interrupt scheme 44908c2ecf20Sopenharmony_ci * @pf: board private structure to reinitialize 44918c2ecf20Sopenharmony_ci * 44928c2ecf20Sopenharmony_ci * This routine reinitialize interrupt scheme that was cleared during 44938c2ecf20Sopenharmony_ci * power management suspend callback. 44948c2ecf20Sopenharmony_ci * 44958c2ecf20Sopenharmony_ci * This should be called during resume routine to re-allocate the q_vectors 44968c2ecf20Sopenharmony_ci * and reacquire interrupts. 44978c2ecf20Sopenharmony_ci */ 44988c2ecf20Sopenharmony_cistatic int ice_reinit_interrupt_scheme(struct ice_pf *pf) 44998c2ecf20Sopenharmony_ci{ 45008c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 45018c2ecf20Sopenharmony_ci int ret, v; 45028c2ecf20Sopenharmony_ci 45038c2ecf20Sopenharmony_ci /* Since we clear MSIX flag during suspend, we need to 45048c2ecf20Sopenharmony_ci * set it back during resume... 45058c2ecf20Sopenharmony_ci */ 45068c2ecf20Sopenharmony_ci 45078c2ecf20Sopenharmony_ci ret = ice_init_interrupt_scheme(pf); 45088c2ecf20Sopenharmony_ci if (ret) { 45098c2ecf20Sopenharmony_ci dev_err(dev, "Failed to re-initialize interrupt %d\n", ret); 45108c2ecf20Sopenharmony_ci return ret; 45118c2ecf20Sopenharmony_ci } 45128c2ecf20Sopenharmony_ci 45138c2ecf20Sopenharmony_ci /* Remap vectors and rings, after successful re-init interrupts */ 45148c2ecf20Sopenharmony_ci ice_for_each_vsi(pf, v) { 45158c2ecf20Sopenharmony_ci if (!pf->vsi[v]) 45168c2ecf20Sopenharmony_ci continue; 45178c2ecf20Sopenharmony_ci 45188c2ecf20Sopenharmony_ci ret = ice_vsi_alloc_q_vectors(pf->vsi[v]); 45198c2ecf20Sopenharmony_ci if (ret) 45208c2ecf20Sopenharmony_ci goto err_reinit; 45218c2ecf20Sopenharmony_ci ice_vsi_map_rings_to_vectors(pf->vsi[v]); 45228c2ecf20Sopenharmony_ci } 45238c2ecf20Sopenharmony_ci 45248c2ecf20Sopenharmony_ci ret = ice_req_irq_msix_misc(pf); 45258c2ecf20Sopenharmony_ci if (ret) { 45268c2ecf20Sopenharmony_ci dev_err(dev, "Setting up misc vector failed after device suspend %d\n", 45278c2ecf20Sopenharmony_ci ret); 45288c2ecf20Sopenharmony_ci goto err_reinit; 45298c2ecf20Sopenharmony_ci } 45308c2ecf20Sopenharmony_ci 45318c2ecf20Sopenharmony_ci return 0; 45328c2ecf20Sopenharmony_ci 45338c2ecf20Sopenharmony_cierr_reinit: 45348c2ecf20Sopenharmony_ci while (v--) 45358c2ecf20Sopenharmony_ci if (pf->vsi[v]) 45368c2ecf20Sopenharmony_ci ice_vsi_free_q_vectors(pf->vsi[v]); 45378c2ecf20Sopenharmony_ci 45388c2ecf20Sopenharmony_ci return ret; 45398c2ecf20Sopenharmony_ci} 45408c2ecf20Sopenharmony_ci 45418c2ecf20Sopenharmony_ci/** 45428c2ecf20Sopenharmony_ci * ice_suspend 45438c2ecf20Sopenharmony_ci * @dev: generic device information structure 45448c2ecf20Sopenharmony_ci * 45458c2ecf20Sopenharmony_ci * Power Management callback to quiesce the device and prepare 45468c2ecf20Sopenharmony_ci * for D3 transition. 45478c2ecf20Sopenharmony_ci */ 45488c2ecf20Sopenharmony_cistatic int __maybe_unused ice_suspend(struct device *dev) 45498c2ecf20Sopenharmony_ci{ 45508c2ecf20Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev); 45518c2ecf20Sopenharmony_ci struct ice_pf *pf; 45528c2ecf20Sopenharmony_ci int disabled, v; 45538c2ecf20Sopenharmony_ci 45548c2ecf20Sopenharmony_ci pf = pci_get_drvdata(pdev); 45558c2ecf20Sopenharmony_ci 45568c2ecf20Sopenharmony_ci if (!ice_pf_state_is_nominal(pf)) { 45578c2ecf20Sopenharmony_ci dev_err(dev, "Device is not ready, no need to suspend it\n"); 45588c2ecf20Sopenharmony_ci return -EBUSY; 45598c2ecf20Sopenharmony_ci } 45608c2ecf20Sopenharmony_ci 45618c2ecf20Sopenharmony_ci /* Stop watchdog tasks until resume completion. 45628c2ecf20Sopenharmony_ci * Even though it is most likely that the service task is 45638c2ecf20Sopenharmony_ci * disabled if the device is suspended or down, the service task's 45648c2ecf20Sopenharmony_ci * state is controlled by a different state bit, and we should 45658c2ecf20Sopenharmony_ci * store and honor whatever state that bit is in at this point. 45668c2ecf20Sopenharmony_ci */ 45678c2ecf20Sopenharmony_ci disabled = ice_service_task_stop(pf); 45688c2ecf20Sopenharmony_ci 45698c2ecf20Sopenharmony_ci /* Already suspended?, then there is nothing to do */ 45708c2ecf20Sopenharmony_ci if (test_and_set_bit(__ICE_SUSPENDED, pf->state)) { 45718c2ecf20Sopenharmony_ci if (!disabled) 45728c2ecf20Sopenharmony_ci ice_service_task_restart(pf); 45738c2ecf20Sopenharmony_ci return 0; 45748c2ecf20Sopenharmony_ci } 45758c2ecf20Sopenharmony_ci 45768c2ecf20Sopenharmony_ci if (test_bit(__ICE_DOWN, pf->state) || 45778c2ecf20Sopenharmony_ci ice_is_reset_in_progress(pf->state)) { 45788c2ecf20Sopenharmony_ci dev_err(dev, "can't suspend device in reset or already down\n"); 45798c2ecf20Sopenharmony_ci if (!disabled) 45808c2ecf20Sopenharmony_ci ice_service_task_restart(pf); 45818c2ecf20Sopenharmony_ci return 0; 45828c2ecf20Sopenharmony_ci } 45838c2ecf20Sopenharmony_ci 45848c2ecf20Sopenharmony_ci ice_setup_mc_magic_wake(pf); 45858c2ecf20Sopenharmony_ci 45868c2ecf20Sopenharmony_ci ice_prepare_for_shutdown(pf); 45878c2ecf20Sopenharmony_ci 45888c2ecf20Sopenharmony_ci ice_set_wake(pf); 45898c2ecf20Sopenharmony_ci 45908c2ecf20Sopenharmony_ci /* Free vectors, clear the interrupt scheme and release IRQs 45918c2ecf20Sopenharmony_ci * for proper hibernation, especially with large number of CPUs. 45928c2ecf20Sopenharmony_ci * Otherwise hibernation might fail when mapping all the vectors back 45938c2ecf20Sopenharmony_ci * to CPU0. 45948c2ecf20Sopenharmony_ci */ 45958c2ecf20Sopenharmony_ci ice_free_irq_msix_misc(pf); 45968c2ecf20Sopenharmony_ci ice_for_each_vsi(pf, v) { 45978c2ecf20Sopenharmony_ci if (!pf->vsi[v]) 45988c2ecf20Sopenharmony_ci continue; 45998c2ecf20Sopenharmony_ci ice_vsi_free_q_vectors(pf->vsi[v]); 46008c2ecf20Sopenharmony_ci } 46018c2ecf20Sopenharmony_ci ice_free_cpu_rx_rmap(ice_get_main_vsi(pf)); 46028c2ecf20Sopenharmony_ci ice_clear_interrupt_scheme(pf); 46038c2ecf20Sopenharmony_ci 46048c2ecf20Sopenharmony_ci pci_save_state(pdev); 46058c2ecf20Sopenharmony_ci pci_wake_from_d3(pdev, pf->wol_ena); 46068c2ecf20Sopenharmony_ci pci_set_power_state(pdev, PCI_D3hot); 46078c2ecf20Sopenharmony_ci return 0; 46088c2ecf20Sopenharmony_ci} 46098c2ecf20Sopenharmony_ci 46108c2ecf20Sopenharmony_ci/** 46118c2ecf20Sopenharmony_ci * ice_resume - PM callback for waking up from D3 46128c2ecf20Sopenharmony_ci * @dev: generic device information structure 46138c2ecf20Sopenharmony_ci */ 46148c2ecf20Sopenharmony_cistatic int __maybe_unused ice_resume(struct device *dev) 46158c2ecf20Sopenharmony_ci{ 46168c2ecf20Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev); 46178c2ecf20Sopenharmony_ci enum ice_reset_req reset_type; 46188c2ecf20Sopenharmony_ci struct ice_pf *pf; 46198c2ecf20Sopenharmony_ci struct ice_hw *hw; 46208c2ecf20Sopenharmony_ci int ret; 46218c2ecf20Sopenharmony_ci 46228c2ecf20Sopenharmony_ci pci_set_power_state(pdev, PCI_D0); 46238c2ecf20Sopenharmony_ci pci_restore_state(pdev); 46248c2ecf20Sopenharmony_ci pci_save_state(pdev); 46258c2ecf20Sopenharmony_ci 46268c2ecf20Sopenharmony_ci if (!pci_device_is_present(pdev)) 46278c2ecf20Sopenharmony_ci return -ENODEV; 46288c2ecf20Sopenharmony_ci 46298c2ecf20Sopenharmony_ci ret = pci_enable_device_mem(pdev); 46308c2ecf20Sopenharmony_ci if (ret) { 46318c2ecf20Sopenharmony_ci dev_err(dev, "Cannot enable device after suspend\n"); 46328c2ecf20Sopenharmony_ci return ret; 46338c2ecf20Sopenharmony_ci } 46348c2ecf20Sopenharmony_ci 46358c2ecf20Sopenharmony_ci pf = pci_get_drvdata(pdev); 46368c2ecf20Sopenharmony_ci hw = &pf->hw; 46378c2ecf20Sopenharmony_ci 46388c2ecf20Sopenharmony_ci pf->wakeup_reason = rd32(hw, PFPM_WUS); 46398c2ecf20Sopenharmony_ci ice_print_wake_reason(pf); 46408c2ecf20Sopenharmony_ci 46418c2ecf20Sopenharmony_ci /* We cleared the interrupt scheme when we suspended, so we need to 46428c2ecf20Sopenharmony_ci * restore it now to resume device functionality. 46438c2ecf20Sopenharmony_ci */ 46448c2ecf20Sopenharmony_ci ret = ice_reinit_interrupt_scheme(pf); 46458c2ecf20Sopenharmony_ci if (ret) 46468c2ecf20Sopenharmony_ci dev_err(dev, "Cannot restore interrupt scheme: %d\n", ret); 46478c2ecf20Sopenharmony_ci 46488c2ecf20Sopenharmony_ci clear_bit(__ICE_DOWN, pf->state); 46498c2ecf20Sopenharmony_ci /* Now perform PF reset and rebuild */ 46508c2ecf20Sopenharmony_ci reset_type = ICE_RESET_PFR; 46518c2ecf20Sopenharmony_ci /* re-enable service task for reset, but allow reset to schedule it */ 46528c2ecf20Sopenharmony_ci clear_bit(__ICE_SERVICE_DIS, pf->state); 46538c2ecf20Sopenharmony_ci 46548c2ecf20Sopenharmony_ci if (ice_schedule_reset(pf, reset_type)) 46558c2ecf20Sopenharmony_ci dev_err(dev, "Reset during resume failed.\n"); 46568c2ecf20Sopenharmony_ci 46578c2ecf20Sopenharmony_ci clear_bit(__ICE_SUSPENDED, pf->state); 46588c2ecf20Sopenharmony_ci ice_service_task_restart(pf); 46598c2ecf20Sopenharmony_ci 46608c2ecf20Sopenharmony_ci /* Restart the service task */ 46618c2ecf20Sopenharmony_ci mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period)); 46628c2ecf20Sopenharmony_ci 46638c2ecf20Sopenharmony_ci return 0; 46648c2ecf20Sopenharmony_ci} 46658c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 46668c2ecf20Sopenharmony_ci 46678c2ecf20Sopenharmony_ci/** 46688c2ecf20Sopenharmony_ci * ice_pci_err_detected - warning that PCI error has been detected 46698c2ecf20Sopenharmony_ci * @pdev: PCI device information struct 46708c2ecf20Sopenharmony_ci * @err: the type of PCI error 46718c2ecf20Sopenharmony_ci * 46728c2ecf20Sopenharmony_ci * Called to warn that something happened on the PCI bus and the error handling 46738c2ecf20Sopenharmony_ci * is in progress. Allows the driver to gracefully prepare/handle PCI errors. 46748c2ecf20Sopenharmony_ci */ 46758c2ecf20Sopenharmony_cistatic pci_ers_result_t 46768c2ecf20Sopenharmony_ciice_pci_err_detected(struct pci_dev *pdev, pci_channel_state_t err) 46778c2ecf20Sopenharmony_ci{ 46788c2ecf20Sopenharmony_ci struct ice_pf *pf = pci_get_drvdata(pdev); 46798c2ecf20Sopenharmony_ci 46808c2ecf20Sopenharmony_ci if (!pf) { 46818c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "%s: unrecoverable device error %d\n", 46828c2ecf20Sopenharmony_ci __func__, err); 46838c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 46848c2ecf20Sopenharmony_ci } 46858c2ecf20Sopenharmony_ci 46868c2ecf20Sopenharmony_ci if (!test_bit(__ICE_SUSPENDED, pf->state)) { 46878c2ecf20Sopenharmony_ci ice_service_task_stop(pf); 46888c2ecf20Sopenharmony_ci 46898c2ecf20Sopenharmony_ci if (!test_bit(__ICE_PREPARED_FOR_RESET, pf->state)) { 46908c2ecf20Sopenharmony_ci set_bit(__ICE_PFR_REQ, pf->state); 46918c2ecf20Sopenharmony_ci ice_prepare_for_reset(pf); 46928c2ecf20Sopenharmony_ci } 46938c2ecf20Sopenharmony_ci } 46948c2ecf20Sopenharmony_ci 46958c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_NEED_RESET; 46968c2ecf20Sopenharmony_ci} 46978c2ecf20Sopenharmony_ci 46988c2ecf20Sopenharmony_ci/** 46998c2ecf20Sopenharmony_ci * ice_pci_err_slot_reset - a PCI slot reset has just happened 47008c2ecf20Sopenharmony_ci * @pdev: PCI device information struct 47018c2ecf20Sopenharmony_ci * 47028c2ecf20Sopenharmony_ci * Called to determine if the driver can recover from the PCI slot reset by 47038c2ecf20Sopenharmony_ci * using a register read to determine if the device is recoverable. 47048c2ecf20Sopenharmony_ci */ 47058c2ecf20Sopenharmony_cistatic pci_ers_result_t ice_pci_err_slot_reset(struct pci_dev *pdev) 47068c2ecf20Sopenharmony_ci{ 47078c2ecf20Sopenharmony_ci struct ice_pf *pf = pci_get_drvdata(pdev); 47088c2ecf20Sopenharmony_ci pci_ers_result_t result; 47098c2ecf20Sopenharmony_ci int err; 47108c2ecf20Sopenharmony_ci u32 reg; 47118c2ecf20Sopenharmony_ci 47128c2ecf20Sopenharmony_ci err = pci_enable_device_mem(pdev); 47138c2ecf20Sopenharmony_ci if (err) { 47148c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Cannot re-enable PCI device after reset, error %d\n", 47158c2ecf20Sopenharmony_ci err); 47168c2ecf20Sopenharmony_ci result = PCI_ERS_RESULT_DISCONNECT; 47178c2ecf20Sopenharmony_ci } else { 47188c2ecf20Sopenharmony_ci pci_set_master(pdev); 47198c2ecf20Sopenharmony_ci pci_restore_state(pdev); 47208c2ecf20Sopenharmony_ci pci_save_state(pdev); 47218c2ecf20Sopenharmony_ci pci_wake_from_d3(pdev, false); 47228c2ecf20Sopenharmony_ci 47238c2ecf20Sopenharmony_ci /* Check for life */ 47248c2ecf20Sopenharmony_ci reg = rd32(&pf->hw, GLGEN_RTRIG); 47258c2ecf20Sopenharmony_ci if (!reg) 47268c2ecf20Sopenharmony_ci result = PCI_ERS_RESULT_RECOVERED; 47278c2ecf20Sopenharmony_ci else 47288c2ecf20Sopenharmony_ci result = PCI_ERS_RESULT_DISCONNECT; 47298c2ecf20Sopenharmony_ci } 47308c2ecf20Sopenharmony_ci 47318c2ecf20Sopenharmony_ci err = pci_aer_clear_nonfatal_status(pdev); 47328c2ecf20Sopenharmony_ci if (err) 47338c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "pci_aer_clear_nonfatal_status() failed, error %d\n", 47348c2ecf20Sopenharmony_ci err); 47358c2ecf20Sopenharmony_ci /* non-fatal, continue */ 47368c2ecf20Sopenharmony_ci 47378c2ecf20Sopenharmony_ci return result; 47388c2ecf20Sopenharmony_ci} 47398c2ecf20Sopenharmony_ci 47408c2ecf20Sopenharmony_ci/** 47418c2ecf20Sopenharmony_ci * ice_pci_err_resume - restart operations after PCI error recovery 47428c2ecf20Sopenharmony_ci * @pdev: PCI device information struct 47438c2ecf20Sopenharmony_ci * 47448c2ecf20Sopenharmony_ci * Called to allow the driver to bring things back up after PCI error and/or 47458c2ecf20Sopenharmony_ci * reset recovery have finished 47468c2ecf20Sopenharmony_ci */ 47478c2ecf20Sopenharmony_cistatic void ice_pci_err_resume(struct pci_dev *pdev) 47488c2ecf20Sopenharmony_ci{ 47498c2ecf20Sopenharmony_ci struct ice_pf *pf = pci_get_drvdata(pdev); 47508c2ecf20Sopenharmony_ci 47518c2ecf20Sopenharmony_ci if (!pf) { 47528c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "%s failed, device is unrecoverable\n", 47538c2ecf20Sopenharmony_ci __func__); 47548c2ecf20Sopenharmony_ci return; 47558c2ecf20Sopenharmony_ci } 47568c2ecf20Sopenharmony_ci 47578c2ecf20Sopenharmony_ci if (test_bit(__ICE_SUSPENDED, pf->state)) { 47588c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "%s failed to resume normal operations!\n", 47598c2ecf20Sopenharmony_ci __func__); 47608c2ecf20Sopenharmony_ci return; 47618c2ecf20Sopenharmony_ci } 47628c2ecf20Sopenharmony_ci 47638c2ecf20Sopenharmony_ci ice_restore_all_vfs_msi_state(pdev); 47648c2ecf20Sopenharmony_ci 47658c2ecf20Sopenharmony_ci ice_do_reset(pf, ICE_RESET_PFR); 47668c2ecf20Sopenharmony_ci ice_service_task_restart(pf); 47678c2ecf20Sopenharmony_ci mod_timer(&pf->serv_tmr, round_jiffies(jiffies + pf->serv_tmr_period)); 47688c2ecf20Sopenharmony_ci} 47698c2ecf20Sopenharmony_ci 47708c2ecf20Sopenharmony_ci/** 47718c2ecf20Sopenharmony_ci * ice_pci_err_reset_prepare - prepare device driver for PCI reset 47728c2ecf20Sopenharmony_ci * @pdev: PCI device information struct 47738c2ecf20Sopenharmony_ci */ 47748c2ecf20Sopenharmony_cistatic void ice_pci_err_reset_prepare(struct pci_dev *pdev) 47758c2ecf20Sopenharmony_ci{ 47768c2ecf20Sopenharmony_ci struct ice_pf *pf = pci_get_drvdata(pdev); 47778c2ecf20Sopenharmony_ci 47788c2ecf20Sopenharmony_ci if (!test_bit(__ICE_SUSPENDED, pf->state)) { 47798c2ecf20Sopenharmony_ci ice_service_task_stop(pf); 47808c2ecf20Sopenharmony_ci 47818c2ecf20Sopenharmony_ci if (!test_bit(__ICE_PREPARED_FOR_RESET, pf->state)) { 47828c2ecf20Sopenharmony_ci set_bit(__ICE_PFR_REQ, pf->state); 47838c2ecf20Sopenharmony_ci ice_prepare_for_reset(pf); 47848c2ecf20Sopenharmony_ci } 47858c2ecf20Sopenharmony_ci } 47868c2ecf20Sopenharmony_ci} 47878c2ecf20Sopenharmony_ci 47888c2ecf20Sopenharmony_ci/** 47898c2ecf20Sopenharmony_ci * ice_pci_err_reset_done - PCI reset done, device driver reset can begin 47908c2ecf20Sopenharmony_ci * @pdev: PCI device information struct 47918c2ecf20Sopenharmony_ci */ 47928c2ecf20Sopenharmony_cistatic void ice_pci_err_reset_done(struct pci_dev *pdev) 47938c2ecf20Sopenharmony_ci{ 47948c2ecf20Sopenharmony_ci ice_pci_err_resume(pdev); 47958c2ecf20Sopenharmony_ci} 47968c2ecf20Sopenharmony_ci 47978c2ecf20Sopenharmony_ci/* ice_pci_tbl - PCI Device ID Table 47988c2ecf20Sopenharmony_ci * 47998c2ecf20Sopenharmony_ci * Wildcard entries (PCI_ANY_ID) should come last 48008c2ecf20Sopenharmony_ci * Last entry must be all 0s 48018c2ecf20Sopenharmony_ci * 48028c2ecf20Sopenharmony_ci * { Vendor ID, Device ID, SubVendor ID, SubDevice ID, 48038c2ecf20Sopenharmony_ci * Class, Class Mask, private data (not used) } 48048c2ecf20Sopenharmony_ci */ 48058c2ecf20Sopenharmony_cistatic const struct pci_device_id ice_pci_tbl[] = { 48068c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E810C_BACKPLANE), 0 }, 48078c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E810C_QSFP), 0 }, 48088c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E810C_SFP), 0 }, 48098c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E810_XXV_BACKPLANE), 0 }, 48108c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E810_XXV_QSFP), 0 }, 48118c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E810_XXV_SFP), 0 }, 48128c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_BACKPLANE), 0 }, 48138c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_QSFP), 0 }, 48148c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_SFP), 0 }, 48158c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_10G_BASE_T), 0 }, 48168c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823C_SGMII), 0 }, 48178c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_BACKPLANE), 0 }, 48188c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_QSFP), 0 }, 48198c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_SFP), 0 }, 48208c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_10G_BASE_T), 0 }, 48218c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822C_SGMII), 0 }, 48228c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822L_BACKPLANE), 0 }, 48238c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822L_SFP), 0 }, 48248c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822L_10G_BASE_T), 0 }, 48258c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822L_SGMII), 0 }, 48268c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_BACKPLANE), 0 }, 48278c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_SFP), 0 }, 48288c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_10G_BASE_T), 0 }, 48298c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_1GBE), 0 }, 48308c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_QSFP), 0 }, 48318c2ecf20Sopenharmony_ci /* required last entry */ 48328c2ecf20Sopenharmony_ci { 0, } 48338c2ecf20Sopenharmony_ci}; 48348c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, ice_pci_tbl); 48358c2ecf20Sopenharmony_ci 48368c2ecf20Sopenharmony_cistatic __maybe_unused SIMPLE_DEV_PM_OPS(ice_pm_ops, ice_suspend, ice_resume); 48378c2ecf20Sopenharmony_ci 48388c2ecf20Sopenharmony_cistatic const struct pci_error_handlers ice_pci_err_handler = { 48398c2ecf20Sopenharmony_ci .error_detected = ice_pci_err_detected, 48408c2ecf20Sopenharmony_ci .slot_reset = ice_pci_err_slot_reset, 48418c2ecf20Sopenharmony_ci .reset_prepare = ice_pci_err_reset_prepare, 48428c2ecf20Sopenharmony_ci .reset_done = ice_pci_err_reset_done, 48438c2ecf20Sopenharmony_ci .resume = ice_pci_err_resume 48448c2ecf20Sopenharmony_ci}; 48458c2ecf20Sopenharmony_ci 48468c2ecf20Sopenharmony_cistatic struct pci_driver ice_driver = { 48478c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 48488c2ecf20Sopenharmony_ci .id_table = ice_pci_tbl, 48498c2ecf20Sopenharmony_ci .probe = ice_probe, 48508c2ecf20Sopenharmony_ci .remove = ice_remove, 48518c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 48528c2ecf20Sopenharmony_ci .driver.pm = &ice_pm_ops, 48538c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 48548c2ecf20Sopenharmony_ci .shutdown = ice_shutdown, 48558c2ecf20Sopenharmony_ci .sriov_configure = ice_sriov_configure, 48568c2ecf20Sopenharmony_ci .err_handler = &ice_pci_err_handler 48578c2ecf20Sopenharmony_ci}; 48588c2ecf20Sopenharmony_ci 48598c2ecf20Sopenharmony_ci/** 48608c2ecf20Sopenharmony_ci * ice_module_init - Driver registration routine 48618c2ecf20Sopenharmony_ci * 48628c2ecf20Sopenharmony_ci * ice_module_init is the first routine called when the driver is 48638c2ecf20Sopenharmony_ci * loaded. All it does is register with the PCI subsystem. 48648c2ecf20Sopenharmony_ci */ 48658c2ecf20Sopenharmony_cistatic int __init ice_module_init(void) 48668c2ecf20Sopenharmony_ci{ 48678c2ecf20Sopenharmony_ci int status; 48688c2ecf20Sopenharmony_ci 48698c2ecf20Sopenharmony_ci pr_info("%s\n", ice_driver_string); 48708c2ecf20Sopenharmony_ci pr_info("%s\n", ice_copyright); 48718c2ecf20Sopenharmony_ci 48728c2ecf20Sopenharmony_ci ice_wq = alloc_workqueue("%s", 0, 0, KBUILD_MODNAME); 48738c2ecf20Sopenharmony_ci if (!ice_wq) { 48748c2ecf20Sopenharmony_ci pr_err("Failed to create workqueue\n"); 48758c2ecf20Sopenharmony_ci return -ENOMEM; 48768c2ecf20Sopenharmony_ci } 48778c2ecf20Sopenharmony_ci 48788c2ecf20Sopenharmony_ci status = pci_register_driver(&ice_driver); 48798c2ecf20Sopenharmony_ci if (status) { 48808c2ecf20Sopenharmony_ci pr_err("failed to register PCI driver, err %d\n", status); 48818c2ecf20Sopenharmony_ci destroy_workqueue(ice_wq); 48828c2ecf20Sopenharmony_ci } 48838c2ecf20Sopenharmony_ci 48848c2ecf20Sopenharmony_ci return status; 48858c2ecf20Sopenharmony_ci} 48868c2ecf20Sopenharmony_cimodule_init(ice_module_init); 48878c2ecf20Sopenharmony_ci 48888c2ecf20Sopenharmony_ci/** 48898c2ecf20Sopenharmony_ci * ice_module_exit - Driver exit cleanup routine 48908c2ecf20Sopenharmony_ci * 48918c2ecf20Sopenharmony_ci * ice_module_exit is called just before the driver is removed 48928c2ecf20Sopenharmony_ci * from memory. 48938c2ecf20Sopenharmony_ci */ 48948c2ecf20Sopenharmony_cistatic void __exit ice_module_exit(void) 48958c2ecf20Sopenharmony_ci{ 48968c2ecf20Sopenharmony_ci pci_unregister_driver(&ice_driver); 48978c2ecf20Sopenharmony_ci destroy_workqueue(ice_wq); 48988c2ecf20Sopenharmony_ci pr_info("module unloaded\n"); 48998c2ecf20Sopenharmony_ci} 49008c2ecf20Sopenharmony_cimodule_exit(ice_module_exit); 49018c2ecf20Sopenharmony_ci 49028c2ecf20Sopenharmony_ci/** 49038c2ecf20Sopenharmony_ci * ice_set_mac_address - NDO callback to set MAC address 49048c2ecf20Sopenharmony_ci * @netdev: network interface device structure 49058c2ecf20Sopenharmony_ci * @pi: pointer to an address structure 49068c2ecf20Sopenharmony_ci * 49078c2ecf20Sopenharmony_ci * Returns 0 on success, negative on failure 49088c2ecf20Sopenharmony_ci */ 49098c2ecf20Sopenharmony_cistatic int ice_set_mac_address(struct net_device *netdev, void *pi) 49108c2ecf20Sopenharmony_ci{ 49118c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 49128c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 49138c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 49148c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 49158c2ecf20Sopenharmony_ci struct sockaddr *addr = pi; 49168c2ecf20Sopenharmony_ci enum ice_status status; 49178c2ecf20Sopenharmony_ci u8 old_mac[ETH_ALEN]; 49188c2ecf20Sopenharmony_ci u8 flags = 0; 49198c2ecf20Sopenharmony_ci int err = 0; 49208c2ecf20Sopenharmony_ci u8 *mac; 49218c2ecf20Sopenharmony_ci 49228c2ecf20Sopenharmony_ci mac = (u8 *)addr->sa_data; 49238c2ecf20Sopenharmony_ci 49248c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(mac)) 49258c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 49268c2ecf20Sopenharmony_ci 49278c2ecf20Sopenharmony_ci if (ether_addr_equal(netdev->dev_addr, mac)) { 49288c2ecf20Sopenharmony_ci netdev_dbg(netdev, "already using mac %pM\n", mac); 49298c2ecf20Sopenharmony_ci return 0; 49308c2ecf20Sopenharmony_ci } 49318c2ecf20Sopenharmony_ci 49328c2ecf20Sopenharmony_ci if (test_bit(__ICE_DOWN, pf->state) || 49338c2ecf20Sopenharmony_ci ice_is_reset_in_progress(pf->state)) { 49348c2ecf20Sopenharmony_ci netdev_err(netdev, "can't set mac %pM. device not ready\n", 49358c2ecf20Sopenharmony_ci mac); 49368c2ecf20Sopenharmony_ci return -EBUSY; 49378c2ecf20Sopenharmony_ci } 49388c2ecf20Sopenharmony_ci 49398c2ecf20Sopenharmony_ci netif_addr_lock_bh(netdev); 49408c2ecf20Sopenharmony_ci ether_addr_copy(old_mac, netdev->dev_addr); 49418c2ecf20Sopenharmony_ci /* change the netdev's MAC address */ 49428c2ecf20Sopenharmony_ci memcpy(netdev->dev_addr, mac, netdev->addr_len); 49438c2ecf20Sopenharmony_ci netif_addr_unlock_bh(netdev); 49448c2ecf20Sopenharmony_ci 49458c2ecf20Sopenharmony_ci /* Clean up old MAC filter. Not an error if old filter doesn't exist */ 49468c2ecf20Sopenharmony_ci status = ice_fltr_remove_mac(vsi, old_mac, ICE_FWD_TO_VSI); 49478c2ecf20Sopenharmony_ci if (status && status != ICE_ERR_DOES_NOT_EXIST) { 49488c2ecf20Sopenharmony_ci err = -EADDRNOTAVAIL; 49498c2ecf20Sopenharmony_ci goto err_update_filters; 49508c2ecf20Sopenharmony_ci } 49518c2ecf20Sopenharmony_ci 49528c2ecf20Sopenharmony_ci /* Add filter for new MAC. If filter exists, return success */ 49538c2ecf20Sopenharmony_ci status = ice_fltr_add_mac(vsi, mac, ICE_FWD_TO_VSI); 49548c2ecf20Sopenharmony_ci if (status == ICE_ERR_ALREADY_EXISTS) 49558c2ecf20Sopenharmony_ci /* Although this MAC filter is already present in hardware it's 49568c2ecf20Sopenharmony_ci * possible in some cases (e.g. bonding) that dev_addr was 49578c2ecf20Sopenharmony_ci * modified outside of the driver and needs to be restored back 49588c2ecf20Sopenharmony_ci * to this value. 49598c2ecf20Sopenharmony_ci */ 49608c2ecf20Sopenharmony_ci netdev_dbg(netdev, "filter for MAC %pM already exists\n", mac); 49618c2ecf20Sopenharmony_ci else if (status) 49628c2ecf20Sopenharmony_ci /* error if the new filter addition failed */ 49638c2ecf20Sopenharmony_ci err = -EADDRNOTAVAIL; 49648c2ecf20Sopenharmony_ci 49658c2ecf20Sopenharmony_cierr_update_filters: 49668c2ecf20Sopenharmony_ci if (err) { 49678c2ecf20Sopenharmony_ci netdev_err(netdev, "can't set MAC %pM. filter update failed\n", 49688c2ecf20Sopenharmony_ci mac); 49698c2ecf20Sopenharmony_ci netif_addr_lock_bh(netdev); 49708c2ecf20Sopenharmony_ci ether_addr_copy(netdev->dev_addr, old_mac); 49718c2ecf20Sopenharmony_ci netif_addr_unlock_bh(netdev); 49728c2ecf20Sopenharmony_ci return err; 49738c2ecf20Sopenharmony_ci } 49748c2ecf20Sopenharmony_ci 49758c2ecf20Sopenharmony_ci netdev_dbg(vsi->netdev, "updated MAC address to %pM\n", 49768c2ecf20Sopenharmony_ci netdev->dev_addr); 49778c2ecf20Sopenharmony_ci 49788c2ecf20Sopenharmony_ci /* write new MAC address to the firmware */ 49798c2ecf20Sopenharmony_ci flags = ICE_AQC_MAN_MAC_UPDATE_LAA_WOL; 49808c2ecf20Sopenharmony_ci status = ice_aq_manage_mac_write(hw, mac, flags, NULL); 49818c2ecf20Sopenharmony_ci if (status) { 49828c2ecf20Sopenharmony_ci netdev_err(netdev, "can't set MAC %pM. write to firmware failed error %s\n", 49838c2ecf20Sopenharmony_ci mac, ice_stat_str(status)); 49848c2ecf20Sopenharmony_ci } 49858c2ecf20Sopenharmony_ci return 0; 49868c2ecf20Sopenharmony_ci} 49878c2ecf20Sopenharmony_ci 49888c2ecf20Sopenharmony_ci/** 49898c2ecf20Sopenharmony_ci * ice_set_rx_mode - NDO callback to set the netdev filters 49908c2ecf20Sopenharmony_ci * @netdev: network interface device structure 49918c2ecf20Sopenharmony_ci */ 49928c2ecf20Sopenharmony_cistatic void ice_set_rx_mode(struct net_device *netdev) 49938c2ecf20Sopenharmony_ci{ 49948c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 49958c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 49968c2ecf20Sopenharmony_ci 49978c2ecf20Sopenharmony_ci if (!vsi) 49988c2ecf20Sopenharmony_ci return; 49998c2ecf20Sopenharmony_ci 50008c2ecf20Sopenharmony_ci /* Set the flags to synchronize filters 50018c2ecf20Sopenharmony_ci * ndo_set_rx_mode may be triggered even without a change in netdev 50028c2ecf20Sopenharmony_ci * flags 50038c2ecf20Sopenharmony_ci */ 50048c2ecf20Sopenharmony_ci set_bit(ICE_VSI_FLAG_UMAC_FLTR_CHANGED, vsi->flags); 50058c2ecf20Sopenharmony_ci set_bit(ICE_VSI_FLAG_MMAC_FLTR_CHANGED, vsi->flags); 50068c2ecf20Sopenharmony_ci set_bit(ICE_FLAG_FLTR_SYNC, vsi->back->flags); 50078c2ecf20Sopenharmony_ci 50088c2ecf20Sopenharmony_ci /* schedule our worker thread which will take care of 50098c2ecf20Sopenharmony_ci * applying the new filter changes 50108c2ecf20Sopenharmony_ci */ 50118c2ecf20Sopenharmony_ci ice_service_task_schedule(vsi->back); 50128c2ecf20Sopenharmony_ci} 50138c2ecf20Sopenharmony_ci 50148c2ecf20Sopenharmony_ci/** 50158c2ecf20Sopenharmony_ci * ice_set_tx_maxrate - NDO callback to set the maximum per-queue bitrate 50168c2ecf20Sopenharmony_ci * @netdev: network interface device structure 50178c2ecf20Sopenharmony_ci * @queue_index: Queue ID 50188c2ecf20Sopenharmony_ci * @maxrate: maximum bandwidth in Mbps 50198c2ecf20Sopenharmony_ci */ 50208c2ecf20Sopenharmony_cistatic int 50218c2ecf20Sopenharmony_ciice_set_tx_maxrate(struct net_device *netdev, int queue_index, u32 maxrate) 50228c2ecf20Sopenharmony_ci{ 50238c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 50248c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 50258c2ecf20Sopenharmony_ci enum ice_status status; 50268c2ecf20Sopenharmony_ci u16 q_handle; 50278c2ecf20Sopenharmony_ci u8 tc; 50288c2ecf20Sopenharmony_ci 50298c2ecf20Sopenharmony_ci /* Validate maxrate requested is within permitted range */ 50308c2ecf20Sopenharmony_ci if (maxrate && (maxrate > (ICE_SCHED_MAX_BW / 1000))) { 50318c2ecf20Sopenharmony_ci netdev_err(netdev, "Invalid max rate %d specified for the queue %d\n", 50328c2ecf20Sopenharmony_ci maxrate, queue_index); 50338c2ecf20Sopenharmony_ci return -EINVAL; 50348c2ecf20Sopenharmony_ci } 50358c2ecf20Sopenharmony_ci 50368c2ecf20Sopenharmony_ci q_handle = vsi->tx_rings[queue_index]->q_handle; 50378c2ecf20Sopenharmony_ci tc = ice_dcb_get_tc(vsi, queue_index); 50388c2ecf20Sopenharmony_ci 50398c2ecf20Sopenharmony_ci /* Set BW back to default, when user set maxrate to 0 */ 50408c2ecf20Sopenharmony_ci if (!maxrate) 50418c2ecf20Sopenharmony_ci status = ice_cfg_q_bw_dflt_lmt(vsi->port_info, vsi->idx, tc, 50428c2ecf20Sopenharmony_ci q_handle, ICE_MAX_BW); 50438c2ecf20Sopenharmony_ci else 50448c2ecf20Sopenharmony_ci status = ice_cfg_q_bw_lmt(vsi->port_info, vsi->idx, tc, 50458c2ecf20Sopenharmony_ci q_handle, ICE_MAX_BW, maxrate * 1000); 50468c2ecf20Sopenharmony_ci if (status) { 50478c2ecf20Sopenharmony_ci netdev_err(netdev, "Unable to set Tx max rate, error %s\n", 50488c2ecf20Sopenharmony_ci ice_stat_str(status)); 50498c2ecf20Sopenharmony_ci return -EIO; 50508c2ecf20Sopenharmony_ci } 50518c2ecf20Sopenharmony_ci 50528c2ecf20Sopenharmony_ci return 0; 50538c2ecf20Sopenharmony_ci} 50548c2ecf20Sopenharmony_ci 50558c2ecf20Sopenharmony_ci/** 50568c2ecf20Sopenharmony_ci * ice_fdb_add - add an entry to the hardware database 50578c2ecf20Sopenharmony_ci * @ndm: the input from the stack 50588c2ecf20Sopenharmony_ci * @tb: pointer to array of nladdr (unused) 50598c2ecf20Sopenharmony_ci * @dev: the net device pointer 50608c2ecf20Sopenharmony_ci * @addr: the MAC address entry being added 50618c2ecf20Sopenharmony_ci * @vid: VLAN ID 50628c2ecf20Sopenharmony_ci * @flags: instructions from stack about fdb operation 50638c2ecf20Sopenharmony_ci * @extack: netlink extended ack 50648c2ecf20Sopenharmony_ci */ 50658c2ecf20Sopenharmony_cistatic int 50668c2ecf20Sopenharmony_ciice_fdb_add(struct ndmsg *ndm, struct nlattr __always_unused *tb[], 50678c2ecf20Sopenharmony_ci struct net_device *dev, const unsigned char *addr, u16 vid, 50688c2ecf20Sopenharmony_ci u16 flags, struct netlink_ext_ack __always_unused *extack) 50698c2ecf20Sopenharmony_ci{ 50708c2ecf20Sopenharmony_ci int err; 50718c2ecf20Sopenharmony_ci 50728c2ecf20Sopenharmony_ci if (vid) { 50738c2ecf20Sopenharmony_ci netdev_err(dev, "VLANs aren't supported yet for dev_uc|mc_add()\n"); 50748c2ecf20Sopenharmony_ci return -EINVAL; 50758c2ecf20Sopenharmony_ci } 50768c2ecf20Sopenharmony_ci if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) { 50778c2ecf20Sopenharmony_ci netdev_err(dev, "FDB only supports static addresses\n"); 50788c2ecf20Sopenharmony_ci return -EINVAL; 50798c2ecf20Sopenharmony_ci } 50808c2ecf20Sopenharmony_ci 50818c2ecf20Sopenharmony_ci if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) 50828c2ecf20Sopenharmony_ci err = dev_uc_add_excl(dev, addr); 50838c2ecf20Sopenharmony_ci else if (is_multicast_ether_addr(addr)) 50848c2ecf20Sopenharmony_ci err = dev_mc_add_excl(dev, addr); 50858c2ecf20Sopenharmony_ci else 50868c2ecf20Sopenharmony_ci err = -EINVAL; 50878c2ecf20Sopenharmony_ci 50888c2ecf20Sopenharmony_ci /* Only return duplicate errors if NLM_F_EXCL is set */ 50898c2ecf20Sopenharmony_ci if (err == -EEXIST && !(flags & NLM_F_EXCL)) 50908c2ecf20Sopenharmony_ci err = 0; 50918c2ecf20Sopenharmony_ci 50928c2ecf20Sopenharmony_ci return err; 50938c2ecf20Sopenharmony_ci} 50948c2ecf20Sopenharmony_ci 50958c2ecf20Sopenharmony_ci/** 50968c2ecf20Sopenharmony_ci * ice_fdb_del - delete an entry from the hardware database 50978c2ecf20Sopenharmony_ci * @ndm: the input from the stack 50988c2ecf20Sopenharmony_ci * @tb: pointer to array of nladdr (unused) 50998c2ecf20Sopenharmony_ci * @dev: the net device pointer 51008c2ecf20Sopenharmony_ci * @addr: the MAC address entry being added 51018c2ecf20Sopenharmony_ci * @vid: VLAN ID 51028c2ecf20Sopenharmony_ci */ 51038c2ecf20Sopenharmony_cistatic int 51048c2ecf20Sopenharmony_ciice_fdb_del(struct ndmsg *ndm, __always_unused struct nlattr *tb[], 51058c2ecf20Sopenharmony_ci struct net_device *dev, const unsigned char *addr, 51068c2ecf20Sopenharmony_ci __always_unused u16 vid) 51078c2ecf20Sopenharmony_ci{ 51088c2ecf20Sopenharmony_ci int err; 51098c2ecf20Sopenharmony_ci 51108c2ecf20Sopenharmony_ci if (ndm->ndm_state & NUD_PERMANENT) { 51118c2ecf20Sopenharmony_ci netdev_err(dev, "FDB only supports static addresses\n"); 51128c2ecf20Sopenharmony_ci return -EINVAL; 51138c2ecf20Sopenharmony_ci } 51148c2ecf20Sopenharmony_ci 51158c2ecf20Sopenharmony_ci if (is_unicast_ether_addr(addr)) 51168c2ecf20Sopenharmony_ci err = dev_uc_del(dev, addr); 51178c2ecf20Sopenharmony_ci else if (is_multicast_ether_addr(addr)) 51188c2ecf20Sopenharmony_ci err = dev_mc_del(dev, addr); 51198c2ecf20Sopenharmony_ci else 51208c2ecf20Sopenharmony_ci err = -EINVAL; 51218c2ecf20Sopenharmony_ci 51228c2ecf20Sopenharmony_ci return err; 51238c2ecf20Sopenharmony_ci} 51248c2ecf20Sopenharmony_ci 51258c2ecf20Sopenharmony_ci/** 51268c2ecf20Sopenharmony_ci * ice_set_features - set the netdev feature flags 51278c2ecf20Sopenharmony_ci * @netdev: ptr to the netdev being adjusted 51288c2ecf20Sopenharmony_ci * @features: the feature set that the stack is suggesting 51298c2ecf20Sopenharmony_ci */ 51308c2ecf20Sopenharmony_cistatic int 51318c2ecf20Sopenharmony_ciice_set_features(struct net_device *netdev, netdev_features_t features) 51328c2ecf20Sopenharmony_ci{ 51338c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 51348c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 51358c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 51368c2ecf20Sopenharmony_ci int ret = 0; 51378c2ecf20Sopenharmony_ci 51388c2ecf20Sopenharmony_ci /* Don't set any netdev advanced features with device in Safe Mode */ 51398c2ecf20Sopenharmony_ci if (ice_is_safe_mode(vsi->back)) { 51408c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "Device is in Safe Mode - not enabling advanced netdev features\n"); 51418c2ecf20Sopenharmony_ci return ret; 51428c2ecf20Sopenharmony_ci } 51438c2ecf20Sopenharmony_ci 51448c2ecf20Sopenharmony_ci /* Do not change setting during reset */ 51458c2ecf20Sopenharmony_ci if (ice_is_reset_in_progress(pf->state)) { 51468c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "Device is resetting, changing advanced netdev features temporarily unavailable.\n"); 51478c2ecf20Sopenharmony_ci return -EBUSY; 51488c2ecf20Sopenharmony_ci } 51498c2ecf20Sopenharmony_ci 51508c2ecf20Sopenharmony_ci /* Multiple features can be changed in one call so keep features in 51518c2ecf20Sopenharmony_ci * separate if/else statements to guarantee each feature is checked 51528c2ecf20Sopenharmony_ci */ 51538c2ecf20Sopenharmony_ci if (features & NETIF_F_RXHASH && !(netdev->features & NETIF_F_RXHASH)) 51548c2ecf20Sopenharmony_ci ret = ice_vsi_manage_rss_lut(vsi, true); 51558c2ecf20Sopenharmony_ci else if (!(features & NETIF_F_RXHASH) && 51568c2ecf20Sopenharmony_ci netdev->features & NETIF_F_RXHASH) 51578c2ecf20Sopenharmony_ci ret = ice_vsi_manage_rss_lut(vsi, false); 51588c2ecf20Sopenharmony_ci 51598c2ecf20Sopenharmony_ci if ((features & NETIF_F_HW_VLAN_CTAG_RX) && 51608c2ecf20Sopenharmony_ci !(netdev->features & NETIF_F_HW_VLAN_CTAG_RX)) 51618c2ecf20Sopenharmony_ci ret = ice_vsi_manage_vlan_stripping(vsi, true); 51628c2ecf20Sopenharmony_ci else if (!(features & NETIF_F_HW_VLAN_CTAG_RX) && 51638c2ecf20Sopenharmony_ci (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)) 51648c2ecf20Sopenharmony_ci ret = ice_vsi_manage_vlan_stripping(vsi, false); 51658c2ecf20Sopenharmony_ci 51668c2ecf20Sopenharmony_ci if ((features & NETIF_F_HW_VLAN_CTAG_TX) && 51678c2ecf20Sopenharmony_ci !(netdev->features & NETIF_F_HW_VLAN_CTAG_TX)) 51688c2ecf20Sopenharmony_ci ret = ice_vsi_manage_vlan_insertion(vsi); 51698c2ecf20Sopenharmony_ci else if (!(features & NETIF_F_HW_VLAN_CTAG_TX) && 51708c2ecf20Sopenharmony_ci (netdev->features & NETIF_F_HW_VLAN_CTAG_TX)) 51718c2ecf20Sopenharmony_ci ret = ice_vsi_manage_vlan_insertion(vsi); 51728c2ecf20Sopenharmony_ci 51738c2ecf20Sopenharmony_ci if ((features & NETIF_F_HW_VLAN_CTAG_FILTER) && 51748c2ecf20Sopenharmony_ci !(netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) 51758c2ecf20Sopenharmony_ci ret = ice_cfg_vlan_pruning(vsi, true, false); 51768c2ecf20Sopenharmony_ci else if (!(features & NETIF_F_HW_VLAN_CTAG_FILTER) && 51778c2ecf20Sopenharmony_ci (netdev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) 51788c2ecf20Sopenharmony_ci ret = ice_cfg_vlan_pruning(vsi, false, false); 51798c2ecf20Sopenharmony_ci 51808c2ecf20Sopenharmony_ci if ((features & NETIF_F_NTUPLE) && 51818c2ecf20Sopenharmony_ci !(netdev->features & NETIF_F_NTUPLE)) { 51828c2ecf20Sopenharmony_ci ice_vsi_manage_fdir(vsi, true); 51838c2ecf20Sopenharmony_ci ice_init_arfs(vsi); 51848c2ecf20Sopenharmony_ci } else if (!(features & NETIF_F_NTUPLE) && 51858c2ecf20Sopenharmony_ci (netdev->features & NETIF_F_NTUPLE)) { 51868c2ecf20Sopenharmony_ci ice_vsi_manage_fdir(vsi, false); 51878c2ecf20Sopenharmony_ci ice_clear_arfs(vsi); 51888c2ecf20Sopenharmony_ci } 51898c2ecf20Sopenharmony_ci 51908c2ecf20Sopenharmony_ci return ret; 51918c2ecf20Sopenharmony_ci} 51928c2ecf20Sopenharmony_ci 51938c2ecf20Sopenharmony_ci/** 51948c2ecf20Sopenharmony_ci * ice_vsi_vlan_setup - Setup VLAN offload properties on a VSI 51958c2ecf20Sopenharmony_ci * @vsi: VSI to setup VLAN properties for 51968c2ecf20Sopenharmony_ci */ 51978c2ecf20Sopenharmony_cistatic int ice_vsi_vlan_setup(struct ice_vsi *vsi) 51988c2ecf20Sopenharmony_ci{ 51998c2ecf20Sopenharmony_ci int ret = 0; 52008c2ecf20Sopenharmony_ci 52018c2ecf20Sopenharmony_ci if (vsi->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) 52028c2ecf20Sopenharmony_ci ret = ice_vsi_manage_vlan_stripping(vsi, true); 52038c2ecf20Sopenharmony_ci if (vsi->netdev->features & NETIF_F_HW_VLAN_CTAG_TX) 52048c2ecf20Sopenharmony_ci ret = ice_vsi_manage_vlan_insertion(vsi); 52058c2ecf20Sopenharmony_ci 52068c2ecf20Sopenharmony_ci return ret; 52078c2ecf20Sopenharmony_ci} 52088c2ecf20Sopenharmony_ci 52098c2ecf20Sopenharmony_ci/** 52108c2ecf20Sopenharmony_ci * ice_vsi_cfg - Setup the VSI 52118c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 52128c2ecf20Sopenharmony_ci * 52138c2ecf20Sopenharmony_ci * Return 0 on success and negative value on error 52148c2ecf20Sopenharmony_ci */ 52158c2ecf20Sopenharmony_ciint ice_vsi_cfg(struct ice_vsi *vsi) 52168c2ecf20Sopenharmony_ci{ 52178c2ecf20Sopenharmony_ci int err; 52188c2ecf20Sopenharmony_ci 52198c2ecf20Sopenharmony_ci if (vsi->netdev && vsi->type == ICE_VSI_PF) { 52208c2ecf20Sopenharmony_ci ice_set_rx_mode(vsi->netdev); 52218c2ecf20Sopenharmony_ci 52228c2ecf20Sopenharmony_ci err = ice_vsi_vlan_setup(vsi); 52238c2ecf20Sopenharmony_ci if (err) 52248c2ecf20Sopenharmony_ci return err; 52258c2ecf20Sopenharmony_ci } 52268c2ecf20Sopenharmony_ci ice_vsi_cfg_dcb_rings(vsi); 52278c2ecf20Sopenharmony_ci 52288c2ecf20Sopenharmony_ci err = ice_vsi_cfg_lan_txqs(vsi); 52298c2ecf20Sopenharmony_ci if (!err && ice_is_xdp_ena_vsi(vsi)) 52308c2ecf20Sopenharmony_ci err = ice_vsi_cfg_xdp_txqs(vsi); 52318c2ecf20Sopenharmony_ci if (!err) 52328c2ecf20Sopenharmony_ci err = ice_vsi_cfg_rxqs(vsi); 52338c2ecf20Sopenharmony_ci 52348c2ecf20Sopenharmony_ci return err; 52358c2ecf20Sopenharmony_ci} 52368c2ecf20Sopenharmony_ci 52378c2ecf20Sopenharmony_ci/** 52388c2ecf20Sopenharmony_ci * ice_napi_enable_all - Enable NAPI for all q_vectors in the VSI 52398c2ecf20Sopenharmony_ci * @vsi: the VSI being configured 52408c2ecf20Sopenharmony_ci */ 52418c2ecf20Sopenharmony_cistatic void ice_napi_enable_all(struct ice_vsi *vsi) 52428c2ecf20Sopenharmony_ci{ 52438c2ecf20Sopenharmony_ci int q_idx; 52448c2ecf20Sopenharmony_ci 52458c2ecf20Sopenharmony_ci if (!vsi->netdev) 52468c2ecf20Sopenharmony_ci return; 52478c2ecf20Sopenharmony_ci 52488c2ecf20Sopenharmony_ci ice_for_each_q_vector(vsi, q_idx) { 52498c2ecf20Sopenharmony_ci struct ice_q_vector *q_vector = vsi->q_vectors[q_idx]; 52508c2ecf20Sopenharmony_ci 52518c2ecf20Sopenharmony_ci if (q_vector->rx.ring || q_vector->tx.ring) 52528c2ecf20Sopenharmony_ci napi_enable(&q_vector->napi); 52538c2ecf20Sopenharmony_ci } 52548c2ecf20Sopenharmony_ci} 52558c2ecf20Sopenharmony_ci 52568c2ecf20Sopenharmony_ci/** 52578c2ecf20Sopenharmony_ci * ice_up_complete - Finish the last steps of bringing up a connection 52588c2ecf20Sopenharmony_ci * @vsi: The VSI being configured 52598c2ecf20Sopenharmony_ci * 52608c2ecf20Sopenharmony_ci * Return 0 on success and negative value on error 52618c2ecf20Sopenharmony_ci */ 52628c2ecf20Sopenharmony_cistatic int ice_up_complete(struct ice_vsi *vsi) 52638c2ecf20Sopenharmony_ci{ 52648c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 52658c2ecf20Sopenharmony_ci int err; 52668c2ecf20Sopenharmony_ci 52678c2ecf20Sopenharmony_ci ice_vsi_cfg_msix(vsi); 52688c2ecf20Sopenharmony_ci 52698c2ecf20Sopenharmony_ci /* Enable only Rx rings, Tx rings were enabled by the FW when the 52708c2ecf20Sopenharmony_ci * Tx queue group list was configured and the context bits were 52718c2ecf20Sopenharmony_ci * programmed using ice_vsi_cfg_txqs 52728c2ecf20Sopenharmony_ci */ 52738c2ecf20Sopenharmony_ci err = ice_vsi_start_all_rx_rings(vsi); 52748c2ecf20Sopenharmony_ci if (err) 52758c2ecf20Sopenharmony_ci return err; 52768c2ecf20Sopenharmony_ci 52778c2ecf20Sopenharmony_ci clear_bit(__ICE_DOWN, vsi->state); 52788c2ecf20Sopenharmony_ci ice_napi_enable_all(vsi); 52798c2ecf20Sopenharmony_ci ice_vsi_ena_irq(vsi); 52808c2ecf20Sopenharmony_ci 52818c2ecf20Sopenharmony_ci if (vsi->port_info && 52828c2ecf20Sopenharmony_ci (vsi->port_info->phy.link_info.link_info & ICE_AQ_LINK_UP) && 52838c2ecf20Sopenharmony_ci vsi->netdev && vsi->type == ICE_VSI_PF) { 52848c2ecf20Sopenharmony_ci ice_print_link_msg(vsi, true); 52858c2ecf20Sopenharmony_ci netif_tx_start_all_queues(vsi->netdev); 52868c2ecf20Sopenharmony_ci netif_carrier_on(vsi->netdev); 52878c2ecf20Sopenharmony_ci } 52888c2ecf20Sopenharmony_ci 52898c2ecf20Sopenharmony_ci /* Perform an initial read of the statistics registers now to 52908c2ecf20Sopenharmony_ci * set the baseline so counters are ready when interface is up 52918c2ecf20Sopenharmony_ci */ 52928c2ecf20Sopenharmony_ci ice_update_eth_stats(vsi); 52938c2ecf20Sopenharmony_ci 52948c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_PF) 52958c2ecf20Sopenharmony_ci ice_service_task_schedule(pf); 52968c2ecf20Sopenharmony_ci 52978c2ecf20Sopenharmony_ci return 0; 52988c2ecf20Sopenharmony_ci} 52998c2ecf20Sopenharmony_ci 53008c2ecf20Sopenharmony_ci/** 53018c2ecf20Sopenharmony_ci * ice_up - Bring the connection back up after being down 53028c2ecf20Sopenharmony_ci * @vsi: VSI being configured 53038c2ecf20Sopenharmony_ci */ 53048c2ecf20Sopenharmony_ciint ice_up(struct ice_vsi *vsi) 53058c2ecf20Sopenharmony_ci{ 53068c2ecf20Sopenharmony_ci int err; 53078c2ecf20Sopenharmony_ci 53088c2ecf20Sopenharmony_ci err = ice_vsi_cfg(vsi); 53098c2ecf20Sopenharmony_ci if (!err) 53108c2ecf20Sopenharmony_ci err = ice_up_complete(vsi); 53118c2ecf20Sopenharmony_ci 53128c2ecf20Sopenharmony_ci return err; 53138c2ecf20Sopenharmony_ci} 53148c2ecf20Sopenharmony_ci 53158c2ecf20Sopenharmony_ci/** 53168c2ecf20Sopenharmony_ci * ice_fetch_u64_stats_per_ring - get packets and bytes stats per ring 53178c2ecf20Sopenharmony_ci * @ring: Tx or Rx ring to read stats from 53188c2ecf20Sopenharmony_ci * @pkts: packets stats counter 53198c2ecf20Sopenharmony_ci * @bytes: bytes stats counter 53208c2ecf20Sopenharmony_ci * 53218c2ecf20Sopenharmony_ci * This function fetches stats from the ring considering the atomic operations 53228c2ecf20Sopenharmony_ci * that needs to be performed to read u64 values in 32 bit machine. 53238c2ecf20Sopenharmony_ci */ 53248c2ecf20Sopenharmony_cistatic void 53258c2ecf20Sopenharmony_ciice_fetch_u64_stats_per_ring(struct ice_ring *ring, u64 *pkts, u64 *bytes) 53268c2ecf20Sopenharmony_ci{ 53278c2ecf20Sopenharmony_ci unsigned int start; 53288c2ecf20Sopenharmony_ci *pkts = 0; 53298c2ecf20Sopenharmony_ci *bytes = 0; 53308c2ecf20Sopenharmony_ci 53318c2ecf20Sopenharmony_ci if (!ring) 53328c2ecf20Sopenharmony_ci return; 53338c2ecf20Sopenharmony_ci do { 53348c2ecf20Sopenharmony_ci start = u64_stats_fetch_begin_irq(&ring->syncp); 53358c2ecf20Sopenharmony_ci *pkts = ring->stats.pkts; 53368c2ecf20Sopenharmony_ci *bytes = ring->stats.bytes; 53378c2ecf20Sopenharmony_ci } while (u64_stats_fetch_retry_irq(&ring->syncp, start)); 53388c2ecf20Sopenharmony_ci} 53398c2ecf20Sopenharmony_ci 53408c2ecf20Sopenharmony_ci/** 53418c2ecf20Sopenharmony_ci * ice_update_vsi_tx_ring_stats - Update VSI Tx ring stats counters 53428c2ecf20Sopenharmony_ci * @vsi: the VSI to be updated 53438c2ecf20Sopenharmony_ci * @rings: rings to work on 53448c2ecf20Sopenharmony_ci * @count: number of rings 53458c2ecf20Sopenharmony_ci */ 53468c2ecf20Sopenharmony_cistatic void 53478c2ecf20Sopenharmony_ciice_update_vsi_tx_ring_stats(struct ice_vsi *vsi, struct ice_ring **rings, 53488c2ecf20Sopenharmony_ci u16 count) 53498c2ecf20Sopenharmony_ci{ 53508c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *vsi_stats = &vsi->net_stats; 53518c2ecf20Sopenharmony_ci u16 i; 53528c2ecf20Sopenharmony_ci 53538c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 53548c2ecf20Sopenharmony_ci struct ice_ring *ring; 53558c2ecf20Sopenharmony_ci u64 pkts, bytes; 53568c2ecf20Sopenharmony_ci 53578c2ecf20Sopenharmony_ci ring = READ_ONCE(rings[i]); 53588c2ecf20Sopenharmony_ci ice_fetch_u64_stats_per_ring(ring, &pkts, &bytes); 53598c2ecf20Sopenharmony_ci vsi_stats->tx_packets += pkts; 53608c2ecf20Sopenharmony_ci vsi_stats->tx_bytes += bytes; 53618c2ecf20Sopenharmony_ci vsi->tx_restart += ring->tx_stats.restart_q; 53628c2ecf20Sopenharmony_ci vsi->tx_busy += ring->tx_stats.tx_busy; 53638c2ecf20Sopenharmony_ci vsi->tx_linearize += ring->tx_stats.tx_linearize; 53648c2ecf20Sopenharmony_ci } 53658c2ecf20Sopenharmony_ci} 53668c2ecf20Sopenharmony_ci 53678c2ecf20Sopenharmony_ci/** 53688c2ecf20Sopenharmony_ci * ice_update_vsi_ring_stats - Update VSI stats counters 53698c2ecf20Sopenharmony_ci * @vsi: the VSI to be updated 53708c2ecf20Sopenharmony_ci */ 53718c2ecf20Sopenharmony_cistatic void ice_update_vsi_ring_stats(struct ice_vsi *vsi) 53728c2ecf20Sopenharmony_ci{ 53738c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *vsi_stats = &vsi->net_stats; 53748c2ecf20Sopenharmony_ci struct ice_ring *ring; 53758c2ecf20Sopenharmony_ci u64 pkts, bytes; 53768c2ecf20Sopenharmony_ci int i; 53778c2ecf20Sopenharmony_ci 53788c2ecf20Sopenharmony_ci /* reset netdev stats */ 53798c2ecf20Sopenharmony_ci vsi_stats->tx_packets = 0; 53808c2ecf20Sopenharmony_ci vsi_stats->tx_bytes = 0; 53818c2ecf20Sopenharmony_ci vsi_stats->rx_packets = 0; 53828c2ecf20Sopenharmony_ci vsi_stats->rx_bytes = 0; 53838c2ecf20Sopenharmony_ci 53848c2ecf20Sopenharmony_ci /* reset non-netdev (extended) stats */ 53858c2ecf20Sopenharmony_ci vsi->tx_restart = 0; 53868c2ecf20Sopenharmony_ci vsi->tx_busy = 0; 53878c2ecf20Sopenharmony_ci vsi->tx_linearize = 0; 53888c2ecf20Sopenharmony_ci vsi->rx_buf_failed = 0; 53898c2ecf20Sopenharmony_ci vsi->rx_page_failed = 0; 53908c2ecf20Sopenharmony_ci vsi->rx_gro_dropped = 0; 53918c2ecf20Sopenharmony_ci 53928c2ecf20Sopenharmony_ci rcu_read_lock(); 53938c2ecf20Sopenharmony_ci 53948c2ecf20Sopenharmony_ci /* update Tx rings counters */ 53958c2ecf20Sopenharmony_ci ice_update_vsi_tx_ring_stats(vsi, vsi->tx_rings, vsi->num_txq); 53968c2ecf20Sopenharmony_ci 53978c2ecf20Sopenharmony_ci /* update Rx rings counters */ 53988c2ecf20Sopenharmony_ci ice_for_each_rxq(vsi, i) { 53998c2ecf20Sopenharmony_ci ring = READ_ONCE(vsi->rx_rings[i]); 54008c2ecf20Sopenharmony_ci ice_fetch_u64_stats_per_ring(ring, &pkts, &bytes); 54018c2ecf20Sopenharmony_ci vsi_stats->rx_packets += pkts; 54028c2ecf20Sopenharmony_ci vsi_stats->rx_bytes += bytes; 54038c2ecf20Sopenharmony_ci vsi->rx_buf_failed += ring->rx_stats.alloc_buf_failed; 54048c2ecf20Sopenharmony_ci vsi->rx_page_failed += ring->rx_stats.alloc_page_failed; 54058c2ecf20Sopenharmony_ci vsi->rx_gro_dropped += ring->rx_stats.gro_dropped; 54068c2ecf20Sopenharmony_ci } 54078c2ecf20Sopenharmony_ci 54088c2ecf20Sopenharmony_ci /* update XDP Tx rings counters */ 54098c2ecf20Sopenharmony_ci if (ice_is_xdp_ena_vsi(vsi)) 54108c2ecf20Sopenharmony_ci ice_update_vsi_tx_ring_stats(vsi, vsi->xdp_rings, 54118c2ecf20Sopenharmony_ci vsi->num_xdp_txq); 54128c2ecf20Sopenharmony_ci 54138c2ecf20Sopenharmony_ci rcu_read_unlock(); 54148c2ecf20Sopenharmony_ci} 54158c2ecf20Sopenharmony_ci 54168c2ecf20Sopenharmony_ci/** 54178c2ecf20Sopenharmony_ci * ice_update_vsi_stats - Update VSI stats counters 54188c2ecf20Sopenharmony_ci * @vsi: the VSI to be updated 54198c2ecf20Sopenharmony_ci */ 54208c2ecf20Sopenharmony_civoid ice_update_vsi_stats(struct ice_vsi *vsi) 54218c2ecf20Sopenharmony_ci{ 54228c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *cur_ns = &vsi->net_stats; 54238c2ecf20Sopenharmony_ci struct ice_eth_stats *cur_es = &vsi->eth_stats; 54248c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 54258c2ecf20Sopenharmony_ci 54268c2ecf20Sopenharmony_ci if (test_bit(__ICE_DOWN, vsi->state) || 54278c2ecf20Sopenharmony_ci test_bit(__ICE_CFG_BUSY, pf->state)) 54288c2ecf20Sopenharmony_ci return; 54298c2ecf20Sopenharmony_ci 54308c2ecf20Sopenharmony_ci /* get stats as recorded by Tx/Rx rings */ 54318c2ecf20Sopenharmony_ci ice_update_vsi_ring_stats(vsi); 54328c2ecf20Sopenharmony_ci 54338c2ecf20Sopenharmony_ci /* get VSI stats as recorded by the hardware */ 54348c2ecf20Sopenharmony_ci ice_update_eth_stats(vsi); 54358c2ecf20Sopenharmony_ci 54368c2ecf20Sopenharmony_ci cur_ns->tx_errors = cur_es->tx_errors; 54378c2ecf20Sopenharmony_ci cur_ns->rx_dropped = cur_es->rx_discards + vsi->rx_gro_dropped; 54388c2ecf20Sopenharmony_ci cur_ns->tx_dropped = cur_es->tx_discards; 54398c2ecf20Sopenharmony_ci cur_ns->multicast = cur_es->rx_multicast; 54408c2ecf20Sopenharmony_ci 54418c2ecf20Sopenharmony_ci /* update some more netdev stats if this is main VSI */ 54428c2ecf20Sopenharmony_ci if (vsi->type == ICE_VSI_PF) { 54438c2ecf20Sopenharmony_ci cur_ns->rx_crc_errors = pf->stats.crc_errors; 54448c2ecf20Sopenharmony_ci cur_ns->rx_errors = pf->stats.crc_errors + 54458c2ecf20Sopenharmony_ci pf->stats.illegal_bytes + 54468c2ecf20Sopenharmony_ci pf->stats.rx_len_errors + 54478c2ecf20Sopenharmony_ci pf->stats.rx_undersize + 54488c2ecf20Sopenharmony_ci pf->hw_csum_rx_error + 54498c2ecf20Sopenharmony_ci pf->stats.rx_jabber + 54508c2ecf20Sopenharmony_ci pf->stats.rx_fragments + 54518c2ecf20Sopenharmony_ci pf->stats.rx_oversize; 54528c2ecf20Sopenharmony_ci cur_ns->rx_length_errors = pf->stats.rx_len_errors; 54538c2ecf20Sopenharmony_ci /* record drops from the port level */ 54548c2ecf20Sopenharmony_ci cur_ns->rx_missed_errors = pf->stats.eth.rx_discards; 54558c2ecf20Sopenharmony_ci } 54568c2ecf20Sopenharmony_ci} 54578c2ecf20Sopenharmony_ci 54588c2ecf20Sopenharmony_ci/** 54598c2ecf20Sopenharmony_ci * ice_update_pf_stats - Update PF port stats counters 54608c2ecf20Sopenharmony_ci * @pf: PF whose stats needs to be updated 54618c2ecf20Sopenharmony_ci */ 54628c2ecf20Sopenharmony_civoid ice_update_pf_stats(struct ice_pf *pf) 54638c2ecf20Sopenharmony_ci{ 54648c2ecf20Sopenharmony_ci struct ice_hw_port_stats *prev_ps, *cur_ps; 54658c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 54668c2ecf20Sopenharmony_ci u16 fd_ctr_base; 54678c2ecf20Sopenharmony_ci u8 port; 54688c2ecf20Sopenharmony_ci 54698c2ecf20Sopenharmony_ci port = hw->port_info->lport; 54708c2ecf20Sopenharmony_ci prev_ps = &pf->stats_prev; 54718c2ecf20Sopenharmony_ci cur_ps = &pf->stats; 54728c2ecf20Sopenharmony_ci 54738c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_GORCL(port), pf->stat_prev_loaded, 54748c2ecf20Sopenharmony_ci &prev_ps->eth.rx_bytes, 54758c2ecf20Sopenharmony_ci &cur_ps->eth.rx_bytes); 54768c2ecf20Sopenharmony_ci 54778c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_UPRCL(port), pf->stat_prev_loaded, 54788c2ecf20Sopenharmony_ci &prev_ps->eth.rx_unicast, 54798c2ecf20Sopenharmony_ci &cur_ps->eth.rx_unicast); 54808c2ecf20Sopenharmony_ci 54818c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_MPRCL(port), pf->stat_prev_loaded, 54828c2ecf20Sopenharmony_ci &prev_ps->eth.rx_multicast, 54838c2ecf20Sopenharmony_ci &cur_ps->eth.rx_multicast); 54848c2ecf20Sopenharmony_ci 54858c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_BPRCL(port), pf->stat_prev_loaded, 54868c2ecf20Sopenharmony_ci &prev_ps->eth.rx_broadcast, 54878c2ecf20Sopenharmony_ci &cur_ps->eth.rx_broadcast); 54888c2ecf20Sopenharmony_ci 54898c2ecf20Sopenharmony_ci ice_stat_update32(hw, PRTRPB_RDPC, pf->stat_prev_loaded, 54908c2ecf20Sopenharmony_ci &prev_ps->eth.rx_discards, 54918c2ecf20Sopenharmony_ci &cur_ps->eth.rx_discards); 54928c2ecf20Sopenharmony_ci 54938c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_GOTCL(port), pf->stat_prev_loaded, 54948c2ecf20Sopenharmony_ci &prev_ps->eth.tx_bytes, 54958c2ecf20Sopenharmony_ci &cur_ps->eth.tx_bytes); 54968c2ecf20Sopenharmony_ci 54978c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_UPTCL(port), pf->stat_prev_loaded, 54988c2ecf20Sopenharmony_ci &prev_ps->eth.tx_unicast, 54998c2ecf20Sopenharmony_ci &cur_ps->eth.tx_unicast); 55008c2ecf20Sopenharmony_ci 55018c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_MPTCL(port), pf->stat_prev_loaded, 55028c2ecf20Sopenharmony_ci &prev_ps->eth.tx_multicast, 55038c2ecf20Sopenharmony_ci &cur_ps->eth.tx_multicast); 55048c2ecf20Sopenharmony_ci 55058c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_BPTCL(port), pf->stat_prev_loaded, 55068c2ecf20Sopenharmony_ci &prev_ps->eth.tx_broadcast, 55078c2ecf20Sopenharmony_ci &cur_ps->eth.tx_broadcast); 55088c2ecf20Sopenharmony_ci 55098c2ecf20Sopenharmony_ci ice_stat_update32(hw, GLPRT_TDOLD(port), pf->stat_prev_loaded, 55108c2ecf20Sopenharmony_ci &prev_ps->tx_dropped_link_down, 55118c2ecf20Sopenharmony_ci &cur_ps->tx_dropped_link_down); 55128c2ecf20Sopenharmony_ci 55138c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_PRC64L(port), pf->stat_prev_loaded, 55148c2ecf20Sopenharmony_ci &prev_ps->rx_size_64, &cur_ps->rx_size_64); 55158c2ecf20Sopenharmony_ci 55168c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_PRC127L(port), pf->stat_prev_loaded, 55178c2ecf20Sopenharmony_ci &prev_ps->rx_size_127, &cur_ps->rx_size_127); 55188c2ecf20Sopenharmony_ci 55198c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_PRC255L(port), pf->stat_prev_loaded, 55208c2ecf20Sopenharmony_ci &prev_ps->rx_size_255, &cur_ps->rx_size_255); 55218c2ecf20Sopenharmony_ci 55228c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_PRC511L(port), pf->stat_prev_loaded, 55238c2ecf20Sopenharmony_ci &prev_ps->rx_size_511, &cur_ps->rx_size_511); 55248c2ecf20Sopenharmony_ci 55258c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_PRC1023L(port), pf->stat_prev_loaded, 55268c2ecf20Sopenharmony_ci &prev_ps->rx_size_1023, &cur_ps->rx_size_1023); 55278c2ecf20Sopenharmony_ci 55288c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_PRC1522L(port), pf->stat_prev_loaded, 55298c2ecf20Sopenharmony_ci &prev_ps->rx_size_1522, &cur_ps->rx_size_1522); 55308c2ecf20Sopenharmony_ci 55318c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_PRC9522L(port), pf->stat_prev_loaded, 55328c2ecf20Sopenharmony_ci &prev_ps->rx_size_big, &cur_ps->rx_size_big); 55338c2ecf20Sopenharmony_ci 55348c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_PTC64L(port), pf->stat_prev_loaded, 55358c2ecf20Sopenharmony_ci &prev_ps->tx_size_64, &cur_ps->tx_size_64); 55368c2ecf20Sopenharmony_ci 55378c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_PTC127L(port), pf->stat_prev_loaded, 55388c2ecf20Sopenharmony_ci &prev_ps->tx_size_127, &cur_ps->tx_size_127); 55398c2ecf20Sopenharmony_ci 55408c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_PTC255L(port), pf->stat_prev_loaded, 55418c2ecf20Sopenharmony_ci &prev_ps->tx_size_255, &cur_ps->tx_size_255); 55428c2ecf20Sopenharmony_ci 55438c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_PTC511L(port), pf->stat_prev_loaded, 55448c2ecf20Sopenharmony_ci &prev_ps->tx_size_511, &cur_ps->tx_size_511); 55458c2ecf20Sopenharmony_ci 55468c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_PTC1023L(port), pf->stat_prev_loaded, 55478c2ecf20Sopenharmony_ci &prev_ps->tx_size_1023, &cur_ps->tx_size_1023); 55488c2ecf20Sopenharmony_ci 55498c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_PTC1522L(port), pf->stat_prev_loaded, 55508c2ecf20Sopenharmony_ci &prev_ps->tx_size_1522, &cur_ps->tx_size_1522); 55518c2ecf20Sopenharmony_ci 55528c2ecf20Sopenharmony_ci ice_stat_update40(hw, GLPRT_PTC9522L(port), pf->stat_prev_loaded, 55538c2ecf20Sopenharmony_ci &prev_ps->tx_size_big, &cur_ps->tx_size_big); 55548c2ecf20Sopenharmony_ci 55558c2ecf20Sopenharmony_ci fd_ctr_base = hw->fd_ctr_base; 55568c2ecf20Sopenharmony_ci 55578c2ecf20Sopenharmony_ci ice_stat_update40(hw, 55588c2ecf20Sopenharmony_ci GLSTAT_FD_CNT0L(ICE_FD_SB_STAT_IDX(fd_ctr_base)), 55598c2ecf20Sopenharmony_ci pf->stat_prev_loaded, &prev_ps->fd_sb_match, 55608c2ecf20Sopenharmony_ci &cur_ps->fd_sb_match); 55618c2ecf20Sopenharmony_ci ice_stat_update32(hw, GLPRT_LXONRXC(port), pf->stat_prev_loaded, 55628c2ecf20Sopenharmony_ci &prev_ps->link_xon_rx, &cur_ps->link_xon_rx); 55638c2ecf20Sopenharmony_ci 55648c2ecf20Sopenharmony_ci ice_stat_update32(hw, GLPRT_LXOFFRXC(port), pf->stat_prev_loaded, 55658c2ecf20Sopenharmony_ci &prev_ps->link_xoff_rx, &cur_ps->link_xoff_rx); 55668c2ecf20Sopenharmony_ci 55678c2ecf20Sopenharmony_ci ice_stat_update32(hw, GLPRT_LXONTXC(port), pf->stat_prev_loaded, 55688c2ecf20Sopenharmony_ci &prev_ps->link_xon_tx, &cur_ps->link_xon_tx); 55698c2ecf20Sopenharmony_ci 55708c2ecf20Sopenharmony_ci ice_stat_update32(hw, GLPRT_LXOFFTXC(port), pf->stat_prev_loaded, 55718c2ecf20Sopenharmony_ci &prev_ps->link_xoff_tx, &cur_ps->link_xoff_tx); 55728c2ecf20Sopenharmony_ci 55738c2ecf20Sopenharmony_ci ice_update_dcb_stats(pf); 55748c2ecf20Sopenharmony_ci 55758c2ecf20Sopenharmony_ci ice_stat_update32(hw, GLPRT_CRCERRS(port), pf->stat_prev_loaded, 55768c2ecf20Sopenharmony_ci &prev_ps->crc_errors, &cur_ps->crc_errors); 55778c2ecf20Sopenharmony_ci 55788c2ecf20Sopenharmony_ci ice_stat_update32(hw, GLPRT_ILLERRC(port), pf->stat_prev_loaded, 55798c2ecf20Sopenharmony_ci &prev_ps->illegal_bytes, &cur_ps->illegal_bytes); 55808c2ecf20Sopenharmony_ci 55818c2ecf20Sopenharmony_ci ice_stat_update32(hw, GLPRT_MLFC(port), pf->stat_prev_loaded, 55828c2ecf20Sopenharmony_ci &prev_ps->mac_local_faults, 55838c2ecf20Sopenharmony_ci &cur_ps->mac_local_faults); 55848c2ecf20Sopenharmony_ci 55858c2ecf20Sopenharmony_ci ice_stat_update32(hw, GLPRT_MRFC(port), pf->stat_prev_loaded, 55868c2ecf20Sopenharmony_ci &prev_ps->mac_remote_faults, 55878c2ecf20Sopenharmony_ci &cur_ps->mac_remote_faults); 55888c2ecf20Sopenharmony_ci 55898c2ecf20Sopenharmony_ci ice_stat_update32(hw, GLPRT_RLEC(port), pf->stat_prev_loaded, 55908c2ecf20Sopenharmony_ci &prev_ps->rx_len_errors, &cur_ps->rx_len_errors); 55918c2ecf20Sopenharmony_ci 55928c2ecf20Sopenharmony_ci ice_stat_update32(hw, GLPRT_RUC(port), pf->stat_prev_loaded, 55938c2ecf20Sopenharmony_ci &prev_ps->rx_undersize, &cur_ps->rx_undersize); 55948c2ecf20Sopenharmony_ci 55958c2ecf20Sopenharmony_ci ice_stat_update32(hw, GLPRT_RFC(port), pf->stat_prev_loaded, 55968c2ecf20Sopenharmony_ci &prev_ps->rx_fragments, &cur_ps->rx_fragments); 55978c2ecf20Sopenharmony_ci 55988c2ecf20Sopenharmony_ci ice_stat_update32(hw, GLPRT_ROC(port), pf->stat_prev_loaded, 55998c2ecf20Sopenharmony_ci &prev_ps->rx_oversize, &cur_ps->rx_oversize); 56008c2ecf20Sopenharmony_ci 56018c2ecf20Sopenharmony_ci ice_stat_update32(hw, GLPRT_RJC(port), pf->stat_prev_loaded, 56028c2ecf20Sopenharmony_ci &prev_ps->rx_jabber, &cur_ps->rx_jabber); 56038c2ecf20Sopenharmony_ci 56048c2ecf20Sopenharmony_ci cur_ps->fd_sb_status = test_bit(ICE_FLAG_FD_ENA, pf->flags) ? 1 : 0; 56058c2ecf20Sopenharmony_ci 56068c2ecf20Sopenharmony_ci pf->stat_prev_loaded = true; 56078c2ecf20Sopenharmony_ci} 56088c2ecf20Sopenharmony_ci 56098c2ecf20Sopenharmony_ci/** 56108c2ecf20Sopenharmony_ci * ice_get_stats64 - get statistics for network device structure 56118c2ecf20Sopenharmony_ci * @netdev: network interface device structure 56128c2ecf20Sopenharmony_ci * @stats: main device statistics structure 56138c2ecf20Sopenharmony_ci */ 56148c2ecf20Sopenharmony_cistatic 56158c2ecf20Sopenharmony_civoid ice_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) 56168c2ecf20Sopenharmony_ci{ 56178c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 56188c2ecf20Sopenharmony_ci struct rtnl_link_stats64 *vsi_stats; 56198c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 56208c2ecf20Sopenharmony_ci 56218c2ecf20Sopenharmony_ci vsi_stats = &vsi->net_stats; 56228c2ecf20Sopenharmony_ci 56238c2ecf20Sopenharmony_ci if (!vsi->num_txq || !vsi->num_rxq) 56248c2ecf20Sopenharmony_ci return; 56258c2ecf20Sopenharmony_ci 56268c2ecf20Sopenharmony_ci /* netdev packet/byte stats come from ring counter. These are obtained 56278c2ecf20Sopenharmony_ci * by summing up ring counters (done by ice_update_vsi_ring_stats). 56288c2ecf20Sopenharmony_ci * But, only call the update routine and read the registers if VSI is 56298c2ecf20Sopenharmony_ci * not down. 56308c2ecf20Sopenharmony_ci */ 56318c2ecf20Sopenharmony_ci if (!test_bit(__ICE_DOWN, vsi->state)) 56328c2ecf20Sopenharmony_ci ice_update_vsi_ring_stats(vsi); 56338c2ecf20Sopenharmony_ci stats->tx_packets = vsi_stats->tx_packets; 56348c2ecf20Sopenharmony_ci stats->tx_bytes = vsi_stats->tx_bytes; 56358c2ecf20Sopenharmony_ci stats->rx_packets = vsi_stats->rx_packets; 56368c2ecf20Sopenharmony_ci stats->rx_bytes = vsi_stats->rx_bytes; 56378c2ecf20Sopenharmony_ci 56388c2ecf20Sopenharmony_ci /* The rest of the stats can be read from the hardware but instead we 56398c2ecf20Sopenharmony_ci * just return values that the watchdog task has already obtained from 56408c2ecf20Sopenharmony_ci * the hardware. 56418c2ecf20Sopenharmony_ci */ 56428c2ecf20Sopenharmony_ci stats->multicast = vsi_stats->multicast; 56438c2ecf20Sopenharmony_ci stats->tx_errors = vsi_stats->tx_errors; 56448c2ecf20Sopenharmony_ci stats->tx_dropped = vsi_stats->tx_dropped; 56458c2ecf20Sopenharmony_ci stats->rx_errors = vsi_stats->rx_errors; 56468c2ecf20Sopenharmony_ci stats->rx_dropped = vsi_stats->rx_dropped; 56478c2ecf20Sopenharmony_ci stats->rx_crc_errors = vsi_stats->rx_crc_errors; 56488c2ecf20Sopenharmony_ci stats->rx_length_errors = vsi_stats->rx_length_errors; 56498c2ecf20Sopenharmony_ci} 56508c2ecf20Sopenharmony_ci 56518c2ecf20Sopenharmony_ci/** 56528c2ecf20Sopenharmony_ci * ice_napi_disable_all - Disable NAPI for all q_vectors in the VSI 56538c2ecf20Sopenharmony_ci * @vsi: VSI having NAPI disabled 56548c2ecf20Sopenharmony_ci */ 56558c2ecf20Sopenharmony_cistatic void ice_napi_disable_all(struct ice_vsi *vsi) 56568c2ecf20Sopenharmony_ci{ 56578c2ecf20Sopenharmony_ci int q_idx; 56588c2ecf20Sopenharmony_ci 56598c2ecf20Sopenharmony_ci if (!vsi->netdev) 56608c2ecf20Sopenharmony_ci return; 56618c2ecf20Sopenharmony_ci 56628c2ecf20Sopenharmony_ci ice_for_each_q_vector(vsi, q_idx) { 56638c2ecf20Sopenharmony_ci struct ice_q_vector *q_vector = vsi->q_vectors[q_idx]; 56648c2ecf20Sopenharmony_ci 56658c2ecf20Sopenharmony_ci if (q_vector->rx.ring || q_vector->tx.ring) 56668c2ecf20Sopenharmony_ci napi_disable(&q_vector->napi); 56678c2ecf20Sopenharmony_ci } 56688c2ecf20Sopenharmony_ci} 56698c2ecf20Sopenharmony_ci 56708c2ecf20Sopenharmony_ci/** 56718c2ecf20Sopenharmony_ci * ice_down - Shutdown the connection 56728c2ecf20Sopenharmony_ci * @vsi: The VSI being stopped 56738c2ecf20Sopenharmony_ci */ 56748c2ecf20Sopenharmony_ciint ice_down(struct ice_vsi *vsi) 56758c2ecf20Sopenharmony_ci{ 56768c2ecf20Sopenharmony_ci int i, tx_err, rx_err, link_err = 0; 56778c2ecf20Sopenharmony_ci 56788c2ecf20Sopenharmony_ci /* Caller of this function is expected to set the 56798c2ecf20Sopenharmony_ci * vsi->state __ICE_DOWN bit 56808c2ecf20Sopenharmony_ci */ 56818c2ecf20Sopenharmony_ci if (vsi->netdev) { 56828c2ecf20Sopenharmony_ci netif_carrier_off(vsi->netdev); 56838c2ecf20Sopenharmony_ci netif_tx_disable(vsi->netdev); 56848c2ecf20Sopenharmony_ci } 56858c2ecf20Sopenharmony_ci 56868c2ecf20Sopenharmony_ci ice_vsi_dis_irq(vsi); 56878c2ecf20Sopenharmony_ci 56888c2ecf20Sopenharmony_ci tx_err = ice_vsi_stop_lan_tx_rings(vsi, ICE_NO_RESET, 0); 56898c2ecf20Sopenharmony_ci if (tx_err) 56908c2ecf20Sopenharmony_ci netdev_err(vsi->netdev, "Failed stop Tx rings, VSI %d error %d\n", 56918c2ecf20Sopenharmony_ci vsi->vsi_num, tx_err); 56928c2ecf20Sopenharmony_ci if (!tx_err && ice_is_xdp_ena_vsi(vsi)) { 56938c2ecf20Sopenharmony_ci tx_err = ice_vsi_stop_xdp_tx_rings(vsi); 56948c2ecf20Sopenharmony_ci if (tx_err) 56958c2ecf20Sopenharmony_ci netdev_err(vsi->netdev, "Failed stop XDP rings, VSI %d error %d\n", 56968c2ecf20Sopenharmony_ci vsi->vsi_num, tx_err); 56978c2ecf20Sopenharmony_ci } 56988c2ecf20Sopenharmony_ci 56998c2ecf20Sopenharmony_ci rx_err = ice_vsi_stop_all_rx_rings(vsi); 57008c2ecf20Sopenharmony_ci if (rx_err) 57018c2ecf20Sopenharmony_ci netdev_err(vsi->netdev, "Failed stop Rx rings, VSI %d error %d\n", 57028c2ecf20Sopenharmony_ci vsi->vsi_num, rx_err); 57038c2ecf20Sopenharmony_ci 57048c2ecf20Sopenharmony_ci ice_napi_disable_all(vsi); 57058c2ecf20Sopenharmony_ci 57068c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags)) { 57078c2ecf20Sopenharmony_ci link_err = ice_force_phys_link_state(vsi, false); 57088c2ecf20Sopenharmony_ci if (link_err) 57098c2ecf20Sopenharmony_ci netdev_err(vsi->netdev, "Failed to set physical link down, VSI %d error %d\n", 57108c2ecf20Sopenharmony_ci vsi->vsi_num, link_err); 57118c2ecf20Sopenharmony_ci } 57128c2ecf20Sopenharmony_ci 57138c2ecf20Sopenharmony_ci ice_for_each_txq(vsi, i) 57148c2ecf20Sopenharmony_ci ice_clean_tx_ring(vsi->tx_rings[i]); 57158c2ecf20Sopenharmony_ci 57168c2ecf20Sopenharmony_ci ice_for_each_rxq(vsi, i) 57178c2ecf20Sopenharmony_ci ice_clean_rx_ring(vsi->rx_rings[i]); 57188c2ecf20Sopenharmony_ci 57198c2ecf20Sopenharmony_ci if (tx_err || rx_err || link_err) { 57208c2ecf20Sopenharmony_ci netdev_err(vsi->netdev, "Failed to close VSI 0x%04X on switch 0x%04X\n", 57218c2ecf20Sopenharmony_ci vsi->vsi_num, vsi->vsw->sw_id); 57228c2ecf20Sopenharmony_ci return -EIO; 57238c2ecf20Sopenharmony_ci } 57248c2ecf20Sopenharmony_ci 57258c2ecf20Sopenharmony_ci return 0; 57268c2ecf20Sopenharmony_ci} 57278c2ecf20Sopenharmony_ci 57288c2ecf20Sopenharmony_ci/** 57298c2ecf20Sopenharmony_ci * ice_vsi_setup_tx_rings - Allocate VSI Tx queue resources 57308c2ecf20Sopenharmony_ci * @vsi: VSI having resources allocated 57318c2ecf20Sopenharmony_ci * 57328c2ecf20Sopenharmony_ci * Return 0 on success, negative on failure 57338c2ecf20Sopenharmony_ci */ 57348c2ecf20Sopenharmony_ciint ice_vsi_setup_tx_rings(struct ice_vsi *vsi) 57358c2ecf20Sopenharmony_ci{ 57368c2ecf20Sopenharmony_ci int i, err = 0; 57378c2ecf20Sopenharmony_ci 57388c2ecf20Sopenharmony_ci if (!vsi->num_txq) { 57398c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "VSI %d has 0 Tx queues\n", 57408c2ecf20Sopenharmony_ci vsi->vsi_num); 57418c2ecf20Sopenharmony_ci return -EINVAL; 57428c2ecf20Sopenharmony_ci } 57438c2ecf20Sopenharmony_ci 57448c2ecf20Sopenharmony_ci ice_for_each_txq(vsi, i) { 57458c2ecf20Sopenharmony_ci struct ice_ring *ring = vsi->tx_rings[i]; 57468c2ecf20Sopenharmony_ci 57478c2ecf20Sopenharmony_ci if (!ring) 57488c2ecf20Sopenharmony_ci return -EINVAL; 57498c2ecf20Sopenharmony_ci 57508c2ecf20Sopenharmony_ci ring->netdev = vsi->netdev; 57518c2ecf20Sopenharmony_ci err = ice_setup_tx_ring(ring); 57528c2ecf20Sopenharmony_ci if (err) 57538c2ecf20Sopenharmony_ci break; 57548c2ecf20Sopenharmony_ci } 57558c2ecf20Sopenharmony_ci 57568c2ecf20Sopenharmony_ci return err; 57578c2ecf20Sopenharmony_ci} 57588c2ecf20Sopenharmony_ci 57598c2ecf20Sopenharmony_ci/** 57608c2ecf20Sopenharmony_ci * ice_vsi_setup_rx_rings - Allocate VSI Rx queue resources 57618c2ecf20Sopenharmony_ci * @vsi: VSI having resources allocated 57628c2ecf20Sopenharmony_ci * 57638c2ecf20Sopenharmony_ci * Return 0 on success, negative on failure 57648c2ecf20Sopenharmony_ci */ 57658c2ecf20Sopenharmony_ciint ice_vsi_setup_rx_rings(struct ice_vsi *vsi) 57668c2ecf20Sopenharmony_ci{ 57678c2ecf20Sopenharmony_ci int i, err = 0; 57688c2ecf20Sopenharmony_ci 57698c2ecf20Sopenharmony_ci if (!vsi->num_rxq) { 57708c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "VSI %d has 0 Rx queues\n", 57718c2ecf20Sopenharmony_ci vsi->vsi_num); 57728c2ecf20Sopenharmony_ci return -EINVAL; 57738c2ecf20Sopenharmony_ci } 57748c2ecf20Sopenharmony_ci 57758c2ecf20Sopenharmony_ci ice_for_each_rxq(vsi, i) { 57768c2ecf20Sopenharmony_ci struct ice_ring *ring = vsi->rx_rings[i]; 57778c2ecf20Sopenharmony_ci 57788c2ecf20Sopenharmony_ci if (!ring) 57798c2ecf20Sopenharmony_ci return -EINVAL; 57808c2ecf20Sopenharmony_ci 57818c2ecf20Sopenharmony_ci ring->netdev = vsi->netdev; 57828c2ecf20Sopenharmony_ci err = ice_setup_rx_ring(ring); 57838c2ecf20Sopenharmony_ci if (err) 57848c2ecf20Sopenharmony_ci break; 57858c2ecf20Sopenharmony_ci } 57868c2ecf20Sopenharmony_ci 57878c2ecf20Sopenharmony_ci return err; 57888c2ecf20Sopenharmony_ci} 57898c2ecf20Sopenharmony_ci 57908c2ecf20Sopenharmony_ci/** 57918c2ecf20Sopenharmony_ci * ice_vsi_open_ctrl - open control VSI for use 57928c2ecf20Sopenharmony_ci * @vsi: the VSI to open 57938c2ecf20Sopenharmony_ci * 57948c2ecf20Sopenharmony_ci * Initialization of the Control VSI 57958c2ecf20Sopenharmony_ci * 57968c2ecf20Sopenharmony_ci * Returns 0 on success, negative value on error 57978c2ecf20Sopenharmony_ci */ 57988c2ecf20Sopenharmony_ciint ice_vsi_open_ctrl(struct ice_vsi *vsi) 57998c2ecf20Sopenharmony_ci{ 58008c2ecf20Sopenharmony_ci char int_name[ICE_INT_NAME_STR_LEN]; 58018c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 58028c2ecf20Sopenharmony_ci struct device *dev; 58038c2ecf20Sopenharmony_ci int err; 58048c2ecf20Sopenharmony_ci 58058c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 58068c2ecf20Sopenharmony_ci /* allocate descriptors */ 58078c2ecf20Sopenharmony_ci err = ice_vsi_setup_tx_rings(vsi); 58088c2ecf20Sopenharmony_ci if (err) 58098c2ecf20Sopenharmony_ci goto err_setup_tx; 58108c2ecf20Sopenharmony_ci 58118c2ecf20Sopenharmony_ci err = ice_vsi_setup_rx_rings(vsi); 58128c2ecf20Sopenharmony_ci if (err) 58138c2ecf20Sopenharmony_ci goto err_setup_rx; 58148c2ecf20Sopenharmony_ci 58158c2ecf20Sopenharmony_ci err = ice_vsi_cfg(vsi); 58168c2ecf20Sopenharmony_ci if (err) 58178c2ecf20Sopenharmony_ci goto err_setup_rx; 58188c2ecf20Sopenharmony_ci 58198c2ecf20Sopenharmony_ci snprintf(int_name, sizeof(int_name) - 1, "%s-%s:ctrl", 58208c2ecf20Sopenharmony_ci dev_driver_string(dev), dev_name(dev)); 58218c2ecf20Sopenharmony_ci err = ice_vsi_req_irq_msix(vsi, int_name); 58228c2ecf20Sopenharmony_ci if (err) 58238c2ecf20Sopenharmony_ci goto err_setup_rx; 58248c2ecf20Sopenharmony_ci 58258c2ecf20Sopenharmony_ci ice_vsi_cfg_msix(vsi); 58268c2ecf20Sopenharmony_ci 58278c2ecf20Sopenharmony_ci err = ice_vsi_start_all_rx_rings(vsi); 58288c2ecf20Sopenharmony_ci if (err) 58298c2ecf20Sopenharmony_ci goto err_up_complete; 58308c2ecf20Sopenharmony_ci 58318c2ecf20Sopenharmony_ci clear_bit(__ICE_DOWN, vsi->state); 58328c2ecf20Sopenharmony_ci ice_vsi_ena_irq(vsi); 58338c2ecf20Sopenharmony_ci 58348c2ecf20Sopenharmony_ci return 0; 58358c2ecf20Sopenharmony_ci 58368c2ecf20Sopenharmony_cierr_up_complete: 58378c2ecf20Sopenharmony_ci ice_down(vsi); 58388c2ecf20Sopenharmony_cierr_setup_rx: 58398c2ecf20Sopenharmony_ci ice_vsi_free_rx_rings(vsi); 58408c2ecf20Sopenharmony_cierr_setup_tx: 58418c2ecf20Sopenharmony_ci ice_vsi_free_tx_rings(vsi); 58428c2ecf20Sopenharmony_ci 58438c2ecf20Sopenharmony_ci return err; 58448c2ecf20Sopenharmony_ci} 58458c2ecf20Sopenharmony_ci 58468c2ecf20Sopenharmony_ci/** 58478c2ecf20Sopenharmony_ci * ice_vsi_open - Called when a network interface is made active 58488c2ecf20Sopenharmony_ci * @vsi: the VSI to open 58498c2ecf20Sopenharmony_ci * 58508c2ecf20Sopenharmony_ci * Initialization of the VSI 58518c2ecf20Sopenharmony_ci * 58528c2ecf20Sopenharmony_ci * Returns 0 on success, negative value on error 58538c2ecf20Sopenharmony_ci */ 58548c2ecf20Sopenharmony_cistatic int ice_vsi_open(struct ice_vsi *vsi) 58558c2ecf20Sopenharmony_ci{ 58568c2ecf20Sopenharmony_ci char int_name[ICE_INT_NAME_STR_LEN]; 58578c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 58588c2ecf20Sopenharmony_ci int err; 58598c2ecf20Sopenharmony_ci 58608c2ecf20Sopenharmony_ci /* allocate descriptors */ 58618c2ecf20Sopenharmony_ci err = ice_vsi_setup_tx_rings(vsi); 58628c2ecf20Sopenharmony_ci if (err) 58638c2ecf20Sopenharmony_ci goto err_setup_tx; 58648c2ecf20Sopenharmony_ci 58658c2ecf20Sopenharmony_ci err = ice_vsi_setup_rx_rings(vsi); 58668c2ecf20Sopenharmony_ci if (err) 58678c2ecf20Sopenharmony_ci goto err_setup_rx; 58688c2ecf20Sopenharmony_ci 58698c2ecf20Sopenharmony_ci err = ice_vsi_cfg(vsi); 58708c2ecf20Sopenharmony_ci if (err) 58718c2ecf20Sopenharmony_ci goto err_setup_rx; 58728c2ecf20Sopenharmony_ci 58738c2ecf20Sopenharmony_ci snprintf(int_name, sizeof(int_name) - 1, "%s-%s", 58748c2ecf20Sopenharmony_ci dev_driver_string(ice_pf_to_dev(pf)), vsi->netdev->name); 58758c2ecf20Sopenharmony_ci err = ice_vsi_req_irq_msix(vsi, int_name); 58768c2ecf20Sopenharmony_ci if (err) 58778c2ecf20Sopenharmony_ci goto err_setup_rx; 58788c2ecf20Sopenharmony_ci 58798c2ecf20Sopenharmony_ci /* Notify the stack of the actual queue counts. */ 58808c2ecf20Sopenharmony_ci err = netif_set_real_num_tx_queues(vsi->netdev, vsi->num_txq); 58818c2ecf20Sopenharmony_ci if (err) 58828c2ecf20Sopenharmony_ci goto err_set_qs; 58838c2ecf20Sopenharmony_ci 58848c2ecf20Sopenharmony_ci err = netif_set_real_num_rx_queues(vsi->netdev, vsi->num_rxq); 58858c2ecf20Sopenharmony_ci if (err) 58868c2ecf20Sopenharmony_ci goto err_set_qs; 58878c2ecf20Sopenharmony_ci 58888c2ecf20Sopenharmony_ci err = ice_up_complete(vsi); 58898c2ecf20Sopenharmony_ci if (err) 58908c2ecf20Sopenharmony_ci goto err_up_complete; 58918c2ecf20Sopenharmony_ci 58928c2ecf20Sopenharmony_ci return 0; 58938c2ecf20Sopenharmony_ci 58948c2ecf20Sopenharmony_cierr_up_complete: 58958c2ecf20Sopenharmony_ci ice_down(vsi); 58968c2ecf20Sopenharmony_cierr_set_qs: 58978c2ecf20Sopenharmony_ci ice_vsi_free_irq(vsi); 58988c2ecf20Sopenharmony_cierr_setup_rx: 58998c2ecf20Sopenharmony_ci ice_vsi_free_rx_rings(vsi); 59008c2ecf20Sopenharmony_cierr_setup_tx: 59018c2ecf20Sopenharmony_ci ice_vsi_free_tx_rings(vsi); 59028c2ecf20Sopenharmony_ci 59038c2ecf20Sopenharmony_ci return err; 59048c2ecf20Sopenharmony_ci} 59058c2ecf20Sopenharmony_ci 59068c2ecf20Sopenharmony_ci/** 59078c2ecf20Sopenharmony_ci * ice_vsi_release_all - Delete all VSIs 59088c2ecf20Sopenharmony_ci * @pf: PF from which all VSIs are being removed 59098c2ecf20Sopenharmony_ci */ 59108c2ecf20Sopenharmony_cistatic void ice_vsi_release_all(struct ice_pf *pf) 59118c2ecf20Sopenharmony_ci{ 59128c2ecf20Sopenharmony_ci int err, i; 59138c2ecf20Sopenharmony_ci 59148c2ecf20Sopenharmony_ci if (!pf->vsi) 59158c2ecf20Sopenharmony_ci return; 59168c2ecf20Sopenharmony_ci 59178c2ecf20Sopenharmony_ci ice_for_each_vsi(pf, i) { 59188c2ecf20Sopenharmony_ci if (!pf->vsi[i]) 59198c2ecf20Sopenharmony_ci continue; 59208c2ecf20Sopenharmony_ci 59218c2ecf20Sopenharmony_ci err = ice_vsi_release(pf->vsi[i]); 59228c2ecf20Sopenharmony_ci if (err) 59238c2ecf20Sopenharmony_ci dev_dbg(ice_pf_to_dev(pf), "Failed to release pf->vsi[%d], err %d, vsi_num = %d\n", 59248c2ecf20Sopenharmony_ci i, err, pf->vsi[i]->vsi_num); 59258c2ecf20Sopenharmony_ci } 59268c2ecf20Sopenharmony_ci} 59278c2ecf20Sopenharmony_ci 59288c2ecf20Sopenharmony_ci/** 59298c2ecf20Sopenharmony_ci * ice_vsi_rebuild_by_type - Rebuild VSI of a given type 59308c2ecf20Sopenharmony_ci * @pf: pointer to the PF instance 59318c2ecf20Sopenharmony_ci * @type: VSI type to rebuild 59328c2ecf20Sopenharmony_ci * 59338c2ecf20Sopenharmony_ci * Iterates through the pf->vsi array and rebuilds VSIs of the requested type 59348c2ecf20Sopenharmony_ci */ 59358c2ecf20Sopenharmony_cistatic int ice_vsi_rebuild_by_type(struct ice_pf *pf, enum ice_vsi_type type) 59368c2ecf20Sopenharmony_ci{ 59378c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 59388c2ecf20Sopenharmony_ci enum ice_status status; 59398c2ecf20Sopenharmony_ci int i, err; 59408c2ecf20Sopenharmony_ci 59418c2ecf20Sopenharmony_ci ice_for_each_vsi(pf, i) { 59428c2ecf20Sopenharmony_ci struct ice_vsi *vsi = pf->vsi[i]; 59438c2ecf20Sopenharmony_ci 59448c2ecf20Sopenharmony_ci if (!vsi || vsi->type != type) 59458c2ecf20Sopenharmony_ci continue; 59468c2ecf20Sopenharmony_ci 59478c2ecf20Sopenharmony_ci /* rebuild the VSI */ 59488c2ecf20Sopenharmony_ci err = ice_vsi_rebuild(vsi, true); 59498c2ecf20Sopenharmony_ci if (err) { 59508c2ecf20Sopenharmony_ci dev_err(dev, "rebuild VSI failed, err %d, VSI index %d, type %s\n", 59518c2ecf20Sopenharmony_ci err, vsi->idx, ice_vsi_type_str(type)); 59528c2ecf20Sopenharmony_ci return err; 59538c2ecf20Sopenharmony_ci } 59548c2ecf20Sopenharmony_ci 59558c2ecf20Sopenharmony_ci /* replay filters for the VSI */ 59568c2ecf20Sopenharmony_ci status = ice_replay_vsi(&pf->hw, vsi->idx); 59578c2ecf20Sopenharmony_ci if (status) { 59588c2ecf20Sopenharmony_ci dev_err(dev, "replay VSI failed, status %s, VSI index %d, type %s\n", 59598c2ecf20Sopenharmony_ci ice_stat_str(status), vsi->idx, 59608c2ecf20Sopenharmony_ci ice_vsi_type_str(type)); 59618c2ecf20Sopenharmony_ci return -EIO; 59628c2ecf20Sopenharmony_ci } 59638c2ecf20Sopenharmony_ci 59648c2ecf20Sopenharmony_ci /* Re-map HW VSI number, using VSI handle that has been 59658c2ecf20Sopenharmony_ci * previously validated in ice_replay_vsi() call above 59668c2ecf20Sopenharmony_ci */ 59678c2ecf20Sopenharmony_ci vsi->vsi_num = ice_get_hw_vsi_num(&pf->hw, vsi->idx); 59688c2ecf20Sopenharmony_ci 59698c2ecf20Sopenharmony_ci /* enable the VSI */ 59708c2ecf20Sopenharmony_ci err = ice_ena_vsi(vsi, false); 59718c2ecf20Sopenharmony_ci if (err) { 59728c2ecf20Sopenharmony_ci dev_err(dev, "enable VSI failed, err %d, VSI index %d, type %s\n", 59738c2ecf20Sopenharmony_ci err, vsi->idx, ice_vsi_type_str(type)); 59748c2ecf20Sopenharmony_ci return err; 59758c2ecf20Sopenharmony_ci } 59768c2ecf20Sopenharmony_ci 59778c2ecf20Sopenharmony_ci dev_info(dev, "VSI rebuilt. VSI index %d, type %s\n", vsi->idx, 59788c2ecf20Sopenharmony_ci ice_vsi_type_str(type)); 59798c2ecf20Sopenharmony_ci } 59808c2ecf20Sopenharmony_ci 59818c2ecf20Sopenharmony_ci return 0; 59828c2ecf20Sopenharmony_ci} 59838c2ecf20Sopenharmony_ci 59848c2ecf20Sopenharmony_ci/** 59858c2ecf20Sopenharmony_ci * ice_update_pf_netdev_link - Update PF netdev link status 59868c2ecf20Sopenharmony_ci * @pf: pointer to the PF instance 59878c2ecf20Sopenharmony_ci */ 59888c2ecf20Sopenharmony_cistatic void ice_update_pf_netdev_link(struct ice_pf *pf) 59898c2ecf20Sopenharmony_ci{ 59908c2ecf20Sopenharmony_ci bool link_up; 59918c2ecf20Sopenharmony_ci int i; 59928c2ecf20Sopenharmony_ci 59938c2ecf20Sopenharmony_ci ice_for_each_vsi(pf, i) { 59948c2ecf20Sopenharmony_ci struct ice_vsi *vsi = pf->vsi[i]; 59958c2ecf20Sopenharmony_ci 59968c2ecf20Sopenharmony_ci if (!vsi || vsi->type != ICE_VSI_PF) 59978c2ecf20Sopenharmony_ci return; 59988c2ecf20Sopenharmony_ci 59998c2ecf20Sopenharmony_ci ice_get_link_status(pf->vsi[i]->port_info, &link_up); 60008c2ecf20Sopenharmony_ci if (link_up) { 60018c2ecf20Sopenharmony_ci netif_carrier_on(pf->vsi[i]->netdev); 60028c2ecf20Sopenharmony_ci netif_tx_wake_all_queues(pf->vsi[i]->netdev); 60038c2ecf20Sopenharmony_ci } else { 60048c2ecf20Sopenharmony_ci netif_carrier_off(pf->vsi[i]->netdev); 60058c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(pf->vsi[i]->netdev); 60068c2ecf20Sopenharmony_ci } 60078c2ecf20Sopenharmony_ci } 60088c2ecf20Sopenharmony_ci} 60098c2ecf20Sopenharmony_ci 60108c2ecf20Sopenharmony_ci/** 60118c2ecf20Sopenharmony_ci * ice_rebuild - rebuild after reset 60128c2ecf20Sopenharmony_ci * @pf: PF to rebuild 60138c2ecf20Sopenharmony_ci * @reset_type: type of reset 60148c2ecf20Sopenharmony_ci * 60158c2ecf20Sopenharmony_ci * Do not rebuild VF VSI in this flow because that is already handled via 60168c2ecf20Sopenharmony_ci * ice_reset_all_vfs(). This is because requirements for resetting a VF after a 60178c2ecf20Sopenharmony_ci * PFR/CORER/GLOBER/etc. are different than the normal flow. Also, we don't want 60188c2ecf20Sopenharmony_ci * to reset/rebuild all the VF VSI twice. 60198c2ecf20Sopenharmony_ci */ 60208c2ecf20Sopenharmony_cistatic void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type) 60218c2ecf20Sopenharmony_ci{ 60228c2ecf20Sopenharmony_ci struct device *dev = ice_pf_to_dev(pf); 60238c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 60248c2ecf20Sopenharmony_ci enum ice_status ret; 60258c2ecf20Sopenharmony_ci int err; 60268c2ecf20Sopenharmony_ci 60278c2ecf20Sopenharmony_ci if (test_bit(__ICE_DOWN, pf->state)) 60288c2ecf20Sopenharmony_ci goto clear_recovery; 60298c2ecf20Sopenharmony_ci 60308c2ecf20Sopenharmony_ci dev_dbg(dev, "rebuilding PF after reset_type=%d\n", reset_type); 60318c2ecf20Sopenharmony_ci 60328c2ecf20Sopenharmony_ci ret = ice_init_all_ctrlq(hw); 60338c2ecf20Sopenharmony_ci if (ret) { 60348c2ecf20Sopenharmony_ci dev_err(dev, "control queues init failed %s\n", 60358c2ecf20Sopenharmony_ci ice_stat_str(ret)); 60368c2ecf20Sopenharmony_ci goto err_init_ctrlq; 60378c2ecf20Sopenharmony_ci } 60388c2ecf20Sopenharmony_ci 60398c2ecf20Sopenharmony_ci /* if DDP was previously loaded successfully */ 60408c2ecf20Sopenharmony_ci if (!ice_is_safe_mode(pf)) { 60418c2ecf20Sopenharmony_ci /* reload the SW DB of filter tables */ 60428c2ecf20Sopenharmony_ci if (reset_type == ICE_RESET_PFR) 60438c2ecf20Sopenharmony_ci ice_fill_blk_tbls(hw); 60448c2ecf20Sopenharmony_ci else 60458c2ecf20Sopenharmony_ci /* Reload DDP Package after CORER/GLOBR reset */ 60468c2ecf20Sopenharmony_ci ice_load_pkg(NULL, pf); 60478c2ecf20Sopenharmony_ci } 60488c2ecf20Sopenharmony_ci 60498c2ecf20Sopenharmony_ci ret = ice_clear_pf_cfg(hw); 60508c2ecf20Sopenharmony_ci if (ret) { 60518c2ecf20Sopenharmony_ci dev_err(dev, "clear PF configuration failed %s\n", 60528c2ecf20Sopenharmony_ci ice_stat_str(ret)); 60538c2ecf20Sopenharmony_ci goto err_init_ctrlq; 60548c2ecf20Sopenharmony_ci } 60558c2ecf20Sopenharmony_ci 60568c2ecf20Sopenharmony_ci if (pf->first_sw->dflt_vsi_ena) 60578c2ecf20Sopenharmony_ci dev_info(dev, "Clearing default VSI, re-enable after reset completes\n"); 60588c2ecf20Sopenharmony_ci /* clear the default VSI configuration if it exists */ 60598c2ecf20Sopenharmony_ci pf->first_sw->dflt_vsi = NULL; 60608c2ecf20Sopenharmony_ci pf->first_sw->dflt_vsi_ena = false; 60618c2ecf20Sopenharmony_ci 60628c2ecf20Sopenharmony_ci ice_clear_pxe_mode(hw); 60638c2ecf20Sopenharmony_ci 60648c2ecf20Sopenharmony_ci ret = ice_get_caps(hw); 60658c2ecf20Sopenharmony_ci if (ret) { 60668c2ecf20Sopenharmony_ci dev_err(dev, "ice_get_caps failed %s\n", ice_stat_str(ret)); 60678c2ecf20Sopenharmony_ci goto err_init_ctrlq; 60688c2ecf20Sopenharmony_ci } 60698c2ecf20Sopenharmony_ci 60708c2ecf20Sopenharmony_ci ret = ice_aq_set_mac_cfg(hw, ICE_AQ_SET_MAC_FRAME_SIZE_MAX, NULL); 60718c2ecf20Sopenharmony_ci if (ret) { 60728c2ecf20Sopenharmony_ci dev_err(dev, "set_mac_cfg failed %s\n", ice_stat_str(ret)); 60738c2ecf20Sopenharmony_ci goto err_init_ctrlq; 60748c2ecf20Sopenharmony_ci } 60758c2ecf20Sopenharmony_ci 60768c2ecf20Sopenharmony_ci err = ice_sched_init_port(hw->port_info); 60778c2ecf20Sopenharmony_ci if (err) 60788c2ecf20Sopenharmony_ci goto err_sched_init_port; 60798c2ecf20Sopenharmony_ci 60808c2ecf20Sopenharmony_ci /* start misc vector */ 60818c2ecf20Sopenharmony_ci err = ice_req_irq_msix_misc(pf); 60828c2ecf20Sopenharmony_ci if (err) { 60838c2ecf20Sopenharmony_ci dev_err(dev, "misc vector setup failed: %d\n", err); 60848c2ecf20Sopenharmony_ci goto err_sched_init_port; 60858c2ecf20Sopenharmony_ci } 60868c2ecf20Sopenharmony_ci 60878c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_FD_ENA, pf->flags)) { 60888c2ecf20Sopenharmony_ci wr32(hw, PFQF_FD_ENA, PFQF_FD_ENA_FD_ENA_M); 60898c2ecf20Sopenharmony_ci if (!rd32(hw, PFQF_FD_SIZE)) { 60908c2ecf20Sopenharmony_ci u16 unused, guar, b_effort; 60918c2ecf20Sopenharmony_ci 60928c2ecf20Sopenharmony_ci guar = hw->func_caps.fd_fltr_guar; 60938c2ecf20Sopenharmony_ci b_effort = hw->func_caps.fd_fltr_best_effort; 60948c2ecf20Sopenharmony_ci 60958c2ecf20Sopenharmony_ci /* force guaranteed filter pool for PF */ 60968c2ecf20Sopenharmony_ci ice_alloc_fd_guar_item(hw, &unused, guar); 60978c2ecf20Sopenharmony_ci /* force shared filter pool for PF */ 60988c2ecf20Sopenharmony_ci ice_alloc_fd_shrd_item(hw, &unused, b_effort); 60998c2ecf20Sopenharmony_ci } 61008c2ecf20Sopenharmony_ci } 61018c2ecf20Sopenharmony_ci 61028c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_DCB_ENA, pf->flags)) 61038c2ecf20Sopenharmony_ci ice_dcb_rebuild(pf); 61048c2ecf20Sopenharmony_ci 61058c2ecf20Sopenharmony_ci /* rebuild PF VSI */ 61068c2ecf20Sopenharmony_ci err = ice_vsi_rebuild_by_type(pf, ICE_VSI_PF); 61078c2ecf20Sopenharmony_ci if (err) { 61088c2ecf20Sopenharmony_ci dev_err(dev, "PF VSI rebuild failed: %d\n", err); 61098c2ecf20Sopenharmony_ci goto err_vsi_rebuild; 61108c2ecf20Sopenharmony_ci } 61118c2ecf20Sopenharmony_ci 61128c2ecf20Sopenharmony_ci /* If Flow Director is active */ 61138c2ecf20Sopenharmony_ci if (test_bit(ICE_FLAG_FD_ENA, pf->flags)) { 61148c2ecf20Sopenharmony_ci err = ice_vsi_rebuild_by_type(pf, ICE_VSI_CTRL); 61158c2ecf20Sopenharmony_ci if (err) { 61168c2ecf20Sopenharmony_ci dev_err(dev, "control VSI rebuild failed: %d\n", err); 61178c2ecf20Sopenharmony_ci goto err_vsi_rebuild; 61188c2ecf20Sopenharmony_ci } 61198c2ecf20Sopenharmony_ci 61208c2ecf20Sopenharmony_ci /* replay HW Flow Director recipes */ 61218c2ecf20Sopenharmony_ci if (hw->fdir_prof) 61228c2ecf20Sopenharmony_ci ice_fdir_replay_flows(hw); 61238c2ecf20Sopenharmony_ci 61248c2ecf20Sopenharmony_ci /* replay Flow Director filters */ 61258c2ecf20Sopenharmony_ci ice_fdir_replay_fltrs(pf); 61268c2ecf20Sopenharmony_ci 61278c2ecf20Sopenharmony_ci ice_rebuild_arfs(pf); 61288c2ecf20Sopenharmony_ci } 61298c2ecf20Sopenharmony_ci 61308c2ecf20Sopenharmony_ci ice_update_pf_netdev_link(pf); 61318c2ecf20Sopenharmony_ci 61328c2ecf20Sopenharmony_ci /* tell the firmware we are up */ 61338c2ecf20Sopenharmony_ci ret = ice_send_version(pf); 61348c2ecf20Sopenharmony_ci if (ret) { 61358c2ecf20Sopenharmony_ci dev_err(dev, "Rebuild failed due to error sending driver version: %s\n", 61368c2ecf20Sopenharmony_ci ice_stat_str(ret)); 61378c2ecf20Sopenharmony_ci goto err_vsi_rebuild; 61388c2ecf20Sopenharmony_ci } 61398c2ecf20Sopenharmony_ci 61408c2ecf20Sopenharmony_ci ice_replay_post(hw); 61418c2ecf20Sopenharmony_ci 61428c2ecf20Sopenharmony_ci /* if we get here, reset flow is successful */ 61438c2ecf20Sopenharmony_ci clear_bit(__ICE_RESET_FAILED, pf->state); 61448c2ecf20Sopenharmony_ci return; 61458c2ecf20Sopenharmony_ci 61468c2ecf20Sopenharmony_cierr_vsi_rebuild: 61478c2ecf20Sopenharmony_cierr_sched_init_port: 61488c2ecf20Sopenharmony_ci ice_sched_cleanup_all(hw); 61498c2ecf20Sopenharmony_cierr_init_ctrlq: 61508c2ecf20Sopenharmony_ci ice_shutdown_all_ctrlq(hw); 61518c2ecf20Sopenharmony_ci set_bit(__ICE_RESET_FAILED, pf->state); 61528c2ecf20Sopenharmony_ciclear_recovery: 61538c2ecf20Sopenharmony_ci /* set this bit in PF state to control service task scheduling */ 61548c2ecf20Sopenharmony_ci set_bit(__ICE_NEEDS_RESTART, pf->state); 61558c2ecf20Sopenharmony_ci dev_err(dev, "Rebuild failed, unload and reload driver\n"); 61568c2ecf20Sopenharmony_ci} 61578c2ecf20Sopenharmony_ci 61588c2ecf20Sopenharmony_ci/** 61598c2ecf20Sopenharmony_ci * ice_max_xdp_frame_size - returns the maximum allowed frame size for XDP 61608c2ecf20Sopenharmony_ci * @vsi: Pointer to VSI structure 61618c2ecf20Sopenharmony_ci */ 61628c2ecf20Sopenharmony_cistatic int ice_max_xdp_frame_size(struct ice_vsi *vsi) 61638c2ecf20Sopenharmony_ci{ 61648c2ecf20Sopenharmony_ci if (PAGE_SIZE >= 8192 || test_bit(ICE_FLAG_LEGACY_RX, vsi->back->flags)) 61658c2ecf20Sopenharmony_ci return ICE_RXBUF_2048 - XDP_PACKET_HEADROOM; 61668c2ecf20Sopenharmony_ci else 61678c2ecf20Sopenharmony_ci return ICE_RXBUF_3072; 61688c2ecf20Sopenharmony_ci} 61698c2ecf20Sopenharmony_ci 61708c2ecf20Sopenharmony_ci/** 61718c2ecf20Sopenharmony_ci * ice_change_mtu - NDO callback to change the MTU 61728c2ecf20Sopenharmony_ci * @netdev: network interface device structure 61738c2ecf20Sopenharmony_ci * @new_mtu: new value for maximum frame size 61748c2ecf20Sopenharmony_ci * 61758c2ecf20Sopenharmony_ci * Returns 0 on success, negative on failure 61768c2ecf20Sopenharmony_ci */ 61778c2ecf20Sopenharmony_cistatic int ice_change_mtu(struct net_device *netdev, int new_mtu) 61788c2ecf20Sopenharmony_ci{ 61798c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 61808c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 61818c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 61828c2ecf20Sopenharmony_ci u8 count = 0; 61838c2ecf20Sopenharmony_ci 61848c2ecf20Sopenharmony_ci if (new_mtu == (int)netdev->mtu) { 61858c2ecf20Sopenharmony_ci netdev_warn(netdev, "MTU is already %u\n", netdev->mtu); 61868c2ecf20Sopenharmony_ci return 0; 61878c2ecf20Sopenharmony_ci } 61888c2ecf20Sopenharmony_ci 61898c2ecf20Sopenharmony_ci if (ice_is_xdp_ena_vsi(vsi)) { 61908c2ecf20Sopenharmony_ci int frame_size = ice_max_xdp_frame_size(vsi); 61918c2ecf20Sopenharmony_ci 61928c2ecf20Sopenharmony_ci if (new_mtu + ICE_ETH_PKT_HDR_PAD > frame_size) { 61938c2ecf20Sopenharmony_ci netdev_err(netdev, "max MTU for XDP usage is %d\n", 61948c2ecf20Sopenharmony_ci frame_size - ICE_ETH_PKT_HDR_PAD); 61958c2ecf20Sopenharmony_ci return -EINVAL; 61968c2ecf20Sopenharmony_ci } 61978c2ecf20Sopenharmony_ci } 61988c2ecf20Sopenharmony_ci 61998c2ecf20Sopenharmony_ci if (new_mtu < (int)netdev->min_mtu) { 62008c2ecf20Sopenharmony_ci netdev_err(netdev, "new MTU invalid. min_mtu is %d\n", 62018c2ecf20Sopenharmony_ci netdev->min_mtu); 62028c2ecf20Sopenharmony_ci return -EINVAL; 62038c2ecf20Sopenharmony_ci } else if (new_mtu > (int)netdev->max_mtu) { 62048c2ecf20Sopenharmony_ci netdev_err(netdev, "new MTU invalid. max_mtu is %d\n", 62058c2ecf20Sopenharmony_ci netdev->min_mtu); 62068c2ecf20Sopenharmony_ci return -EINVAL; 62078c2ecf20Sopenharmony_ci } 62088c2ecf20Sopenharmony_ci /* if a reset is in progress, wait for some time for it to complete */ 62098c2ecf20Sopenharmony_ci do { 62108c2ecf20Sopenharmony_ci if (ice_is_reset_in_progress(pf->state)) { 62118c2ecf20Sopenharmony_ci count++; 62128c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 62138c2ecf20Sopenharmony_ci } else { 62148c2ecf20Sopenharmony_ci break; 62158c2ecf20Sopenharmony_ci } 62168c2ecf20Sopenharmony_ci 62178c2ecf20Sopenharmony_ci } while (count < 100); 62188c2ecf20Sopenharmony_ci 62198c2ecf20Sopenharmony_ci if (count == 100) { 62208c2ecf20Sopenharmony_ci netdev_err(netdev, "can't change MTU. Device is busy\n"); 62218c2ecf20Sopenharmony_ci return -EBUSY; 62228c2ecf20Sopenharmony_ci } 62238c2ecf20Sopenharmony_ci 62248c2ecf20Sopenharmony_ci netdev->mtu = (unsigned int)new_mtu; 62258c2ecf20Sopenharmony_ci 62268c2ecf20Sopenharmony_ci /* if VSI is up, bring it down and then back up */ 62278c2ecf20Sopenharmony_ci if (!test_and_set_bit(__ICE_DOWN, vsi->state)) { 62288c2ecf20Sopenharmony_ci int err; 62298c2ecf20Sopenharmony_ci 62308c2ecf20Sopenharmony_ci err = ice_down(vsi); 62318c2ecf20Sopenharmony_ci if (err) { 62328c2ecf20Sopenharmony_ci netdev_err(netdev, "change MTU if_up err %d\n", err); 62338c2ecf20Sopenharmony_ci return err; 62348c2ecf20Sopenharmony_ci } 62358c2ecf20Sopenharmony_ci 62368c2ecf20Sopenharmony_ci err = ice_up(vsi); 62378c2ecf20Sopenharmony_ci if (err) { 62388c2ecf20Sopenharmony_ci netdev_err(netdev, "change MTU if_up err %d\n", err); 62398c2ecf20Sopenharmony_ci return err; 62408c2ecf20Sopenharmony_ci } 62418c2ecf20Sopenharmony_ci } 62428c2ecf20Sopenharmony_ci 62438c2ecf20Sopenharmony_ci netdev_dbg(netdev, "changed MTU to %d\n", new_mtu); 62448c2ecf20Sopenharmony_ci return 0; 62458c2ecf20Sopenharmony_ci} 62468c2ecf20Sopenharmony_ci 62478c2ecf20Sopenharmony_ci/** 62488c2ecf20Sopenharmony_ci * ice_aq_str - convert AQ err code to a string 62498c2ecf20Sopenharmony_ci * @aq_err: the AQ error code to convert 62508c2ecf20Sopenharmony_ci */ 62518c2ecf20Sopenharmony_ciconst char *ice_aq_str(enum ice_aq_err aq_err) 62528c2ecf20Sopenharmony_ci{ 62538c2ecf20Sopenharmony_ci switch (aq_err) { 62548c2ecf20Sopenharmony_ci case ICE_AQ_RC_OK: 62558c2ecf20Sopenharmony_ci return "OK"; 62568c2ecf20Sopenharmony_ci case ICE_AQ_RC_EPERM: 62578c2ecf20Sopenharmony_ci return "ICE_AQ_RC_EPERM"; 62588c2ecf20Sopenharmony_ci case ICE_AQ_RC_ENOENT: 62598c2ecf20Sopenharmony_ci return "ICE_AQ_RC_ENOENT"; 62608c2ecf20Sopenharmony_ci case ICE_AQ_RC_ENOMEM: 62618c2ecf20Sopenharmony_ci return "ICE_AQ_RC_ENOMEM"; 62628c2ecf20Sopenharmony_ci case ICE_AQ_RC_EBUSY: 62638c2ecf20Sopenharmony_ci return "ICE_AQ_RC_EBUSY"; 62648c2ecf20Sopenharmony_ci case ICE_AQ_RC_EEXIST: 62658c2ecf20Sopenharmony_ci return "ICE_AQ_RC_EEXIST"; 62668c2ecf20Sopenharmony_ci case ICE_AQ_RC_EINVAL: 62678c2ecf20Sopenharmony_ci return "ICE_AQ_RC_EINVAL"; 62688c2ecf20Sopenharmony_ci case ICE_AQ_RC_ENOSPC: 62698c2ecf20Sopenharmony_ci return "ICE_AQ_RC_ENOSPC"; 62708c2ecf20Sopenharmony_ci case ICE_AQ_RC_ENOSYS: 62718c2ecf20Sopenharmony_ci return "ICE_AQ_RC_ENOSYS"; 62728c2ecf20Sopenharmony_ci case ICE_AQ_RC_EMODE: 62738c2ecf20Sopenharmony_ci return "ICE_AQ_RC_EMODE"; 62748c2ecf20Sopenharmony_ci case ICE_AQ_RC_ENOSEC: 62758c2ecf20Sopenharmony_ci return "ICE_AQ_RC_ENOSEC"; 62768c2ecf20Sopenharmony_ci case ICE_AQ_RC_EBADSIG: 62778c2ecf20Sopenharmony_ci return "ICE_AQ_RC_EBADSIG"; 62788c2ecf20Sopenharmony_ci case ICE_AQ_RC_ESVN: 62798c2ecf20Sopenharmony_ci return "ICE_AQ_RC_ESVN"; 62808c2ecf20Sopenharmony_ci case ICE_AQ_RC_EBADMAN: 62818c2ecf20Sopenharmony_ci return "ICE_AQ_RC_EBADMAN"; 62828c2ecf20Sopenharmony_ci case ICE_AQ_RC_EBADBUF: 62838c2ecf20Sopenharmony_ci return "ICE_AQ_RC_EBADBUF"; 62848c2ecf20Sopenharmony_ci } 62858c2ecf20Sopenharmony_ci 62868c2ecf20Sopenharmony_ci return "ICE_AQ_RC_UNKNOWN"; 62878c2ecf20Sopenharmony_ci} 62888c2ecf20Sopenharmony_ci 62898c2ecf20Sopenharmony_ci/** 62908c2ecf20Sopenharmony_ci * ice_stat_str - convert status err code to a string 62918c2ecf20Sopenharmony_ci * @stat_err: the status error code to convert 62928c2ecf20Sopenharmony_ci */ 62938c2ecf20Sopenharmony_ciconst char *ice_stat_str(enum ice_status stat_err) 62948c2ecf20Sopenharmony_ci{ 62958c2ecf20Sopenharmony_ci switch (stat_err) { 62968c2ecf20Sopenharmony_ci case ICE_SUCCESS: 62978c2ecf20Sopenharmony_ci return "OK"; 62988c2ecf20Sopenharmony_ci case ICE_ERR_PARAM: 62998c2ecf20Sopenharmony_ci return "ICE_ERR_PARAM"; 63008c2ecf20Sopenharmony_ci case ICE_ERR_NOT_IMPL: 63018c2ecf20Sopenharmony_ci return "ICE_ERR_NOT_IMPL"; 63028c2ecf20Sopenharmony_ci case ICE_ERR_NOT_READY: 63038c2ecf20Sopenharmony_ci return "ICE_ERR_NOT_READY"; 63048c2ecf20Sopenharmony_ci case ICE_ERR_NOT_SUPPORTED: 63058c2ecf20Sopenharmony_ci return "ICE_ERR_NOT_SUPPORTED"; 63068c2ecf20Sopenharmony_ci case ICE_ERR_BAD_PTR: 63078c2ecf20Sopenharmony_ci return "ICE_ERR_BAD_PTR"; 63088c2ecf20Sopenharmony_ci case ICE_ERR_INVAL_SIZE: 63098c2ecf20Sopenharmony_ci return "ICE_ERR_INVAL_SIZE"; 63108c2ecf20Sopenharmony_ci case ICE_ERR_DEVICE_NOT_SUPPORTED: 63118c2ecf20Sopenharmony_ci return "ICE_ERR_DEVICE_NOT_SUPPORTED"; 63128c2ecf20Sopenharmony_ci case ICE_ERR_RESET_FAILED: 63138c2ecf20Sopenharmony_ci return "ICE_ERR_RESET_FAILED"; 63148c2ecf20Sopenharmony_ci case ICE_ERR_FW_API_VER: 63158c2ecf20Sopenharmony_ci return "ICE_ERR_FW_API_VER"; 63168c2ecf20Sopenharmony_ci case ICE_ERR_NO_MEMORY: 63178c2ecf20Sopenharmony_ci return "ICE_ERR_NO_MEMORY"; 63188c2ecf20Sopenharmony_ci case ICE_ERR_CFG: 63198c2ecf20Sopenharmony_ci return "ICE_ERR_CFG"; 63208c2ecf20Sopenharmony_ci case ICE_ERR_OUT_OF_RANGE: 63218c2ecf20Sopenharmony_ci return "ICE_ERR_OUT_OF_RANGE"; 63228c2ecf20Sopenharmony_ci case ICE_ERR_ALREADY_EXISTS: 63238c2ecf20Sopenharmony_ci return "ICE_ERR_ALREADY_EXISTS"; 63248c2ecf20Sopenharmony_ci case ICE_ERR_NVM_CHECKSUM: 63258c2ecf20Sopenharmony_ci return "ICE_ERR_NVM_CHECKSUM"; 63268c2ecf20Sopenharmony_ci case ICE_ERR_BUF_TOO_SHORT: 63278c2ecf20Sopenharmony_ci return "ICE_ERR_BUF_TOO_SHORT"; 63288c2ecf20Sopenharmony_ci case ICE_ERR_NVM_BLANK_MODE: 63298c2ecf20Sopenharmony_ci return "ICE_ERR_NVM_BLANK_MODE"; 63308c2ecf20Sopenharmony_ci case ICE_ERR_IN_USE: 63318c2ecf20Sopenharmony_ci return "ICE_ERR_IN_USE"; 63328c2ecf20Sopenharmony_ci case ICE_ERR_MAX_LIMIT: 63338c2ecf20Sopenharmony_ci return "ICE_ERR_MAX_LIMIT"; 63348c2ecf20Sopenharmony_ci case ICE_ERR_RESET_ONGOING: 63358c2ecf20Sopenharmony_ci return "ICE_ERR_RESET_ONGOING"; 63368c2ecf20Sopenharmony_ci case ICE_ERR_HW_TABLE: 63378c2ecf20Sopenharmony_ci return "ICE_ERR_HW_TABLE"; 63388c2ecf20Sopenharmony_ci case ICE_ERR_DOES_NOT_EXIST: 63398c2ecf20Sopenharmony_ci return "ICE_ERR_DOES_NOT_EXIST"; 63408c2ecf20Sopenharmony_ci case ICE_ERR_FW_DDP_MISMATCH: 63418c2ecf20Sopenharmony_ci return "ICE_ERR_FW_DDP_MISMATCH"; 63428c2ecf20Sopenharmony_ci case ICE_ERR_AQ_ERROR: 63438c2ecf20Sopenharmony_ci return "ICE_ERR_AQ_ERROR"; 63448c2ecf20Sopenharmony_ci case ICE_ERR_AQ_TIMEOUT: 63458c2ecf20Sopenharmony_ci return "ICE_ERR_AQ_TIMEOUT"; 63468c2ecf20Sopenharmony_ci case ICE_ERR_AQ_FULL: 63478c2ecf20Sopenharmony_ci return "ICE_ERR_AQ_FULL"; 63488c2ecf20Sopenharmony_ci case ICE_ERR_AQ_NO_WORK: 63498c2ecf20Sopenharmony_ci return "ICE_ERR_AQ_NO_WORK"; 63508c2ecf20Sopenharmony_ci case ICE_ERR_AQ_EMPTY: 63518c2ecf20Sopenharmony_ci return "ICE_ERR_AQ_EMPTY"; 63528c2ecf20Sopenharmony_ci case ICE_ERR_AQ_FW_CRITICAL: 63538c2ecf20Sopenharmony_ci return "ICE_ERR_AQ_FW_CRITICAL"; 63548c2ecf20Sopenharmony_ci } 63558c2ecf20Sopenharmony_ci 63568c2ecf20Sopenharmony_ci return "ICE_ERR_UNKNOWN"; 63578c2ecf20Sopenharmony_ci} 63588c2ecf20Sopenharmony_ci 63598c2ecf20Sopenharmony_ci/** 63608c2ecf20Sopenharmony_ci * ice_set_rss - Set RSS keys and lut 63618c2ecf20Sopenharmony_ci * @vsi: Pointer to VSI structure 63628c2ecf20Sopenharmony_ci * @seed: RSS hash seed 63638c2ecf20Sopenharmony_ci * @lut: Lookup table 63648c2ecf20Sopenharmony_ci * @lut_size: Lookup table size 63658c2ecf20Sopenharmony_ci * 63668c2ecf20Sopenharmony_ci * Returns 0 on success, negative on failure 63678c2ecf20Sopenharmony_ci */ 63688c2ecf20Sopenharmony_ciint ice_set_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) 63698c2ecf20Sopenharmony_ci{ 63708c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 63718c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 63728c2ecf20Sopenharmony_ci enum ice_status status; 63738c2ecf20Sopenharmony_ci struct device *dev; 63748c2ecf20Sopenharmony_ci 63758c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 63768c2ecf20Sopenharmony_ci if (seed) { 63778c2ecf20Sopenharmony_ci struct ice_aqc_get_set_rss_keys *buf = 63788c2ecf20Sopenharmony_ci (struct ice_aqc_get_set_rss_keys *)seed; 63798c2ecf20Sopenharmony_ci 63808c2ecf20Sopenharmony_ci status = ice_aq_set_rss_key(hw, vsi->idx, buf); 63818c2ecf20Sopenharmony_ci 63828c2ecf20Sopenharmony_ci if (status) { 63838c2ecf20Sopenharmony_ci dev_err(dev, "Cannot set RSS key, err %s aq_err %s\n", 63848c2ecf20Sopenharmony_ci ice_stat_str(status), 63858c2ecf20Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 63868c2ecf20Sopenharmony_ci return -EIO; 63878c2ecf20Sopenharmony_ci } 63888c2ecf20Sopenharmony_ci } 63898c2ecf20Sopenharmony_ci 63908c2ecf20Sopenharmony_ci if (lut) { 63918c2ecf20Sopenharmony_ci status = ice_aq_set_rss_lut(hw, vsi->idx, vsi->rss_lut_type, 63928c2ecf20Sopenharmony_ci lut, lut_size); 63938c2ecf20Sopenharmony_ci if (status) { 63948c2ecf20Sopenharmony_ci dev_err(dev, "Cannot set RSS lut, err %s aq_err %s\n", 63958c2ecf20Sopenharmony_ci ice_stat_str(status), 63968c2ecf20Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 63978c2ecf20Sopenharmony_ci return -EIO; 63988c2ecf20Sopenharmony_ci } 63998c2ecf20Sopenharmony_ci } 64008c2ecf20Sopenharmony_ci 64018c2ecf20Sopenharmony_ci return 0; 64028c2ecf20Sopenharmony_ci} 64038c2ecf20Sopenharmony_ci 64048c2ecf20Sopenharmony_ci/** 64058c2ecf20Sopenharmony_ci * ice_get_rss - Get RSS keys and lut 64068c2ecf20Sopenharmony_ci * @vsi: Pointer to VSI structure 64078c2ecf20Sopenharmony_ci * @seed: Buffer to store the keys 64088c2ecf20Sopenharmony_ci * @lut: Buffer to store the lookup table entries 64098c2ecf20Sopenharmony_ci * @lut_size: Size of buffer to store the lookup table entries 64108c2ecf20Sopenharmony_ci * 64118c2ecf20Sopenharmony_ci * Returns 0 on success, negative on failure 64128c2ecf20Sopenharmony_ci */ 64138c2ecf20Sopenharmony_ciint ice_get_rss(struct ice_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size) 64148c2ecf20Sopenharmony_ci{ 64158c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 64168c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 64178c2ecf20Sopenharmony_ci enum ice_status status; 64188c2ecf20Sopenharmony_ci struct device *dev; 64198c2ecf20Sopenharmony_ci 64208c2ecf20Sopenharmony_ci dev = ice_pf_to_dev(pf); 64218c2ecf20Sopenharmony_ci if (seed) { 64228c2ecf20Sopenharmony_ci struct ice_aqc_get_set_rss_keys *buf = 64238c2ecf20Sopenharmony_ci (struct ice_aqc_get_set_rss_keys *)seed; 64248c2ecf20Sopenharmony_ci 64258c2ecf20Sopenharmony_ci status = ice_aq_get_rss_key(hw, vsi->idx, buf); 64268c2ecf20Sopenharmony_ci if (status) { 64278c2ecf20Sopenharmony_ci dev_err(dev, "Cannot get RSS key, err %s aq_err %s\n", 64288c2ecf20Sopenharmony_ci ice_stat_str(status), 64298c2ecf20Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 64308c2ecf20Sopenharmony_ci return -EIO; 64318c2ecf20Sopenharmony_ci } 64328c2ecf20Sopenharmony_ci } 64338c2ecf20Sopenharmony_ci 64348c2ecf20Sopenharmony_ci if (lut) { 64358c2ecf20Sopenharmony_ci status = ice_aq_get_rss_lut(hw, vsi->idx, vsi->rss_lut_type, 64368c2ecf20Sopenharmony_ci lut, lut_size); 64378c2ecf20Sopenharmony_ci if (status) { 64388c2ecf20Sopenharmony_ci dev_err(dev, "Cannot get RSS lut, err %s aq_err %s\n", 64398c2ecf20Sopenharmony_ci ice_stat_str(status), 64408c2ecf20Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 64418c2ecf20Sopenharmony_ci return -EIO; 64428c2ecf20Sopenharmony_ci } 64438c2ecf20Sopenharmony_ci } 64448c2ecf20Sopenharmony_ci 64458c2ecf20Sopenharmony_ci return 0; 64468c2ecf20Sopenharmony_ci} 64478c2ecf20Sopenharmony_ci 64488c2ecf20Sopenharmony_ci/** 64498c2ecf20Sopenharmony_ci * ice_bridge_getlink - Get the hardware bridge mode 64508c2ecf20Sopenharmony_ci * @skb: skb buff 64518c2ecf20Sopenharmony_ci * @pid: process ID 64528c2ecf20Sopenharmony_ci * @seq: RTNL message seq 64538c2ecf20Sopenharmony_ci * @dev: the netdev being configured 64548c2ecf20Sopenharmony_ci * @filter_mask: filter mask passed in 64558c2ecf20Sopenharmony_ci * @nlflags: netlink flags passed in 64568c2ecf20Sopenharmony_ci * 64578c2ecf20Sopenharmony_ci * Return the bridge mode (VEB/VEPA) 64588c2ecf20Sopenharmony_ci */ 64598c2ecf20Sopenharmony_cistatic int 64608c2ecf20Sopenharmony_ciice_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, 64618c2ecf20Sopenharmony_ci struct net_device *dev, u32 filter_mask, int nlflags) 64628c2ecf20Sopenharmony_ci{ 64638c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(dev); 64648c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 64658c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 64668c2ecf20Sopenharmony_ci u16 bmode; 64678c2ecf20Sopenharmony_ci 64688c2ecf20Sopenharmony_ci bmode = pf->first_sw->bridge_mode; 64698c2ecf20Sopenharmony_ci 64708c2ecf20Sopenharmony_ci return ndo_dflt_bridge_getlink(skb, pid, seq, dev, bmode, 0, 0, nlflags, 64718c2ecf20Sopenharmony_ci filter_mask, NULL); 64728c2ecf20Sopenharmony_ci} 64738c2ecf20Sopenharmony_ci 64748c2ecf20Sopenharmony_ci/** 64758c2ecf20Sopenharmony_ci * ice_vsi_update_bridge_mode - Update VSI for switching bridge mode (VEB/VEPA) 64768c2ecf20Sopenharmony_ci * @vsi: Pointer to VSI structure 64778c2ecf20Sopenharmony_ci * @bmode: Hardware bridge mode (VEB/VEPA) 64788c2ecf20Sopenharmony_ci * 64798c2ecf20Sopenharmony_ci * Returns 0 on success, negative on failure 64808c2ecf20Sopenharmony_ci */ 64818c2ecf20Sopenharmony_cistatic int ice_vsi_update_bridge_mode(struct ice_vsi *vsi, u16 bmode) 64828c2ecf20Sopenharmony_ci{ 64838c2ecf20Sopenharmony_ci struct ice_aqc_vsi_props *vsi_props; 64848c2ecf20Sopenharmony_ci struct ice_hw *hw = &vsi->back->hw; 64858c2ecf20Sopenharmony_ci struct ice_vsi_ctx *ctxt; 64868c2ecf20Sopenharmony_ci enum ice_status status; 64878c2ecf20Sopenharmony_ci int ret = 0; 64888c2ecf20Sopenharmony_ci 64898c2ecf20Sopenharmony_ci vsi_props = &vsi->info; 64908c2ecf20Sopenharmony_ci 64918c2ecf20Sopenharmony_ci ctxt = kzalloc(sizeof(*ctxt), GFP_KERNEL); 64928c2ecf20Sopenharmony_ci if (!ctxt) 64938c2ecf20Sopenharmony_ci return -ENOMEM; 64948c2ecf20Sopenharmony_ci 64958c2ecf20Sopenharmony_ci ctxt->info = vsi->info; 64968c2ecf20Sopenharmony_ci 64978c2ecf20Sopenharmony_ci if (bmode == BRIDGE_MODE_VEB) 64988c2ecf20Sopenharmony_ci /* change from VEPA to VEB mode */ 64998c2ecf20Sopenharmony_ci ctxt->info.sw_flags |= ICE_AQ_VSI_SW_FLAG_ALLOW_LB; 65008c2ecf20Sopenharmony_ci else 65018c2ecf20Sopenharmony_ci /* change from VEB to VEPA mode */ 65028c2ecf20Sopenharmony_ci ctxt->info.sw_flags &= ~ICE_AQ_VSI_SW_FLAG_ALLOW_LB; 65038c2ecf20Sopenharmony_ci ctxt->info.valid_sections = cpu_to_le16(ICE_AQ_VSI_PROP_SW_VALID); 65048c2ecf20Sopenharmony_ci 65058c2ecf20Sopenharmony_ci status = ice_update_vsi(hw, vsi->idx, ctxt, NULL); 65068c2ecf20Sopenharmony_ci if (status) { 65078c2ecf20Sopenharmony_ci dev_err(ice_pf_to_dev(vsi->back), "update VSI for bridge mode failed, bmode = %d err %s aq_err %s\n", 65088c2ecf20Sopenharmony_ci bmode, ice_stat_str(status), 65098c2ecf20Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 65108c2ecf20Sopenharmony_ci ret = -EIO; 65118c2ecf20Sopenharmony_ci goto out; 65128c2ecf20Sopenharmony_ci } 65138c2ecf20Sopenharmony_ci /* Update sw flags for book keeping */ 65148c2ecf20Sopenharmony_ci vsi_props->sw_flags = ctxt->info.sw_flags; 65158c2ecf20Sopenharmony_ci 65168c2ecf20Sopenharmony_ciout: 65178c2ecf20Sopenharmony_ci kfree(ctxt); 65188c2ecf20Sopenharmony_ci return ret; 65198c2ecf20Sopenharmony_ci} 65208c2ecf20Sopenharmony_ci 65218c2ecf20Sopenharmony_ci/** 65228c2ecf20Sopenharmony_ci * ice_bridge_setlink - Set the hardware bridge mode 65238c2ecf20Sopenharmony_ci * @dev: the netdev being configured 65248c2ecf20Sopenharmony_ci * @nlh: RTNL message 65258c2ecf20Sopenharmony_ci * @flags: bridge setlink flags 65268c2ecf20Sopenharmony_ci * @extack: netlink extended ack 65278c2ecf20Sopenharmony_ci * 65288c2ecf20Sopenharmony_ci * Sets the bridge mode (VEB/VEPA) of the switch to which the netdev (VSI) is 65298c2ecf20Sopenharmony_ci * hooked up to. Iterates through the PF VSI list and sets the loopback mode (if 65308c2ecf20Sopenharmony_ci * not already set for all VSIs connected to this switch. And also update the 65318c2ecf20Sopenharmony_ci * unicast switch filter rules for the corresponding switch of the netdev. 65328c2ecf20Sopenharmony_ci */ 65338c2ecf20Sopenharmony_cistatic int 65348c2ecf20Sopenharmony_ciice_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh, 65358c2ecf20Sopenharmony_ci u16 __always_unused flags, 65368c2ecf20Sopenharmony_ci struct netlink_ext_ack __always_unused *extack) 65378c2ecf20Sopenharmony_ci{ 65388c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(dev); 65398c2ecf20Sopenharmony_ci struct ice_pf *pf = np->vsi->back; 65408c2ecf20Sopenharmony_ci struct nlattr *attr, *br_spec; 65418c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 65428c2ecf20Sopenharmony_ci enum ice_status status; 65438c2ecf20Sopenharmony_ci struct ice_sw *pf_sw; 65448c2ecf20Sopenharmony_ci int rem, v, err = 0; 65458c2ecf20Sopenharmony_ci 65468c2ecf20Sopenharmony_ci pf_sw = pf->first_sw; 65478c2ecf20Sopenharmony_ci /* find the attribute in the netlink message */ 65488c2ecf20Sopenharmony_ci br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); 65498c2ecf20Sopenharmony_ci 65508c2ecf20Sopenharmony_ci nla_for_each_nested(attr, br_spec, rem) { 65518c2ecf20Sopenharmony_ci __u16 mode; 65528c2ecf20Sopenharmony_ci 65538c2ecf20Sopenharmony_ci if (nla_type(attr) != IFLA_BRIDGE_MODE) 65548c2ecf20Sopenharmony_ci continue; 65558c2ecf20Sopenharmony_ci mode = nla_get_u16(attr); 65568c2ecf20Sopenharmony_ci if (mode != BRIDGE_MODE_VEPA && mode != BRIDGE_MODE_VEB) 65578c2ecf20Sopenharmony_ci return -EINVAL; 65588c2ecf20Sopenharmony_ci /* Continue if bridge mode is not being flipped */ 65598c2ecf20Sopenharmony_ci if (mode == pf_sw->bridge_mode) 65608c2ecf20Sopenharmony_ci continue; 65618c2ecf20Sopenharmony_ci /* Iterates through the PF VSI list and update the loopback 65628c2ecf20Sopenharmony_ci * mode of the VSI 65638c2ecf20Sopenharmony_ci */ 65648c2ecf20Sopenharmony_ci ice_for_each_vsi(pf, v) { 65658c2ecf20Sopenharmony_ci if (!pf->vsi[v]) 65668c2ecf20Sopenharmony_ci continue; 65678c2ecf20Sopenharmony_ci err = ice_vsi_update_bridge_mode(pf->vsi[v], mode); 65688c2ecf20Sopenharmony_ci if (err) 65698c2ecf20Sopenharmony_ci return err; 65708c2ecf20Sopenharmony_ci } 65718c2ecf20Sopenharmony_ci 65728c2ecf20Sopenharmony_ci hw->evb_veb = (mode == BRIDGE_MODE_VEB); 65738c2ecf20Sopenharmony_ci /* Update the unicast switch filter rules for the corresponding 65748c2ecf20Sopenharmony_ci * switch of the netdev 65758c2ecf20Sopenharmony_ci */ 65768c2ecf20Sopenharmony_ci status = ice_update_sw_rule_bridge_mode(hw); 65778c2ecf20Sopenharmony_ci if (status) { 65788c2ecf20Sopenharmony_ci netdev_err(dev, "switch rule update failed, mode = %d err %s aq_err %s\n", 65798c2ecf20Sopenharmony_ci mode, ice_stat_str(status), 65808c2ecf20Sopenharmony_ci ice_aq_str(hw->adminq.sq_last_status)); 65818c2ecf20Sopenharmony_ci /* revert hw->evb_veb */ 65828c2ecf20Sopenharmony_ci hw->evb_veb = (pf_sw->bridge_mode == BRIDGE_MODE_VEB); 65838c2ecf20Sopenharmony_ci return -EIO; 65848c2ecf20Sopenharmony_ci } 65858c2ecf20Sopenharmony_ci 65868c2ecf20Sopenharmony_ci pf_sw->bridge_mode = mode; 65878c2ecf20Sopenharmony_ci } 65888c2ecf20Sopenharmony_ci 65898c2ecf20Sopenharmony_ci return 0; 65908c2ecf20Sopenharmony_ci} 65918c2ecf20Sopenharmony_ci 65928c2ecf20Sopenharmony_ci/** 65938c2ecf20Sopenharmony_ci * ice_tx_timeout - Respond to a Tx Hang 65948c2ecf20Sopenharmony_ci * @netdev: network interface device structure 65958c2ecf20Sopenharmony_ci * @txqueue: Tx queue 65968c2ecf20Sopenharmony_ci */ 65978c2ecf20Sopenharmony_cistatic void ice_tx_timeout(struct net_device *netdev, unsigned int txqueue) 65988c2ecf20Sopenharmony_ci{ 65998c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 66008c2ecf20Sopenharmony_ci struct ice_ring *tx_ring = NULL; 66018c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 66028c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 66038c2ecf20Sopenharmony_ci u32 i; 66048c2ecf20Sopenharmony_ci 66058c2ecf20Sopenharmony_ci pf->tx_timeout_count++; 66068c2ecf20Sopenharmony_ci 66078c2ecf20Sopenharmony_ci /* Check if PFC is enabled for the TC to which the queue belongs 66088c2ecf20Sopenharmony_ci * to. If yes then Tx timeout is not caused by a hung queue, no 66098c2ecf20Sopenharmony_ci * need to reset and rebuild 66108c2ecf20Sopenharmony_ci */ 66118c2ecf20Sopenharmony_ci if (ice_is_pfc_causing_hung_q(pf, txqueue)) { 66128c2ecf20Sopenharmony_ci dev_info(ice_pf_to_dev(pf), "Fake Tx hang detected on queue %u, timeout caused by PFC storm\n", 66138c2ecf20Sopenharmony_ci txqueue); 66148c2ecf20Sopenharmony_ci return; 66158c2ecf20Sopenharmony_ci } 66168c2ecf20Sopenharmony_ci 66178c2ecf20Sopenharmony_ci /* now that we have an index, find the tx_ring struct */ 66188c2ecf20Sopenharmony_ci for (i = 0; i < vsi->num_txq; i++) 66198c2ecf20Sopenharmony_ci if (vsi->tx_rings[i] && vsi->tx_rings[i]->desc) 66208c2ecf20Sopenharmony_ci if (txqueue == vsi->tx_rings[i]->q_index) { 66218c2ecf20Sopenharmony_ci tx_ring = vsi->tx_rings[i]; 66228c2ecf20Sopenharmony_ci break; 66238c2ecf20Sopenharmony_ci } 66248c2ecf20Sopenharmony_ci 66258c2ecf20Sopenharmony_ci /* Reset recovery level if enough time has elapsed after last timeout. 66268c2ecf20Sopenharmony_ci * Also ensure no new reset action happens before next timeout period. 66278c2ecf20Sopenharmony_ci */ 66288c2ecf20Sopenharmony_ci if (time_after(jiffies, (pf->tx_timeout_last_recovery + HZ * 20))) 66298c2ecf20Sopenharmony_ci pf->tx_timeout_recovery_level = 1; 66308c2ecf20Sopenharmony_ci else if (time_before(jiffies, (pf->tx_timeout_last_recovery + 66318c2ecf20Sopenharmony_ci netdev->watchdog_timeo))) 66328c2ecf20Sopenharmony_ci return; 66338c2ecf20Sopenharmony_ci 66348c2ecf20Sopenharmony_ci if (tx_ring) { 66358c2ecf20Sopenharmony_ci struct ice_hw *hw = &pf->hw; 66368c2ecf20Sopenharmony_ci u32 head, val = 0; 66378c2ecf20Sopenharmony_ci 66388c2ecf20Sopenharmony_ci head = (rd32(hw, QTX_COMM_HEAD(vsi->txq_map[txqueue])) & 66398c2ecf20Sopenharmony_ci QTX_COMM_HEAD_HEAD_M) >> QTX_COMM_HEAD_HEAD_S; 66408c2ecf20Sopenharmony_ci /* Read interrupt register */ 66418c2ecf20Sopenharmony_ci val = rd32(hw, GLINT_DYN_CTL(tx_ring->q_vector->reg_idx)); 66428c2ecf20Sopenharmony_ci 66438c2ecf20Sopenharmony_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", 66448c2ecf20Sopenharmony_ci vsi->vsi_num, txqueue, tx_ring->next_to_clean, 66458c2ecf20Sopenharmony_ci head, tx_ring->next_to_use, val); 66468c2ecf20Sopenharmony_ci } 66478c2ecf20Sopenharmony_ci 66488c2ecf20Sopenharmony_ci pf->tx_timeout_last_recovery = jiffies; 66498c2ecf20Sopenharmony_ci netdev_info(netdev, "tx_timeout recovery level %d, txqueue %u\n", 66508c2ecf20Sopenharmony_ci pf->tx_timeout_recovery_level, txqueue); 66518c2ecf20Sopenharmony_ci 66528c2ecf20Sopenharmony_ci switch (pf->tx_timeout_recovery_level) { 66538c2ecf20Sopenharmony_ci case 1: 66548c2ecf20Sopenharmony_ci set_bit(__ICE_PFR_REQ, pf->state); 66558c2ecf20Sopenharmony_ci break; 66568c2ecf20Sopenharmony_ci case 2: 66578c2ecf20Sopenharmony_ci set_bit(__ICE_CORER_REQ, pf->state); 66588c2ecf20Sopenharmony_ci break; 66598c2ecf20Sopenharmony_ci case 3: 66608c2ecf20Sopenharmony_ci set_bit(__ICE_GLOBR_REQ, pf->state); 66618c2ecf20Sopenharmony_ci break; 66628c2ecf20Sopenharmony_ci default: 66638c2ecf20Sopenharmony_ci netdev_err(netdev, "tx_timeout recovery unsuccessful, device is in unrecoverable state.\n"); 66648c2ecf20Sopenharmony_ci set_bit(__ICE_DOWN, pf->state); 66658c2ecf20Sopenharmony_ci set_bit(__ICE_NEEDS_RESTART, vsi->state); 66668c2ecf20Sopenharmony_ci set_bit(__ICE_SERVICE_DIS, pf->state); 66678c2ecf20Sopenharmony_ci break; 66688c2ecf20Sopenharmony_ci } 66698c2ecf20Sopenharmony_ci 66708c2ecf20Sopenharmony_ci ice_service_task_schedule(pf); 66718c2ecf20Sopenharmony_ci pf->tx_timeout_recovery_level++; 66728c2ecf20Sopenharmony_ci} 66738c2ecf20Sopenharmony_ci 66748c2ecf20Sopenharmony_ci/** 66758c2ecf20Sopenharmony_ci * ice_open - Called when a network interface becomes active 66768c2ecf20Sopenharmony_ci * @netdev: network interface device structure 66778c2ecf20Sopenharmony_ci * 66788c2ecf20Sopenharmony_ci * The open entry point is called when a network interface is made 66798c2ecf20Sopenharmony_ci * active by the system (IFF_UP). At this point all resources needed 66808c2ecf20Sopenharmony_ci * for transmit and receive operations are allocated, the interrupt 66818c2ecf20Sopenharmony_ci * handler is registered with the OS, the netdev watchdog is enabled, 66828c2ecf20Sopenharmony_ci * and the stack is notified that the interface is ready. 66838c2ecf20Sopenharmony_ci * 66848c2ecf20Sopenharmony_ci * Returns 0 on success, negative value on failure 66858c2ecf20Sopenharmony_ci */ 66868c2ecf20Sopenharmony_ciint ice_open(struct net_device *netdev) 66878c2ecf20Sopenharmony_ci{ 66888c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 66898c2ecf20Sopenharmony_ci struct ice_pf *pf = np->vsi->back; 66908c2ecf20Sopenharmony_ci 66918c2ecf20Sopenharmony_ci if (ice_is_reset_in_progress(pf->state)) { 66928c2ecf20Sopenharmony_ci netdev_err(netdev, "can't open net device while reset is in progress"); 66938c2ecf20Sopenharmony_ci return -EBUSY; 66948c2ecf20Sopenharmony_ci } 66958c2ecf20Sopenharmony_ci 66968c2ecf20Sopenharmony_ci return ice_open_internal(netdev); 66978c2ecf20Sopenharmony_ci} 66988c2ecf20Sopenharmony_ci 66998c2ecf20Sopenharmony_ci/** 67008c2ecf20Sopenharmony_ci * ice_open_internal - Called when a network interface becomes active 67018c2ecf20Sopenharmony_ci * @netdev: network interface device structure 67028c2ecf20Sopenharmony_ci * 67038c2ecf20Sopenharmony_ci * Internal ice_open implementation. Should not be used directly except for ice_open and reset 67048c2ecf20Sopenharmony_ci * handling routine 67058c2ecf20Sopenharmony_ci * 67068c2ecf20Sopenharmony_ci * Returns 0 on success, negative value on failure 67078c2ecf20Sopenharmony_ci */ 67088c2ecf20Sopenharmony_ciint ice_open_internal(struct net_device *netdev) 67098c2ecf20Sopenharmony_ci{ 67108c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 67118c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 67128c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 67138c2ecf20Sopenharmony_ci struct ice_port_info *pi; 67148c2ecf20Sopenharmony_ci int err; 67158c2ecf20Sopenharmony_ci 67168c2ecf20Sopenharmony_ci if (test_bit(__ICE_NEEDS_RESTART, pf->state)) { 67178c2ecf20Sopenharmony_ci netdev_err(netdev, "driver needs to be unloaded and reloaded\n"); 67188c2ecf20Sopenharmony_ci return -EIO; 67198c2ecf20Sopenharmony_ci } 67208c2ecf20Sopenharmony_ci 67218c2ecf20Sopenharmony_ci if (test_bit(__ICE_DOWN, pf->state)) { 67228c2ecf20Sopenharmony_ci netdev_err(netdev, "device is not ready yet\n"); 67238c2ecf20Sopenharmony_ci return -EBUSY; 67248c2ecf20Sopenharmony_ci } 67258c2ecf20Sopenharmony_ci 67268c2ecf20Sopenharmony_ci netif_carrier_off(netdev); 67278c2ecf20Sopenharmony_ci 67288c2ecf20Sopenharmony_ci pi = vsi->port_info; 67298c2ecf20Sopenharmony_ci err = ice_update_link_info(pi); 67308c2ecf20Sopenharmony_ci if (err) { 67318c2ecf20Sopenharmony_ci netdev_err(netdev, "Failed to get link info, error %d\n", 67328c2ecf20Sopenharmony_ci err); 67338c2ecf20Sopenharmony_ci return err; 67348c2ecf20Sopenharmony_ci } 67358c2ecf20Sopenharmony_ci 67368c2ecf20Sopenharmony_ci /* Set PHY if there is media, otherwise, turn off PHY */ 67378c2ecf20Sopenharmony_ci if (pi->phy.link_info.link_info & ICE_AQ_MEDIA_AVAILABLE) { 67388c2ecf20Sopenharmony_ci clear_bit(ICE_FLAG_NO_MEDIA, pf->flags); 67398c2ecf20Sopenharmony_ci if (!test_bit(__ICE_PHY_INIT_COMPLETE, pf->state)) { 67408c2ecf20Sopenharmony_ci err = ice_init_phy_user_cfg(pi); 67418c2ecf20Sopenharmony_ci if (err) { 67428c2ecf20Sopenharmony_ci netdev_err(netdev, "Failed to initialize PHY settings, error %d\n", 67438c2ecf20Sopenharmony_ci err); 67448c2ecf20Sopenharmony_ci return err; 67458c2ecf20Sopenharmony_ci } 67468c2ecf20Sopenharmony_ci } 67478c2ecf20Sopenharmony_ci 67488c2ecf20Sopenharmony_ci err = ice_configure_phy(vsi); 67498c2ecf20Sopenharmony_ci if (err) { 67508c2ecf20Sopenharmony_ci netdev_err(netdev, "Failed to set physical link up, error %d\n", 67518c2ecf20Sopenharmony_ci err); 67528c2ecf20Sopenharmony_ci return err; 67538c2ecf20Sopenharmony_ci } 67548c2ecf20Sopenharmony_ci } else { 67558c2ecf20Sopenharmony_ci set_bit(ICE_FLAG_NO_MEDIA, pf->flags); 67568c2ecf20Sopenharmony_ci err = ice_aq_set_link_restart_an(pi, false, NULL); 67578c2ecf20Sopenharmony_ci if (err) { 67588c2ecf20Sopenharmony_ci netdev_err(netdev, "Failed to set PHY state, VSI %d error %d\n", 67598c2ecf20Sopenharmony_ci vsi->vsi_num, err); 67608c2ecf20Sopenharmony_ci return err; 67618c2ecf20Sopenharmony_ci } 67628c2ecf20Sopenharmony_ci } 67638c2ecf20Sopenharmony_ci 67648c2ecf20Sopenharmony_ci err = ice_vsi_open(vsi); 67658c2ecf20Sopenharmony_ci if (err) 67668c2ecf20Sopenharmony_ci netdev_err(netdev, "Failed to open VSI 0x%04X on switch 0x%04X\n", 67678c2ecf20Sopenharmony_ci vsi->vsi_num, vsi->vsw->sw_id); 67688c2ecf20Sopenharmony_ci 67698c2ecf20Sopenharmony_ci /* Update existing tunnels information */ 67708c2ecf20Sopenharmony_ci udp_tunnel_get_rx_info(netdev); 67718c2ecf20Sopenharmony_ci 67728c2ecf20Sopenharmony_ci return err; 67738c2ecf20Sopenharmony_ci} 67748c2ecf20Sopenharmony_ci 67758c2ecf20Sopenharmony_ci/** 67768c2ecf20Sopenharmony_ci * ice_stop - Disables a network interface 67778c2ecf20Sopenharmony_ci * @netdev: network interface device structure 67788c2ecf20Sopenharmony_ci * 67798c2ecf20Sopenharmony_ci * The stop entry point is called when an interface is de-activated by the OS, 67808c2ecf20Sopenharmony_ci * and the netdevice enters the DOWN state. The hardware is still under the 67818c2ecf20Sopenharmony_ci * driver's control, but the netdev interface is disabled. 67828c2ecf20Sopenharmony_ci * 67838c2ecf20Sopenharmony_ci * Returns success only - not allowed to fail 67848c2ecf20Sopenharmony_ci */ 67858c2ecf20Sopenharmony_ciint ice_stop(struct net_device *netdev) 67868c2ecf20Sopenharmony_ci{ 67878c2ecf20Sopenharmony_ci struct ice_netdev_priv *np = netdev_priv(netdev); 67888c2ecf20Sopenharmony_ci struct ice_vsi *vsi = np->vsi; 67898c2ecf20Sopenharmony_ci struct ice_pf *pf = vsi->back; 67908c2ecf20Sopenharmony_ci 67918c2ecf20Sopenharmony_ci if (ice_is_reset_in_progress(pf->state)) { 67928c2ecf20Sopenharmony_ci netdev_err(netdev, "can't stop net device while reset is in progress"); 67938c2ecf20Sopenharmony_ci return -EBUSY; 67948c2ecf20Sopenharmony_ci } 67958c2ecf20Sopenharmony_ci 67968c2ecf20Sopenharmony_ci ice_vsi_close(vsi); 67978c2ecf20Sopenharmony_ci 67988c2ecf20Sopenharmony_ci return 0; 67998c2ecf20Sopenharmony_ci} 68008c2ecf20Sopenharmony_ci 68018c2ecf20Sopenharmony_ci/** 68028c2ecf20Sopenharmony_ci * ice_features_check - Validate encapsulated packet conforms to limits 68038c2ecf20Sopenharmony_ci * @skb: skb buffer 68048c2ecf20Sopenharmony_ci * @netdev: This port's netdev 68058c2ecf20Sopenharmony_ci * @features: Offload features that the stack believes apply 68068c2ecf20Sopenharmony_ci */ 68078c2ecf20Sopenharmony_cistatic netdev_features_t 68088c2ecf20Sopenharmony_ciice_features_check(struct sk_buff *skb, 68098c2ecf20Sopenharmony_ci struct net_device __always_unused *netdev, 68108c2ecf20Sopenharmony_ci netdev_features_t features) 68118c2ecf20Sopenharmony_ci{ 68128c2ecf20Sopenharmony_ci size_t len; 68138c2ecf20Sopenharmony_ci 68148c2ecf20Sopenharmony_ci /* No point in doing any of this if neither checksum nor GSO are 68158c2ecf20Sopenharmony_ci * being requested for this frame. We can rule out both by just 68168c2ecf20Sopenharmony_ci * checking for CHECKSUM_PARTIAL 68178c2ecf20Sopenharmony_ci */ 68188c2ecf20Sopenharmony_ci if (skb->ip_summed != CHECKSUM_PARTIAL) 68198c2ecf20Sopenharmony_ci return features; 68208c2ecf20Sopenharmony_ci 68218c2ecf20Sopenharmony_ci /* We cannot support GSO if the MSS is going to be less than 68228c2ecf20Sopenharmony_ci * 64 bytes. If it is then we need to drop support for GSO. 68238c2ecf20Sopenharmony_ci */ 68248c2ecf20Sopenharmony_ci if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_size < 64)) 68258c2ecf20Sopenharmony_ci features &= ~NETIF_F_GSO_MASK; 68268c2ecf20Sopenharmony_ci 68278c2ecf20Sopenharmony_ci len = skb_network_header(skb) - skb->data; 68288c2ecf20Sopenharmony_ci if (len > ICE_TXD_MACLEN_MAX || len & 0x1) 68298c2ecf20Sopenharmony_ci goto out_rm_features; 68308c2ecf20Sopenharmony_ci 68318c2ecf20Sopenharmony_ci len = skb_transport_header(skb) - skb_network_header(skb); 68328c2ecf20Sopenharmony_ci if (len > ICE_TXD_IPLEN_MAX || len & 0x1) 68338c2ecf20Sopenharmony_ci goto out_rm_features; 68348c2ecf20Sopenharmony_ci 68358c2ecf20Sopenharmony_ci if (skb->encapsulation) { 68368c2ecf20Sopenharmony_ci len = skb_inner_network_header(skb) - skb_transport_header(skb); 68378c2ecf20Sopenharmony_ci if (len > ICE_TXD_L4LEN_MAX || len & 0x1) 68388c2ecf20Sopenharmony_ci goto out_rm_features; 68398c2ecf20Sopenharmony_ci 68408c2ecf20Sopenharmony_ci len = skb_inner_transport_header(skb) - 68418c2ecf20Sopenharmony_ci skb_inner_network_header(skb); 68428c2ecf20Sopenharmony_ci if (len > ICE_TXD_IPLEN_MAX || len & 0x1) 68438c2ecf20Sopenharmony_ci goto out_rm_features; 68448c2ecf20Sopenharmony_ci } 68458c2ecf20Sopenharmony_ci 68468c2ecf20Sopenharmony_ci return features; 68478c2ecf20Sopenharmony_ciout_rm_features: 68488c2ecf20Sopenharmony_ci return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); 68498c2ecf20Sopenharmony_ci} 68508c2ecf20Sopenharmony_ci 68518c2ecf20Sopenharmony_cistatic const struct net_device_ops ice_netdev_safe_mode_ops = { 68528c2ecf20Sopenharmony_ci .ndo_open = ice_open, 68538c2ecf20Sopenharmony_ci .ndo_stop = ice_stop, 68548c2ecf20Sopenharmony_ci .ndo_start_xmit = ice_start_xmit, 68558c2ecf20Sopenharmony_ci .ndo_set_mac_address = ice_set_mac_address, 68568c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 68578c2ecf20Sopenharmony_ci .ndo_change_mtu = ice_change_mtu, 68588c2ecf20Sopenharmony_ci .ndo_get_stats64 = ice_get_stats64, 68598c2ecf20Sopenharmony_ci .ndo_tx_timeout = ice_tx_timeout, 68608c2ecf20Sopenharmony_ci .ndo_bpf = ice_xdp_safe_mode, 68618c2ecf20Sopenharmony_ci}; 68628c2ecf20Sopenharmony_ci 68638c2ecf20Sopenharmony_cistatic const struct net_device_ops ice_netdev_ops = { 68648c2ecf20Sopenharmony_ci .ndo_open = ice_open, 68658c2ecf20Sopenharmony_ci .ndo_stop = ice_stop, 68668c2ecf20Sopenharmony_ci .ndo_start_xmit = ice_start_xmit, 68678c2ecf20Sopenharmony_ci .ndo_features_check = ice_features_check, 68688c2ecf20Sopenharmony_ci .ndo_set_rx_mode = ice_set_rx_mode, 68698c2ecf20Sopenharmony_ci .ndo_set_mac_address = ice_set_mac_address, 68708c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 68718c2ecf20Sopenharmony_ci .ndo_change_mtu = ice_change_mtu, 68728c2ecf20Sopenharmony_ci .ndo_get_stats64 = ice_get_stats64, 68738c2ecf20Sopenharmony_ci .ndo_set_tx_maxrate = ice_set_tx_maxrate, 68748c2ecf20Sopenharmony_ci .ndo_set_vf_spoofchk = ice_set_vf_spoofchk, 68758c2ecf20Sopenharmony_ci .ndo_set_vf_mac = ice_set_vf_mac, 68768c2ecf20Sopenharmony_ci .ndo_get_vf_config = ice_get_vf_cfg, 68778c2ecf20Sopenharmony_ci .ndo_set_vf_trust = ice_set_vf_trust, 68788c2ecf20Sopenharmony_ci .ndo_set_vf_vlan = ice_set_vf_port_vlan, 68798c2ecf20Sopenharmony_ci .ndo_set_vf_link_state = ice_set_vf_link_state, 68808c2ecf20Sopenharmony_ci .ndo_get_vf_stats = ice_get_vf_stats, 68818c2ecf20Sopenharmony_ci .ndo_vlan_rx_add_vid = ice_vlan_rx_add_vid, 68828c2ecf20Sopenharmony_ci .ndo_vlan_rx_kill_vid = ice_vlan_rx_kill_vid, 68838c2ecf20Sopenharmony_ci .ndo_set_features = ice_set_features, 68848c2ecf20Sopenharmony_ci .ndo_bridge_getlink = ice_bridge_getlink, 68858c2ecf20Sopenharmony_ci .ndo_bridge_setlink = ice_bridge_setlink, 68868c2ecf20Sopenharmony_ci .ndo_fdb_add = ice_fdb_add, 68878c2ecf20Sopenharmony_ci .ndo_fdb_del = ice_fdb_del, 68888c2ecf20Sopenharmony_ci#ifdef CONFIG_RFS_ACCEL 68898c2ecf20Sopenharmony_ci .ndo_rx_flow_steer = ice_rx_flow_steer, 68908c2ecf20Sopenharmony_ci#endif 68918c2ecf20Sopenharmony_ci .ndo_tx_timeout = ice_tx_timeout, 68928c2ecf20Sopenharmony_ci .ndo_bpf = ice_xdp, 68938c2ecf20Sopenharmony_ci .ndo_xdp_xmit = ice_xdp_xmit, 68948c2ecf20Sopenharmony_ci .ndo_xsk_wakeup = ice_xsk_wakeup, 68958c2ecf20Sopenharmony_ci .ndo_udp_tunnel_add = udp_tunnel_nic_add_port, 68968c2ecf20Sopenharmony_ci .ndo_udp_tunnel_del = udp_tunnel_nic_del_port, 68978c2ecf20Sopenharmony_ci}; 6898