18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright(c) 2013 - 2018 Intel Corporation. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include "fm10k_common.h" 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci/** 78c2ecf20Sopenharmony_ci * fm10k_get_bus_info_generic - Generic set PCI bus info 88c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Gets the PCI bus info (speed, width, type) then calls helper function to 118c2ecf20Sopenharmony_ci * store this data within the fm10k_hw structure. 128c2ecf20Sopenharmony_ci **/ 138c2ecf20Sopenharmony_cis32 fm10k_get_bus_info_generic(struct fm10k_hw *hw) 148c2ecf20Sopenharmony_ci{ 158c2ecf20Sopenharmony_ci u16 link_cap, link_status, device_cap, device_control; 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci /* Get the maximum link width and speed from PCIe config space */ 188c2ecf20Sopenharmony_ci link_cap = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_LINK_CAP); 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci switch (link_cap & FM10K_PCIE_LINK_WIDTH) { 218c2ecf20Sopenharmony_ci case FM10K_PCIE_LINK_WIDTH_1: 228c2ecf20Sopenharmony_ci hw->bus_caps.width = fm10k_bus_width_pcie_x1; 238c2ecf20Sopenharmony_ci break; 248c2ecf20Sopenharmony_ci case FM10K_PCIE_LINK_WIDTH_2: 258c2ecf20Sopenharmony_ci hw->bus_caps.width = fm10k_bus_width_pcie_x2; 268c2ecf20Sopenharmony_ci break; 278c2ecf20Sopenharmony_ci case FM10K_PCIE_LINK_WIDTH_4: 288c2ecf20Sopenharmony_ci hw->bus_caps.width = fm10k_bus_width_pcie_x4; 298c2ecf20Sopenharmony_ci break; 308c2ecf20Sopenharmony_ci case FM10K_PCIE_LINK_WIDTH_8: 318c2ecf20Sopenharmony_ci hw->bus_caps.width = fm10k_bus_width_pcie_x8; 328c2ecf20Sopenharmony_ci break; 338c2ecf20Sopenharmony_ci default: 348c2ecf20Sopenharmony_ci hw->bus_caps.width = fm10k_bus_width_unknown; 358c2ecf20Sopenharmony_ci break; 368c2ecf20Sopenharmony_ci } 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci switch (link_cap & FM10K_PCIE_LINK_SPEED) { 398c2ecf20Sopenharmony_ci case FM10K_PCIE_LINK_SPEED_2500: 408c2ecf20Sopenharmony_ci hw->bus_caps.speed = fm10k_bus_speed_2500; 418c2ecf20Sopenharmony_ci break; 428c2ecf20Sopenharmony_ci case FM10K_PCIE_LINK_SPEED_5000: 438c2ecf20Sopenharmony_ci hw->bus_caps.speed = fm10k_bus_speed_5000; 448c2ecf20Sopenharmony_ci break; 458c2ecf20Sopenharmony_ci case FM10K_PCIE_LINK_SPEED_8000: 468c2ecf20Sopenharmony_ci hw->bus_caps.speed = fm10k_bus_speed_8000; 478c2ecf20Sopenharmony_ci break; 488c2ecf20Sopenharmony_ci default: 498c2ecf20Sopenharmony_ci hw->bus_caps.speed = fm10k_bus_speed_unknown; 508c2ecf20Sopenharmony_ci break; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci /* Get the PCIe maximum payload size for the PCIe function */ 548c2ecf20Sopenharmony_ci device_cap = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_DEV_CAP); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci switch (device_cap & FM10K_PCIE_DEV_CAP_PAYLOAD) { 578c2ecf20Sopenharmony_ci case FM10K_PCIE_DEV_CAP_PAYLOAD_128: 588c2ecf20Sopenharmony_ci hw->bus_caps.payload = fm10k_bus_payload_128; 598c2ecf20Sopenharmony_ci break; 608c2ecf20Sopenharmony_ci case FM10K_PCIE_DEV_CAP_PAYLOAD_256: 618c2ecf20Sopenharmony_ci hw->bus_caps.payload = fm10k_bus_payload_256; 628c2ecf20Sopenharmony_ci break; 638c2ecf20Sopenharmony_ci case FM10K_PCIE_DEV_CAP_PAYLOAD_512: 648c2ecf20Sopenharmony_ci hw->bus_caps.payload = fm10k_bus_payload_512; 658c2ecf20Sopenharmony_ci break; 668c2ecf20Sopenharmony_ci default: 678c2ecf20Sopenharmony_ci hw->bus_caps.payload = fm10k_bus_payload_unknown; 688c2ecf20Sopenharmony_ci break; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* Get the negotiated link width and speed from PCIe config space */ 728c2ecf20Sopenharmony_ci link_status = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_LINK_STATUS); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci switch (link_status & FM10K_PCIE_LINK_WIDTH) { 758c2ecf20Sopenharmony_ci case FM10K_PCIE_LINK_WIDTH_1: 768c2ecf20Sopenharmony_ci hw->bus.width = fm10k_bus_width_pcie_x1; 778c2ecf20Sopenharmony_ci break; 788c2ecf20Sopenharmony_ci case FM10K_PCIE_LINK_WIDTH_2: 798c2ecf20Sopenharmony_ci hw->bus.width = fm10k_bus_width_pcie_x2; 808c2ecf20Sopenharmony_ci break; 818c2ecf20Sopenharmony_ci case FM10K_PCIE_LINK_WIDTH_4: 828c2ecf20Sopenharmony_ci hw->bus.width = fm10k_bus_width_pcie_x4; 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci case FM10K_PCIE_LINK_WIDTH_8: 858c2ecf20Sopenharmony_ci hw->bus.width = fm10k_bus_width_pcie_x8; 868c2ecf20Sopenharmony_ci break; 878c2ecf20Sopenharmony_ci default: 888c2ecf20Sopenharmony_ci hw->bus.width = fm10k_bus_width_unknown; 898c2ecf20Sopenharmony_ci break; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci switch (link_status & FM10K_PCIE_LINK_SPEED) { 938c2ecf20Sopenharmony_ci case FM10K_PCIE_LINK_SPEED_2500: 948c2ecf20Sopenharmony_ci hw->bus.speed = fm10k_bus_speed_2500; 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci case FM10K_PCIE_LINK_SPEED_5000: 978c2ecf20Sopenharmony_ci hw->bus.speed = fm10k_bus_speed_5000; 988c2ecf20Sopenharmony_ci break; 998c2ecf20Sopenharmony_ci case FM10K_PCIE_LINK_SPEED_8000: 1008c2ecf20Sopenharmony_ci hw->bus.speed = fm10k_bus_speed_8000; 1018c2ecf20Sopenharmony_ci break; 1028c2ecf20Sopenharmony_ci default: 1038c2ecf20Sopenharmony_ci hw->bus.speed = fm10k_bus_speed_unknown; 1048c2ecf20Sopenharmony_ci break; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* Get the negotiated PCIe maximum payload size for the PCIe function */ 1088c2ecf20Sopenharmony_ci device_control = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_DEV_CTRL); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci switch (device_control & FM10K_PCIE_DEV_CTRL_PAYLOAD) { 1118c2ecf20Sopenharmony_ci case FM10K_PCIE_DEV_CTRL_PAYLOAD_128: 1128c2ecf20Sopenharmony_ci hw->bus.payload = fm10k_bus_payload_128; 1138c2ecf20Sopenharmony_ci break; 1148c2ecf20Sopenharmony_ci case FM10K_PCIE_DEV_CTRL_PAYLOAD_256: 1158c2ecf20Sopenharmony_ci hw->bus.payload = fm10k_bus_payload_256; 1168c2ecf20Sopenharmony_ci break; 1178c2ecf20Sopenharmony_ci case FM10K_PCIE_DEV_CTRL_PAYLOAD_512: 1188c2ecf20Sopenharmony_ci hw->bus.payload = fm10k_bus_payload_512; 1198c2ecf20Sopenharmony_ci break; 1208c2ecf20Sopenharmony_ci default: 1218c2ecf20Sopenharmony_ci hw->bus.payload = fm10k_bus_payload_unknown; 1228c2ecf20Sopenharmony_ci break; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic u16 fm10k_get_pcie_msix_count_generic(struct fm10k_hw *hw) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci u16 msix_count; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* read in value from MSI-X capability register */ 1338c2ecf20Sopenharmony_ci msix_count = fm10k_read_pci_cfg_word(hw, FM10K_PCI_MSIX_MSG_CTRL); 1348c2ecf20Sopenharmony_ci msix_count &= FM10K_PCI_MSIX_MSG_CTRL_TBL_SZ_MASK; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* MSI-X count is zero-based in HW */ 1378c2ecf20Sopenharmony_ci msix_count++; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (msix_count > FM10K_MAX_MSIX_VECTORS) 1408c2ecf20Sopenharmony_ci msix_count = FM10K_MAX_MSIX_VECTORS; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci return msix_count; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci/** 1468c2ecf20Sopenharmony_ci * fm10k_get_invariants_generic - Inits constant values 1478c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 1488c2ecf20Sopenharmony_ci * 1498c2ecf20Sopenharmony_ci * Initialize the common invariants for the device. 1508c2ecf20Sopenharmony_ci **/ 1518c2ecf20Sopenharmony_cis32 fm10k_get_invariants_generic(struct fm10k_hw *hw) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci struct fm10k_mac_info *mac = &hw->mac; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* initialize GLORT state to avoid any false hits */ 1568c2ecf20Sopenharmony_ci mac->dglort_map = FM10K_DGLORTMAP_NONE; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci /* record maximum number of MSI-X vectors */ 1598c2ecf20Sopenharmony_ci mac->max_msix_vectors = fm10k_get_pcie_msix_count_generic(hw); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/** 1658c2ecf20Sopenharmony_ci * fm10k_start_hw_generic - Prepare hardware for Tx/Rx 1668c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 1678c2ecf20Sopenharmony_ci * 1688c2ecf20Sopenharmony_ci * This function sets the Tx ready flag to indicate that the Tx path has 1698c2ecf20Sopenharmony_ci * been initialized. 1708c2ecf20Sopenharmony_ci **/ 1718c2ecf20Sopenharmony_cis32 fm10k_start_hw_generic(struct fm10k_hw *hw) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci /* set flag indicating we are beginning Tx */ 1748c2ecf20Sopenharmony_ci hw->mac.tx_ready = true; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return 0; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/** 1808c2ecf20Sopenharmony_ci * fm10k_disable_queues_generic - Stop Tx/Rx queues 1818c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 1828c2ecf20Sopenharmony_ci * @q_cnt: number of queues to be disabled 1838c2ecf20Sopenharmony_ci * 1848c2ecf20Sopenharmony_ci **/ 1858c2ecf20Sopenharmony_cis32 fm10k_disable_queues_generic(struct fm10k_hw *hw, u16 q_cnt) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci u32 reg; 1888c2ecf20Sopenharmony_ci u16 i, time; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* clear tx_ready to prevent any false hits for reset */ 1918c2ecf20Sopenharmony_ci hw->mac.tx_ready = false; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (FM10K_REMOVED(hw->hw_addr)) 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* clear the enable bit for all rings */ 1978c2ecf20Sopenharmony_ci for (i = 0; i < q_cnt; i++) { 1988c2ecf20Sopenharmony_ci reg = fm10k_read_reg(hw, FM10K_TXDCTL(i)); 1998c2ecf20Sopenharmony_ci fm10k_write_reg(hw, FM10K_TXDCTL(i), 2008c2ecf20Sopenharmony_ci reg & ~FM10K_TXDCTL_ENABLE); 2018c2ecf20Sopenharmony_ci reg = fm10k_read_reg(hw, FM10K_RXQCTL(i)); 2028c2ecf20Sopenharmony_ci fm10k_write_reg(hw, FM10K_RXQCTL(i), 2038c2ecf20Sopenharmony_ci reg & ~FM10K_RXQCTL_ENABLE); 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci fm10k_write_flush(hw); 2078c2ecf20Sopenharmony_ci udelay(1); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* loop through all queues to verify that they are all disabled */ 2108c2ecf20Sopenharmony_ci for (i = 0, time = FM10K_QUEUE_DISABLE_TIMEOUT; time;) { 2118c2ecf20Sopenharmony_ci /* if we are at end of rings all rings are disabled */ 2128c2ecf20Sopenharmony_ci if (i == q_cnt) 2138c2ecf20Sopenharmony_ci return 0; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* if queue enables cleared, then move to next ring pair */ 2168c2ecf20Sopenharmony_ci reg = fm10k_read_reg(hw, FM10K_TXDCTL(i)); 2178c2ecf20Sopenharmony_ci if (!~reg || !(reg & FM10K_TXDCTL_ENABLE)) { 2188c2ecf20Sopenharmony_ci reg = fm10k_read_reg(hw, FM10K_RXQCTL(i)); 2198c2ecf20Sopenharmony_ci if (!~reg || !(reg & FM10K_RXQCTL_ENABLE)) { 2208c2ecf20Sopenharmony_ci i++; 2218c2ecf20Sopenharmony_ci continue; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* decrement time and wait 1 usec */ 2268c2ecf20Sopenharmony_ci time--; 2278c2ecf20Sopenharmony_ci if (time) 2288c2ecf20Sopenharmony_ci udelay(1); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return FM10K_ERR_REQUESTS_PENDING; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/** 2358c2ecf20Sopenharmony_ci * fm10k_stop_hw_generic - Stop Tx/Rx units 2368c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 2378c2ecf20Sopenharmony_ci * 2388c2ecf20Sopenharmony_ci **/ 2398c2ecf20Sopenharmony_cis32 fm10k_stop_hw_generic(struct fm10k_hw *hw) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci return fm10k_disable_queues_generic(hw, hw->mac.max_queues); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci/** 2458c2ecf20Sopenharmony_ci * fm10k_read_hw_stats_32b - Reads value of 32-bit registers 2468c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 2478c2ecf20Sopenharmony_ci * @addr: address of register containing a 32-bit value 2488c2ecf20Sopenharmony_ci * @stat: pointer to structure holding hw stat information 2498c2ecf20Sopenharmony_ci * 2508c2ecf20Sopenharmony_ci * Function reads the content of the register and returns the delta 2518c2ecf20Sopenharmony_ci * between the base and the current value. 2528c2ecf20Sopenharmony_ci * **/ 2538c2ecf20Sopenharmony_ciu32 fm10k_read_hw_stats_32b(struct fm10k_hw *hw, u32 addr, 2548c2ecf20Sopenharmony_ci struct fm10k_hw_stat *stat) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci u32 delta = fm10k_read_reg(hw, addr) - stat->base_l; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (FM10K_REMOVED(hw->hw_addr)) 2598c2ecf20Sopenharmony_ci stat->base_h = 0; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return delta; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci/** 2658c2ecf20Sopenharmony_ci * fm10k_read_hw_stats_48b - Reads value of 48-bit registers 2668c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 2678c2ecf20Sopenharmony_ci * @addr: address of register containing the lower 32-bit value 2688c2ecf20Sopenharmony_ci * @stat: pointer to structure holding hw stat information 2698c2ecf20Sopenharmony_ci * 2708c2ecf20Sopenharmony_ci * Function reads the content of 2 registers, combined to represent a 48-bit 2718c2ecf20Sopenharmony_ci * statistical value. Extra processing is required to handle overflowing. 2728c2ecf20Sopenharmony_ci * Finally, a delta value is returned representing the difference between the 2738c2ecf20Sopenharmony_ci * values stored in registers and values stored in the statistic counters. 2748c2ecf20Sopenharmony_ci * **/ 2758c2ecf20Sopenharmony_cistatic u64 fm10k_read_hw_stats_48b(struct fm10k_hw *hw, u32 addr, 2768c2ecf20Sopenharmony_ci struct fm10k_hw_stat *stat) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci u32 count_l; 2798c2ecf20Sopenharmony_ci u32 count_h; 2808c2ecf20Sopenharmony_ci u32 count_tmp; 2818c2ecf20Sopenharmony_ci u64 delta; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci count_h = fm10k_read_reg(hw, addr + 1); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* Check for overflow */ 2868c2ecf20Sopenharmony_ci do { 2878c2ecf20Sopenharmony_ci count_tmp = count_h; 2888c2ecf20Sopenharmony_ci count_l = fm10k_read_reg(hw, addr); 2898c2ecf20Sopenharmony_ci count_h = fm10k_read_reg(hw, addr + 1); 2908c2ecf20Sopenharmony_ci } while (count_h != count_tmp); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci delta = ((u64)(count_h - stat->base_h) << 32) + count_l; 2938c2ecf20Sopenharmony_ci delta -= stat->base_l; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return delta & FM10K_48_BIT_MASK; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/** 2998c2ecf20Sopenharmony_ci * fm10k_update_hw_base_48b - Updates 48-bit statistic base value 3008c2ecf20Sopenharmony_ci * @stat: pointer to the hardware statistic structure 3018c2ecf20Sopenharmony_ci * @delta: value to be updated into the hardware statistic structure 3028c2ecf20Sopenharmony_ci * 3038c2ecf20Sopenharmony_ci * Function receives a value and determines if an update is required based on 3048c2ecf20Sopenharmony_ci * a delta calculation. Only the base value will be updated. 3058c2ecf20Sopenharmony_ci **/ 3068c2ecf20Sopenharmony_cistatic void fm10k_update_hw_base_48b(struct fm10k_hw_stat *stat, u64 delta) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci if (!delta) 3098c2ecf20Sopenharmony_ci return; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* update lower 32 bits */ 3128c2ecf20Sopenharmony_ci delta += stat->base_l; 3138c2ecf20Sopenharmony_ci stat->base_l = (u32)delta; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* update upper 32 bits */ 3168c2ecf20Sopenharmony_ci stat->base_h += (u32)(delta >> 32); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci/** 3208c2ecf20Sopenharmony_ci * fm10k_update_hw_stats_tx_q - Updates TX queue statistics counters 3218c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 3228c2ecf20Sopenharmony_ci * @q: pointer to the ring of hardware statistics queue 3238c2ecf20Sopenharmony_ci * @idx: index pointing to the start of the ring iteration 3248c2ecf20Sopenharmony_ci * 3258c2ecf20Sopenharmony_ci * Function updates the TX queue statistics counters that are related to the 3268c2ecf20Sopenharmony_ci * hardware. 3278c2ecf20Sopenharmony_ci **/ 3288c2ecf20Sopenharmony_cistatic void fm10k_update_hw_stats_tx_q(struct fm10k_hw *hw, 3298c2ecf20Sopenharmony_ci struct fm10k_hw_stats_q *q, 3308c2ecf20Sopenharmony_ci u32 idx) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci u32 id_tx, id_tx_prev, tx_packets; 3338c2ecf20Sopenharmony_ci u64 tx_bytes = 0; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* Retrieve TX Owner Data */ 3368c2ecf20Sopenharmony_ci id_tx = fm10k_read_reg(hw, FM10K_TXQCTL(idx)); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* Process TX Ring */ 3398c2ecf20Sopenharmony_ci do { 3408c2ecf20Sopenharmony_ci tx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPTC(idx), 3418c2ecf20Sopenharmony_ci &q->tx_packets); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (tx_packets) 3448c2ecf20Sopenharmony_ci tx_bytes = fm10k_read_hw_stats_48b(hw, 3458c2ecf20Sopenharmony_ci FM10K_QBTC_L(idx), 3468c2ecf20Sopenharmony_ci &q->tx_bytes); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* Re-Check Owner Data */ 3498c2ecf20Sopenharmony_ci id_tx_prev = id_tx; 3508c2ecf20Sopenharmony_ci id_tx = fm10k_read_reg(hw, FM10K_TXQCTL(idx)); 3518c2ecf20Sopenharmony_ci } while ((id_tx ^ id_tx_prev) & FM10K_TXQCTL_ID_MASK); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* drop non-ID bits and set VALID ID bit */ 3548c2ecf20Sopenharmony_ci id_tx &= FM10K_TXQCTL_ID_MASK; 3558c2ecf20Sopenharmony_ci id_tx |= FM10K_STAT_VALID; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* update packet counts */ 3588c2ecf20Sopenharmony_ci if (q->tx_stats_idx == id_tx) { 3598c2ecf20Sopenharmony_ci q->tx_packets.count += tx_packets; 3608c2ecf20Sopenharmony_ci q->tx_bytes.count += tx_bytes; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* update bases and record ID */ 3648c2ecf20Sopenharmony_ci fm10k_update_hw_base_32b(&q->tx_packets, tx_packets); 3658c2ecf20Sopenharmony_ci fm10k_update_hw_base_48b(&q->tx_bytes, tx_bytes); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci q->tx_stats_idx = id_tx; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci/** 3718c2ecf20Sopenharmony_ci * fm10k_update_hw_stats_rx_q - Updates RX queue statistics counters 3728c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 3738c2ecf20Sopenharmony_ci * @q: pointer to the ring of hardware statistics queue 3748c2ecf20Sopenharmony_ci * @idx: index pointing to the start of the ring iteration 3758c2ecf20Sopenharmony_ci * 3768c2ecf20Sopenharmony_ci * Function updates the RX queue statistics counters that are related to the 3778c2ecf20Sopenharmony_ci * hardware. 3788c2ecf20Sopenharmony_ci **/ 3798c2ecf20Sopenharmony_cistatic void fm10k_update_hw_stats_rx_q(struct fm10k_hw *hw, 3808c2ecf20Sopenharmony_ci struct fm10k_hw_stats_q *q, 3818c2ecf20Sopenharmony_ci u32 idx) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci u32 id_rx, id_rx_prev, rx_packets, rx_drops; 3848c2ecf20Sopenharmony_ci u64 rx_bytes = 0; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* Retrieve RX Owner Data */ 3878c2ecf20Sopenharmony_ci id_rx = fm10k_read_reg(hw, FM10K_RXQCTL(idx)); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Process RX Ring */ 3908c2ecf20Sopenharmony_ci do { 3918c2ecf20Sopenharmony_ci rx_drops = fm10k_read_hw_stats_32b(hw, FM10K_QPRDC(idx), 3928c2ecf20Sopenharmony_ci &q->rx_drops); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci rx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPRC(idx), 3958c2ecf20Sopenharmony_ci &q->rx_packets); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (rx_packets) 3988c2ecf20Sopenharmony_ci rx_bytes = fm10k_read_hw_stats_48b(hw, 3998c2ecf20Sopenharmony_ci FM10K_QBRC_L(idx), 4008c2ecf20Sopenharmony_ci &q->rx_bytes); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci /* Re-Check Owner Data */ 4038c2ecf20Sopenharmony_ci id_rx_prev = id_rx; 4048c2ecf20Sopenharmony_ci id_rx = fm10k_read_reg(hw, FM10K_RXQCTL(idx)); 4058c2ecf20Sopenharmony_ci } while ((id_rx ^ id_rx_prev) & FM10K_RXQCTL_ID_MASK); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* drop non-ID bits and set VALID ID bit */ 4088c2ecf20Sopenharmony_ci id_rx &= FM10K_RXQCTL_ID_MASK; 4098c2ecf20Sopenharmony_ci id_rx |= FM10K_STAT_VALID; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* update packet counts */ 4128c2ecf20Sopenharmony_ci if (q->rx_stats_idx == id_rx) { 4138c2ecf20Sopenharmony_ci q->rx_drops.count += rx_drops; 4148c2ecf20Sopenharmony_ci q->rx_packets.count += rx_packets; 4158c2ecf20Sopenharmony_ci q->rx_bytes.count += rx_bytes; 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* update bases and record ID */ 4198c2ecf20Sopenharmony_ci fm10k_update_hw_base_32b(&q->rx_drops, rx_drops); 4208c2ecf20Sopenharmony_ci fm10k_update_hw_base_32b(&q->rx_packets, rx_packets); 4218c2ecf20Sopenharmony_ci fm10k_update_hw_base_48b(&q->rx_bytes, rx_bytes); 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci q->rx_stats_idx = id_rx; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci/** 4278c2ecf20Sopenharmony_ci * fm10k_update_hw_stats_q - Updates queue statistics counters 4288c2ecf20Sopenharmony_ci * @hw: pointer to the hardware structure 4298c2ecf20Sopenharmony_ci * @q: pointer to the ring of hardware statistics queue 4308c2ecf20Sopenharmony_ci * @idx: index pointing to the start of the ring iteration 4318c2ecf20Sopenharmony_ci * @count: number of queues to iterate over 4328c2ecf20Sopenharmony_ci * 4338c2ecf20Sopenharmony_ci * Function updates the queue statistics counters that are related to the 4348c2ecf20Sopenharmony_ci * hardware. 4358c2ecf20Sopenharmony_ci **/ 4368c2ecf20Sopenharmony_civoid fm10k_update_hw_stats_q(struct fm10k_hw *hw, struct fm10k_hw_stats_q *q, 4378c2ecf20Sopenharmony_ci u32 idx, u32 count) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci u32 i; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci for (i = 0; i < count; i++, idx++, q++) { 4428c2ecf20Sopenharmony_ci fm10k_update_hw_stats_tx_q(hw, q, idx); 4438c2ecf20Sopenharmony_ci fm10k_update_hw_stats_rx_q(hw, q, idx); 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci/** 4488c2ecf20Sopenharmony_ci * fm10k_unbind_hw_stats_q - Unbind the queue counters from their queues 4498c2ecf20Sopenharmony_ci * @q: pointer to the ring of hardware statistics queue 4508c2ecf20Sopenharmony_ci * @idx: index pointing to the start of the ring iteration 4518c2ecf20Sopenharmony_ci * @count: number of queues to iterate over 4528c2ecf20Sopenharmony_ci * 4538c2ecf20Sopenharmony_ci * Function invalidates the index values for the queues so any updates that 4548c2ecf20Sopenharmony_ci * may have happened are ignored and the base for the queue stats is reset. 4558c2ecf20Sopenharmony_ci **/ 4568c2ecf20Sopenharmony_civoid fm10k_unbind_hw_stats_q(struct fm10k_hw_stats_q *q, u32 idx, u32 count) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci u32 i; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci for (i = 0; i < count; i++, idx++, q++) { 4618c2ecf20Sopenharmony_ci q->rx_stats_idx = 0; 4628c2ecf20Sopenharmony_ci q->tx_stats_idx = 0; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci/** 4678c2ecf20Sopenharmony_ci * fm10k_get_host_state_generic - Returns the state of the host 4688c2ecf20Sopenharmony_ci * @hw: pointer to hardware structure 4698c2ecf20Sopenharmony_ci * @host_ready: pointer to boolean value that will record host state 4708c2ecf20Sopenharmony_ci * 4718c2ecf20Sopenharmony_ci * This function will check the health of the mailbox and Tx queue 0 4728c2ecf20Sopenharmony_ci * in order to determine if we should report that the link is up or not. 4738c2ecf20Sopenharmony_ci **/ 4748c2ecf20Sopenharmony_cis32 fm10k_get_host_state_generic(struct fm10k_hw *hw, bool *host_ready) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci struct fm10k_mbx_info *mbx = &hw->mbx; 4778c2ecf20Sopenharmony_ci struct fm10k_mac_info *mac = &hw->mac; 4788c2ecf20Sopenharmony_ci s32 ret_val = 0; 4798c2ecf20Sopenharmony_ci u32 txdctl = fm10k_read_reg(hw, FM10K_TXDCTL(0)); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* process upstream mailbox in case interrupts were disabled */ 4828c2ecf20Sopenharmony_ci mbx->ops.process(hw, mbx); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci /* If Tx is no longer enabled link should come down */ 4858c2ecf20Sopenharmony_ci if (!(~txdctl) || !(txdctl & FM10K_TXDCTL_ENABLE)) 4868c2ecf20Sopenharmony_ci mac->get_host_state = true; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci /* exit if not checking for link, or link cannot be changed */ 4898c2ecf20Sopenharmony_ci if (!mac->get_host_state || !(~txdctl)) 4908c2ecf20Sopenharmony_ci goto out; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* if we somehow dropped the Tx enable we should reset */ 4938c2ecf20Sopenharmony_ci if (mac->tx_ready && !(txdctl & FM10K_TXDCTL_ENABLE)) { 4948c2ecf20Sopenharmony_ci ret_val = FM10K_ERR_RESET_REQUESTED; 4958c2ecf20Sopenharmony_ci goto out; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci /* if Mailbox timed out we should request reset */ 4998c2ecf20Sopenharmony_ci if (!mbx->timeout) { 5008c2ecf20Sopenharmony_ci ret_val = FM10K_ERR_RESET_REQUESTED; 5018c2ecf20Sopenharmony_ci goto out; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci /* verify Mailbox is still open */ 5058c2ecf20Sopenharmony_ci if (mbx->state != FM10K_STATE_OPEN) 5068c2ecf20Sopenharmony_ci goto out; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* interface cannot receive traffic without logical ports */ 5098c2ecf20Sopenharmony_ci if (mac->dglort_map == FM10K_DGLORTMAP_NONE) { 5108c2ecf20Sopenharmony_ci if (mac->ops.request_lport_map) 5118c2ecf20Sopenharmony_ci ret_val = mac->ops.request_lport_map(hw); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci goto out; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci /* if we passed all the tests above then the switch is ready and we no 5178c2ecf20Sopenharmony_ci * longer need to check for link 5188c2ecf20Sopenharmony_ci */ 5198c2ecf20Sopenharmony_ci mac->get_host_state = false; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ciout: 5228c2ecf20Sopenharmony_ci *host_ready = !mac->get_host_state; 5238c2ecf20Sopenharmony_ci return ret_val; 5248c2ecf20Sopenharmony_ci} 525