162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 2013 - 2018 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include "fm10k_common.h" 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci/** 762306a36Sopenharmony_ci * fm10k_get_bus_info_generic - Generic set PCI bus info 862306a36Sopenharmony_ci * @hw: pointer to hardware structure 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Gets the PCI bus info (speed, width, type) then calls helper function to 1162306a36Sopenharmony_ci * store this data within the fm10k_hw structure. 1262306a36Sopenharmony_ci **/ 1362306a36Sopenharmony_cis32 fm10k_get_bus_info_generic(struct fm10k_hw *hw) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci u16 link_cap, link_status, device_cap, device_control; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci /* Get the maximum link width and speed from PCIe config space */ 1862306a36Sopenharmony_ci link_cap = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_LINK_CAP); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci switch (link_cap & FM10K_PCIE_LINK_WIDTH) { 2162306a36Sopenharmony_ci case FM10K_PCIE_LINK_WIDTH_1: 2262306a36Sopenharmony_ci hw->bus_caps.width = fm10k_bus_width_pcie_x1; 2362306a36Sopenharmony_ci break; 2462306a36Sopenharmony_ci case FM10K_PCIE_LINK_WIDTH_2: 2562306a36Sopenharmony_ci hw->bus_caps.width = fm10k_bus_width_pcie_x2; 2662306a36Sopenharmony_ci break; 2762306a36Sopenharmony_ci case FM10K_PCIE_LINK_WIDTH_4: 2862306a36Sopenharmony_ci hw->bus_caps.width = fm10k_bus_width_pcie_x4; 2962306a36Sopenharmony_ci break; 3062306a36Sopenharmony_ci case FM10K_PCIE_LINK_WIDTH_8: 3162306a36Sopenharmony_ci hw->bus_caps.width = fm10k_bus_width_pcie_x8; 3262306a36Sopenharmony_ci break; 3362306a36Sopenharmony_ci default: 3462306a36Sopenharmony_ci hw->bus_caps.width = fm10k_bus_width_unknown; 3562306a36Sopenharmony_ci break; 3662306a36Sopenharmony_ci } 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci switch (link_cap & FM10K_PCIE_LINK_SPEED) { 3962306a36Sopenharmony_ci case FM10K_PCIE_LINK_SPEED_2500: 4062306a36Sopenharmony_ci hw->bus_caps.speed = fm10k_bus_speed_2500; 4162306a36Sopenharmony_ci break; 4262306a36Sopenharmony_ci case FM10K_PCIE_LINK_SPEED_5000: 4362306a36Sopenharmony_ci hw->bus_caps.speed = fm10k_bus_speed_5000; 4462306a36Sopenharmony_ci break; 4562306a36Sopenharmony_ci case FM10K_PCIE_LINK_SPEED_8000: 4662306a36Sopenharmony_ci hw->bus_caps.speed = fm10k_bus_speed_8000; 4762306a36Sopenharmony_ci break; 4862306a36Sopenharmony_ci default: 4962306a36Sopenharmony_ci hw->bus_caps.speed = fm10k_bus_speed_unknown; 5062306a36Sopenharmony_ci break; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci /* Get the PCIe maximum payload size for the PCIe function */ 5462306a36Sopenharmony_ci device_cap = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_DEV_CAP); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci switch (device_cap & FM10K_PCIE_DEV_CAP_PAYLOAD) { 5762306a36Sopenharmony_ci case FM10K_PCIE_DEV_CAP_PAYLOAD_128: 5862306a36Sopenharmony_ci hw->bus_caps.payload = fm10k_bus_payload_128; 5962306a36Sopenharmony_ci break; 6062306a36Sopenharmony_ci case FM10K_PCIE_DEV_CAP_PAYLOAD_256: 6162306a36Sopenharmony_ci hw->bus_caps.payload = fm10k_bus_payload_256; 6262306a36Sopenharmony_ci break; 6362306a36Sopenharmony_ci case FM10K_PCIE_DEV_CAP_PAYLOAD_512: 6462306a36Sopenharmony_ci hw->bus_caps.payload = fm10k_bus_payload_512; 6562306a36Sopenharmony_ci break; 6662306a36Sopenharmony_ci default: 6762306a36Sopenharmony_ci hw->bus_caps.payload = fm10k_bus_payload_unknown; 6862306a36Sopenharmony_ci break; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* Get the negotiated link width and speed from PCIe config space */ 7262306a36Sopenharmony_ci link_status = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_LINK_STATUS); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci switch (link_status & FM10K_PCIE_LINK_WIDTH) { 7562306a36Sopenharmony_ci case FM10K_PCIE_LINK_WIDTH_1: 7662306a36Sopenharmony_ci hw->bus.width = fm10k_bus_width_pcie_x1; 7762306a36Sopenharmony_ci break; 7862306a36Sopenharmony_ci case FM10K_PCIE_LINK_WIDTH_2: 7962306a36Sopenharmony_ci hw->bus.width = fm10k_bus_width_pcie_x2; 8062306a36Sopenharmony_ci break; 8162306a36Sopenharmony_ci case FM10K_PCIE_LINK_WIDTH_4: 8262306a36Sopenharmony_ci hw->bus.width = fm10k_bus_width_pcie_x4; 8362306a36Sopenharmony_ci break; 8462306a36Sopenharmony_ci case FM10K_PCIE_LINK_WIDTH_8: 8562306a36Sopenharmony_ci hw->bus.width = fm10k_bus_width_pcie_x8; 8662306a36Sopenharmony_ci break; 8762306a36Sopenharmony_ci default: 8862306a36Sopenharmony_ci hw->bus.width = fm10k_bus_width_unknown; 8962306a36Sopenharmony_ci break; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci switch (link_status & FM10K_PCIE_LINK_SPEED) { 9362306a36Sopenharmony_ci case FM10K_PCIE_LINK_SPEED_2500: 9462306a36Sopenharmony_ci hw->bus.speed = fm10k_bus_speed_2500; 9562306a36Sopenharmony_ci break; 9662306a36Sopenharmony_ci case FM10K_PCIE_LINK_SPEED_5000: 9762306a36Sopenharmony_ci hw->bus.speed = fm10k_bus_speed_5000; 9862306a36Sopenharmony_ci break; 9962306a36Sopenharmony_ci case FM10K_PCIE_LINK_SPEED_8000: 10062306a36Sopenharmony_ci hw->bus.speed = fm10k_bus_speed_8000; 10162306a36Sopenharmony_ci break; 10262306a36Sopenharmony_ci default: 10362306a36Sopenharmony_ci hw->bus.speed = fm10k_bus_speed_unknown; 10462306a36Sopenharmony_ci break; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* Get the negotiated PCIe maximum payload size for the PCIe function */ 10862306a36Sopenharmony_ci device_control = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_DEV_CTRL); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci switch (device_control & FM10K_PCIE_DEV_CTRL_PAYLOAD) { 11162306a36Sopenharmony_ci case FM10K_PCIE_DEV_CTRL_PAYLOAD_128: 11262306a36Sopenharmony_ci hw->bus.payload = fm10k_bus_payload_128; 11362306a36Sopenharmony_ci break; 11462306a36Sopenharmony_ci case FM10K_PCIE_DEV_CTRL_PAYLOAD_256: 11562306a36Sopenharmony_ci hw->bus.payload = fm10k_bus_payload_256; 11662306a36Sopenharmony_ci break; 11762306a36Sopenharmony_ci case FM10K_PCIE_DEV_CTRL_PAYLOAD_512: 11862306a36Sopenharmony_ci hw->bus.payload = fm10k_bus_payload_512; 11962306a36Sopenharmony_ci break; 12062306a36Sopenharmony_ci default: 12162306a36Sopenharmony_ci hw->bus.payload = fm10k_bus_payload_unknown; 12262306a36Sopenharmony_ci break; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return 0; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic u16 fm10k_get_pcie_msix_count_generic(struct fm10k_hw *hw) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci u16 msix_count; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* read in value from MSI-X capability register */ 13362306a36Sopenharmony_ci msix_count = fm10k_read_pci_cfg_word(hw, FM10K_PCI_MSIX_MSG_CTRL); 13462306a36Sopenharmony_ci msix_count &= FM10K_PCI_MSIX_MSG_CTRL_TBL_SZ_MASK; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* MSI-X count is zero-based in HW */ 13762306a36Sopenharmony_ci msix_count++; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (msix_count > FM10K_MAX_MSIX_VECTORS) 14062306a36Sopenharmony_ci msix_count = FM10K_MAX_MSIX_VECTORS; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return msix_count; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/** 14662306a36Sopenharmony_ci * fm10k_get_invariants_generic - Inits constant values 14762306a36Sopenharmony_ci * @hw: pointer to the hardware structure 14862306a36Sopenharmony_ci * 14962306a36Sopenharmony_ci * Initialize the common invariants for the device. 15062306a36Sopenharmony_ci **/ 15162306a36Sopenharmony_cis32 fm10k_get_invariants_generic(struct fm10k_hw *hw) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct fm10k_mac_info *mac = &hw->mac; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* initialize GLORT state to avoid any false hits */ 15662306a36Sopenharmony_ci mac->dglort_map = FM10K_DGLORTMAP_NONE; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* record maximum number of MSI-X vectors */ 15962306a36Sopenharmony_ci mac->max_msix_vectors = fm10k_get_pcie_msix_count_generic(hw); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return 0; 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/** 16562306a36Sopenharmony_ci * fm10k_start_hw_generic - Prepare hardware for Tx/Rx 16662306a36Sopenharmony_ci * @hw: pointer to hardware structure 16762306a36Sopenharmony_ci * 16862306a36Sopenharmony_ci * This function sets the Tx ready flag to indicate that the Tx path has 16962306a36Sopenharmony_ci * been initialized. 17062306a36Sopenharmony_ci **/ 17162306a36Sopenharmony_cis32 fm10k_start_hw_generic(struct fm10k_hw *hw) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci /* set flag indicating we are beginning Tx */ 17462306a36Sopenharmony_ci hw->mac.tx_ready = true; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci return 0; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci/** 18062306a36Sopenharmony_ci * fm10k_disable_queues_generic - Stop Tx/Rx queues 18162306a36Sopenharmony_ci * @hw: pointer to hardware structure 18262306a36Sopenharmony_ci * @q_cnt: number of queues to be disabled 18362306a36Sopenharmony_ci * 18462306a36Sopenharmony_ci **/ 18562306a36Sopenharmony_cis32 fm10k_disable_queues_generic(struct fm10k_hw *hw, u16 q_cnt) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci u32 reg; 18862306a36Sopenharmony_ci u16 i, time; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* clear tx_ready to prevent any false hits for reset */ 19162306a36Sopenharmony_ci hw->mac.tx_ready = false; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (FM10K_REMOVED(hw->hw_addr)) 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* clear the enable bit for all rings */ 19762306a36Sopenharmony_ci for (i = 0; i < q_cnt; i++) { 19862306a36Sopenharmony_ci reg = fm10k_read_reg(hw, FM10K_TXDCTL(i)); 19962306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_TXDCTL(i), 20062306a36Sopenharmony_ci reg & ~FM10K_TXDCTL_ENABLE); 20162306a36Sopenharmony_ci reg = fm10k_read_reg(hw, FM10K_RXQCTL(i)); 20262306a36Sopenharmony_ci fm10k_write_reg(hw, FM10K_RXQCTL(i), 20362306a36Sopenharmony_ci reg & ~FM10K_RXQCTL_ENABLE); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci fm10k_write_flush(hw); 20762306a36Sopenharmony_ci udelay(1); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* loop through all queues to verify that they are all disabled */ 21062306a36Sopenharmony_ci for (i = 0, time = FM10K_QUEUE_DISABLE_TIMEOUT; time;) { 21162306a36Sopenharmony_ci /* if we are at end of rings all rings are disabled */ 21262306a36Sopenharmony_ci if (i == q_cnt) 21362306a36Sopenharmony_ci return 0; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* if queue enables cleared, then move to next ring pair */ 21662306a36Sopenharmony_ci reg = fm10k_read_reg(hw, FM10K_TXDCTL(i)); 21762306a36Sopenharmony_ci if (!~reg || !(reg & FM10K_TXDCTL_ENABLE)) { 21862306a36Sopenharmony_ci reg = fm10k_read_reg(hw, FM10K_RXQCTL(i)); 21962306a36Sopenharmony_ci if (!~reg || !(reg & FM10K_RXQCTL_ENABLE)) { 22062306a36Sopenharmony_ci i++; 22162306a36Sopenharmony_ci continue; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* decrement time and wait 1 usec */ 22662306a36Sopenharmony_ci time--; 22762306a36Sopenharmony_ci if (time) 22862306a36Sopenharmony_ci udelay(1); 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return FM10K_ERR_REQUESTS_PENDING; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci/** 23562306a36Sopenharmony_ci * fm10k_stop_hw_generic - Stop Tx/Rx units 23662306a36Sopenharmony_ci * @hw: pointer to hardware structure 23762306a36Sopenharmony_ci * 23862306a36Sopenharmony_ci **/ 23962306a36Sopenharmony_cis32 fm10k_stop_hw_generic(struct fm10k_hw *hw) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci return fm10k_disable_queues_generic(hw, hw->mac.max_queues); 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci/** 24562306a36Sopenharmony_ci * fm10k_read_hw_stats_32b - Reads value of 32-bit registers 24662306a36Sopenharmony_ci * @hw: pointer to the hardware structure 24762306a36Sopenharmony_ci * @addr: address of register containing a 32-bit value 24862306a36Sopenharmony_ci * @stat: pointer to structure holding hw stat information 24962306a36Sopenharmony_ci * 25062306a36Sopenharmony_ci * Function reads the content of the register and returns the delta 25162306a36Sopenharmony_ci * between the base and the current value. 25262306a36Sopenharmony_ci * **/ 25362306a36Sopenharmony_ciu32 fm10k_read_hw_stats_32b(struct fm10k_hw *hw, u32 addr, 25462306a36Sopenharmony_ci struct fm10k_hw_stat *stat) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci u32 delta = fm10k_read_reg(hw, addr) - stat->base_l; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (FM10K_REMOVED(hw->hw_addr)) 25962306a36Sopenharmony_ci stat->base_h = 0; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return delta; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci/** 26562306a36Sopenharmony_ci * fm10k_read_hw_stats_48b - Reads value of 48-bit registers 26662306a36Sopenharmony_ci * @hw: pointer to the hardware structure 26762306a36Sopenharmony_ci * @addr: address of register containing the lower 32-bit value 26862306a36Sopenharmony_ci * @stat: pointer to structure holding hw stat information 26962306a36Sopenharmony_ci * 27062306a36Sopenharmony_ci * Function reads the content of 2 registers, combined to represent a 48-bit 27162306a36Sopenharmony_ci * statistical value. Extra processing is required to handle overflowing. 27262306a36Sopenharmony_ci * Finally, a delta value is returned representing the difference between the 27362306a36Sopenharmony_ci * values stored in registers and values stored in the statistic counters. 27462306a36Sopenharmony_ci * **/ 27562306a36Sopenharmony_cistatic u64 fm10k_read_hw_stats_48b(struct fm10k_hw *hw, u32 addr, 27662306a36Sopenharmony_ci struct fm10k_hw_stat *stat) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci u32 count_l; 27962306a36Sopenharmony_ci u32 count_h; 28062306a36Sopenharmony_ci u32 count_tmp; 28162306a36Sopenharmony_ci u64 delta; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci count_h = fm10k_read_reg(hw, addr + 1); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* Check for overflow */ 28662306a36Sopenharmony_ci do { 28762306a36Sopenharmony_ci count_tmp = count_h; 28862306a36Sopenharmony_ci count_l = fm10k_read_reg(hw, addr); 28962306a36Sopenharmony_ci count_h = fm10k_read_reg(hw, addr + 1); 29062306a36Sopenharmony_ci } while (count_h != count_tmp); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci delta = ((u64)(count_h - stat->base_h) << 32) + count_l; 29362306a36Sopenharmony_ci delta -= stat->base_l; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci return delta & FM10K_48_BIT_MASK; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci/** 29962306a36Sopenharmony_ci * fm10k_update_hw_base_48b - Updates 48-bit statistic base value 30062306a36Sopenharmony_ci * @stat: pointer to the hardware statistic structure 30162306a36Sopenharmony_ci * @delta: value to be updated into the hardware statistic structure 30262306a36Sopenharmony_ci * 30362306a36Sopenharmony_ci * Function receives a value and determines if an update is required based on 30462306a36Sopenharmony_ci * a delta calculation. Only the base value will be updated. 30562306a36Sopenharmony_ci **/ 30662306a36Sopenharmony_cistatic void fm10k_update_hw_base_48b(struct fm10k_hw_stat *stat, u64 delta) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci if (!delta) 30962306a36Sopenharmony_ci return; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci /* update lower 32 bits */ 31262306a36Sopenharmony_ci delta += stat->base_l; 31362306a36Sopenharmony_ci stat->base_l = (u32)delta; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* update upper 32 bits */ 31662306a36Sopenharmony_ci stat->base_h += (u32)(delta >> 32); 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci/** 32062306a36Sopenharmony_ci * fm10k_update_hw_stats_tx_q - Updates TX queue statistics counters 32162306a36Sopenharmony_ci * @hw: pointer to the hardware structure 32262306a36Sopenharmony_ci * @q: pointer to the ring of hardware statistics queue 32362306a36Sopenharmony_ci * @idx: index pointing to the start of the ring iteration 32462306a36Sopenharmony_ci * 32562306a36Sopenharmony_ci * Function updates the TX queue statistics counters that are related to the 32662306a36Sopenharmony_ci * hardware. 32762306a36Sopenharmony_ci **/ 32862306a36Sopenharmony_cistatic void fm10k_update_hw_stats_tx_q(struct fm10k_hw *hw, 32962306a36Sopenharmony_ci struct fm10k_hw_stats_q *q, 33062306a36Sopenharmony_ci u32 idx) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci u32 id_tx, id_tx_prev, tx_packets; 33362306a36Sopenharmony_ci u64 tx_bytes = 0; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* Retrieve TX Owner Data */ 33662306a36Sopenharmony_ci id_tx = fm10k_read_reg(hw, FM10K_TXQCTL(idx)); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* Process TX Ring */ 33962306a36Sopenharmony_ci do { 34062306a36Sopenharmony_ci tx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPTC(idx), 34162306a36Sopenharmony_ci &q->tx_packets); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (tx_packets) 34462306a36Sopenharmony_ci tx_bytes = fm10k_read_hw_stats_48b(hw, 34562306a36Sopenharmony_ci FM10K_QBTC_L(idx), 34662306a36Sopenharmony_ci &q->tx_bytes); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* Re-Check Owner Data */ 34962306a36Sopenharmony_ci id_tx_prev = id_tx; 35062306a36Sopenharmony_ci id_tx = fm10k_read_reg(hw, FM10K_TXQCTL(idx)); 35162306a36Sopenharmony_ci } while ((id_tx ^ id_tx_prev) & FM10K_TXQCTL_ID_MASK); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci /* drop non-ID bits and set VALID ID bit */ 35462306a36Sopenharmony_ci id_tx &= FM10K_TXQCTL_ID_MASK; 35562306a36Sopenharmony_ci id_tx |= FM10K_STAT_VALID; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* update packet counts */ 35862306a36Sopenharmony_ci if (q->tx_stats_idx == id_tx) { 35962306a36Sopenharmony_ci q->tx_packets.count += tx_packets; 36062306a36Sopenharmony_ci q->tx_bytes.count += tx_bytes; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* update bases and record ID */ 36462306a36Sopenharmony_ci fm10k_update_hw_base_32b(&q->tx_packets, tx_packets); 36562306a36Sopenharmony_ci fm10k_update_hw_base_48b(&q->tx_bytes, tx_bytes); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci q->tx_stats_idx = id_tx; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci/** 37162306a36Sopenharmony_ci * fm10k_update_hw_stats_rx_q - Updates RX queue statistics counters 37262306a36Sopenharmony_ci * @hw: pointer to the hardware structure 37362306a36Sopenharmony_ci * @q: pointer to the ring of hardware statistics queue 37462306a36Sopenharmony_ci * @idx: index pointing to the start of the ring iteration 37562306a36Sopenharmony_ci * 37662306a36Sopenharmony_ci * Function updates the RX queue statistics counters that are related to the 37762306a36Sopenharmony_ci * hardware. 37862306a36Sopenharmony_ci **/ 37962306a36Sopenharmony_cistatic void fm10k_update_hw_stats_rx_q(struct fm10k_hw *hw, 38062306a36Sopenharmony_ci struct fm10k_hw_stats_q *q, 38162306a36Sopenharmony_ci u32 idx) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci u32 id_rx, id_rx_prev, rx_packets, rx_drops; 38462306a36Sopenharmony_ci u64 rx_bytes = 0; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* Retrieve RX Owner Data */ 38762306a36Sopenharmony_ci id_rx = fm10k_read_reg(hw, FM10K_RXQCTL(idx)); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci /* Process RX Ring */ 39062306a36Sopenharmony_ci do { 39162306a36Sopenharmony_ci rx_drops = fm10k_read_hw_stats_32b(hw, FM10K_QPRDC(idx), 39262306a36Sopenharmony_ci &q->rx_drops); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci rx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPRC(idx), 39562306a36Sopenharmony_ci &q->rx_packets); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (rx_packets) 39862306a36Sopenharmony_ci rx_bytes = fm10k_read_hw_stats_48b(hw, 39962306a36Sopenharmony_ci FM10K_QBRC_L(idx), 40062306a36Sopenharmony_ci &q->rx_bytes); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* Re-Check Owner Data */ 40362306a36Sopenharmony_ci id_rx_prev = id_rx; 40462306a36Sopenharmony_ci id_rx = fm10k_read_reg(hw, FM10K_RXQCTL(idx)); 40562306a36Sopenharmony_ci } while ((id_rx ^ id_rx_prev) & FM10K_RXQCTL_ID_MASK); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* drop non-ID bits and set VALID ID bit */ 40862306a36Sopenharmony_ci id_rx &= FM10K_RXQCTL_ID_MASK; 40962306a36Sopenharmony_ci id_rx |= FM10K_STAT_VALID; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci /* update packet counts */ 41262306a36Sopenharmony_ci if (q->rx_stats_idx == id_rx) { 41362306a36Sopenharmony_ci q->rx_drops.count += rx_drops; 41462306a36Sopenharmony_ci q->rx_packets.count += rx_packets; 41562306a36Sopenharmony_ci q->rx_bytes.count += rx_bytes; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci /* update bases and record ID */ 41962306a36Sopenharmony_ci fm10k_update_hw_base_32b(&q->rx_drops, rx_drops); 42062306a36Sopenharmony_ci fm10k_update_hw_base_32b(&q->rx_packets, rx_packets); 42162306a36Sopenharmony_ci fm10k_update_hw_base_48b(&q->rx_bytes, rx_bytes); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci q->rx_stats_idx = id_rx; 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci/** 42762306a36Sopenharmony_ci * fm10k_update_hw_stats_q - Updates queue statistics counters 42862306a36Sopenharmony_ci * @hw: pointer to the hardware structure 42962306a36Sopenharmony_ci * @q: pointer to the ring of hardware statistics queue 43062306a36Sopenharmony_ci * @idx: index pointing to the start of the ring iteration 43162306a36Sopenharmony_ci * @count: number of queues to iterate over 43262306a36Sopenharmony_ci * 43362306a36Sopenharmony_ci * Function updates the queue statistics counters that are related to the 43462306a36Sopenharmony_ci * hardware. 43562306a36Sopenharmony_ci **/ 43662306a36Sopenharmony_civoid fm10k_update_hw_stats_q(struct fm10k_hw *hw, struct fm10k_hw_stats_q *q, 43762306a36Sopenharmony_ci u32 idx, u32 count) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci u32 i; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci for (i = 0; i < count; i++, idx++, q++) { 44262306a36Sopenharmony_ci fm10k_update_hw_stats_tx_q(hw, q, idx); 44362306a36Sopenharmony_ci fm10k_update_hw_stats_rx_q(hw, q, idx); 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci/** 44862306a36Sopenharmony_ci * fm10k_unbind_hw_stats_q - Unbind the queue counters from their queues 44962306a36Sopenharmony_ci * @q: pointer to the ring of hardware statistics queue 45062306a36Sopenharmony_ci * @idx: index pointing to the start of the ring iteration 45162306a36Sopenharmony_ci * @count: number of queues to iterate over 45262306a36Sopenharmony_ci * 45362306a36Sopenharmony_ci * Function invalidates the index values for the queues so any updates that 45462306a36Sopenharmony_ci * may have happened are ignored and the base for the queue stats is reset. 45562306a36Sopenharmony_ci **/ 45662306a36Sopenharmony_civoid fm10k_unbind_hw_stats_q(struct fm10k_hw_stats_q *q, u32 idx, u32 count) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci u32 i; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci for (i = 0; i < count; i++, idx++, q++) { 46162306a36Sopenharmony_ci q->rx_stats_idx = 0; 46262306a36Sopenharmony_ci q->tx_stats_idx = 0; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci/** 46762306a36Sopenharmony_ci * fm10k_get_host_state_generic - Returns the state of the host 46862306a36Sopenharmony_ci * @hw: pointer to hardware structure 46962306a36Sopenharmony_ci * @host_ready: pointer to boolean value that will record host state 47062306a36Sopenharmony_ci * 47162306a36Sopenharmony_ci * This function will check the health of the mailbox and Tx queue 0 47262306a36Sopenharmony_ci * in order to determine if we should report that the link is up or not. 47362306a36Sopenharmony_ci **/ 47462306a36Sopenharmony_cis32 fm10k_get_host_state_generic(struct fm10k_hw *hw, bool *host_ready) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct fm10k_mbx_info *mbx = &hw->mbx; 47762306a36Sopenharmony_ci struct fm10k_mac_info *mac = &hw->mac; 47862306a36Sopenharmony_ci s32 ret_val = 0; 47962306a36Sopenharmony_ci u32 txdctl = fm10k_read_reg(hw, FM10K_TXDCTL(0)); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci /* process upstream mailbox in case interrupts were disabled */ 48262306a36Sopenharmony_ci mbx->ops.process(hw, mbx); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci /* If Tx is no longer enabled link should come down */ 48562306a36Sopenharmony_ci if (!(~txdctl) || !(txdctl & FM10K_TXDCTL_ENABLE)) 48662306a36Sopenharmony_ci mac->get_host_state = true; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* exit if not checking for link, or link cannot be changed */ 48962306a36Sopenharmony_ci if (!mac->get_host_state || !(~txdctl)) 49062306a36Sopenharmony_ci goto out; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* if we somehow dropped the Tx enable we should reset */ 49362306a36Sopenharmony_ci if (mac->tx_ready && !(txdctl & FM10K_TXDCTL_ENABLE)) { 49462306a36Sopenharmony_ci ret_val = FM10K_ERR_RESET_REQUESTED; 49562306a36Sopenharmony_ci goto out; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* if Mailbox timed out we should request reset */ 49962306a36Sopenharmony_ci if (!mbx->timeout) { 50062306a36Sopenharmony_ci ret_val = FM10K_ERR_RESET_REQUESTED; 50162306a36Sopenharmony_ci goto out; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci /* verify Mailbox is still open */ 50562306a36Sopenharmony_ci if (mbx->state != FM10K_STATE_OPEN) 50662306a36Sopenharmony_ci goto out; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci /* interface cannot receive traffic without logical ports */ 50962306a36Sopenharmony_ci if (mac->dglort_map == FM10K_DGLORTMAP_NONE) { 51062306a36Sopenharmony_ci if (mac->ops.request_lport_map) 51162306a36Sopenharmony_ci ret_val = mac->ops.request_lport_map(hw); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci goto out; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* if we passed all the tests above then the switch is ready and we no 51762306a36Sopenharmony_ci * longer need to check for link 51862306a36Sopenharmony_ci */ 51962306a36Sopenharmony_ci mac->get_host_state = false; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ciout: 52262306a36Sopenharmony_ci *host_ready = !mac->get_host_state; 52362306a36Sopenharmony_ci return ret_val; 52462306a36Sopenharmony_ci} 525