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