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