xref: /openbmc/linux/drivers/net/ethernet/intel/fm10k/fm10k_common.c (revision 3eb66e91a25497065c5322b1268cbc3953642227)
1ae06c70bSJeff Kirsher // SPDX-License-Identifier: GPL-2.0
2*51dce24bSJeff Kirsher /* Copyright(c) 2013 - 2018 Intel Corporation. */
3b6fec18fSAlexander Duyck 
4b6fec18fSAlexander Duyck #include "fm10k_common.h"
5b6fec18fSAlexander Duyck 
6b6fec18fSAlexander Duyck /**
7b6fec18fSAlexander Duyck  *  fm10k_get_bus_info_generic - Generic set PCI bus info
8b6fec18fSAlexander Duyck  *  @hw: pointer to hardware structure
9b6fec18fSAlexander Duyck  *
10b6fec18fSAlexander Duyck  *  Gets the PCI bus info (speed, width, type) then calls helper function to
11b6fec18fSAlexander Duyck  *  store this data within the fm10k_hw structure.
12b6fec18fSAlexander Duyck  **/
fm10k_get_bus_info_generic(struct fm10k_hw * hw)13b6fec18fSAlexander Duyck s32 fm10k_get_bus_info_generic(struct fm10k_hw *hw)
14b6fec18fSAlexander Duyck {
15b6fec18fSAlexander Duyck 	u16 link_cap, link_status, device_cap, device_control;
16b6fec18fSAlexander Duyck 
17b6fec18fSAlexander Duyck 	/* Get the maximum link width and speed from PCIe config space */
18b6fec18fSAlexander Duyck 	link_cap = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_LINK_CAP);
19b6fec18fSAlexander Duyck 
20b6fec18fSAlexander Duyck 	switch (link_cap & FM10K_PCIE_LINK_WIDTH) {
21b6fec18fSAlexander Duyck 	case FM10K_PCIE_LINK_WIDTH_1:
22b6fec18fSAlexander Duyck 		hw->bus_caps.width = fm10k_bus_width_pcie_x1;
23b6fec18fSAlexander Duyck 		break;
24b6fec18fSAlexander Duyck 	case FM10K_PCIE_LINK_WIDTH_2:
25b6fec18fSAlexander Duyck 		hw->bus_caps.width = fm10k_bus_width_pcie_x2;
26b6fec18fSAlexander Duyck 		break;
27b6fec18fSAlexander Duyck 	case FM10K_PCIE_LINK_WIDTH_4:
28b6fec18fSAlexander Duyck 		hw->bus_caps.width = fm10k_bus_width_pcie_x4;
29b6fec18fSAlexander Duyck 		break;
30b6fec18fSAlexander Duyck 	case FM10K_PCIE_LINK_WIDTH_8:
31b6fec18fSAlexander Duyck 		hw->bus_caps.width = fm10k_bus_width_pcie_x8;
32b6fec18fSAlexander Duyck 		break;
33b6fec18fSAlexander Duyck 	default:
34b6fec18fSAlexander Duyck 		hw->bus_caps.width = fm10k_bus_width_unknown;
35b6fec18fSAlexander Duyck 		break;
36b6fec18fSAlexander Duyck 	}
37b6fec18fSAlexander Duyck 
38b6fec18fSAlexander Duyck 	switch (link_cap & FM10K_PCIE_LINK_SPEED) {
39b6fec18fSAlexander Duyck 	case FM10K_PCIE_LINK_SPEED_2500:
40b6fec18fSAlexander Duyck 		hw->bus_caps.speed = fm10k_bus_speed_2500;
41b6fec18fSAlexander Duyck 		break;
42b6fec18fSAlexander Duyck 	case FM10K_PCIE_LINK_SPEED_5000:
43b6fec18fSAlexander Duyck 		hw->bus_caps.speed = fm10k_bus_speed_5000;
44b6fec18fSAlexander Duyck 		break;
45b6fec18fSAlexander Duyck 	case FM10K_PCIE_LINK_SPEED_8000:
46b6fec18fSAlexander Duyck 		hw->bus_caps.speed = fm10k_bus_speed_8000;
47b6fec18fSAlexander Duyck 		break;
48b6fec18fSAlexander Duyck 	default:
49b6fec18fSAlexander Duyck 		hw->bus_caps.speed = fm10k_bus_speed_unknown;
50b6fec18fSAlexander Duyck 		break;
51b6fec18fSAlexander Duyck 	}
52b6fec18fSAlexander Duyck 
53b6fec18fSAlexander Duyck 	/* Get the PCIe maximum payload size for the PCIe function */
54b6fec18fSAlexander Duyck 	device_cap = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_DEV_CAP);
55b6fec18fSAlexander Duyck 
56b6fec18fSAlexander Duyck 	switch (device_cap & FM10K_PCIE_DEV_CAP_PAYLOAD) {
57b6fec18fSAlexander Duyck 	case FM10K_PCIE_DEV_CAP_PAYLOAD_128:
58b6fec18fSAlexander Duyck 		hw->bus_caps.payload = fm10k_bus_payload_128;
59b6fec18fSAlexander Duyck 		break;
60b6fec18fSAlexander Duyck 	case FM10K_PCIE_DEV_CAP_PAYLOAD_256:
61b6fec18fSAlexander Duyck 		hw->bus_caps.payload = fm10k_bus_payload_256;
62b6fec18fSAlexander Duyck 		break;
63b6fec18fSAlexander Duyck 	case FM10K_PCIE_DEV_CAP_PAYLOAD_512:
64b6fec18fSAlexander Duyck 		hw->bus_caps.payload = fm10k_bus_payload_512;
65b6fec18fSAlexander Duyck 		break;
66b6fec18fSAlexander Duyck 	default:
67b6fec18fSAlexander Duyck 		hw->bus_caps.payload = fm10k_bus_payload_unknown;
68b6fec18fSAlexander Duyck 		break;
69b6fec18fSAlexander Duyck 	}
70b6fec18fSAlexander Duyck 
71b6fec18fSAlexander Duyck 	/* Get the negotiated link width and speed from PCIe config space */
72b6fec18fSAlexander Duyck 	link_status = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_LINK_STATUS);
73b6fec18fSAlexander Duyck 
74b6fec18fSAlexander Duyck 	switch (link_status & FM10K_PCIE_LINK_WIDTH) {
75b6fec18fSAlexander Duyck 	case FM10K_PCIE_LINK_WIDTH_1:
76b6fec18fSAlexander Duyck 		hw->bus.width = fm10k_bus_width_pcie_x1;
77b6fec18fSAlexander Duyck 		break;
78b6fec18fSAlexander Duyck 	case FM10K_PCIE_LINK_WIDTH_2:
79b6fec18fSAlexander Duyck 		hw->bus.width = fm10k_bus_width_pcie_x2;
80b6fec18fSAlexander Duyck 		break;
81b6fec18fSAlexander Duyck 	case FM10K_PCIE_LINK_WIDTH_4:
82b6fec18fSAlexander Duyck 		hw->bus.width = fm10k_bus_width_pcie_x4;
83b6fec18fSAlexander Duyck 		break;
84b6fec18fSAlexander Duyck 	case FM10K_PCIE_LINK_WIDTH_8:
85b6fec18fSAlexander Duyck 		hw->bus.width = fm10k_bus_width_pcie_x8;
86b6fec18fSAlexander Duyck 		break;
87b6fec18fSAlexander Duyck 	default:
88b6fec18fSAlexander Duyck 		hw->bus.width = fm10k_bus_width_unknown;
89b6fec18fSAlexander Duyck 		break;
90b6fec18fSAlexander Duyck 	}
91b6fec18fSAlexander Duyck 
92b6fec18fSAlexander Duyck 	switch (link_status & FM10K_PCIE_LINK_SPEED) {
93b6fec18fSAlexander Duyck 	case FM10K_PCIE_LINK_SPEED_2500:
94b6fec18fSAlexander Duyck 		hw->bus.speed = fm10k_bus_speed_2500;
95b6fec18fSAlexander Duyck 		break;
96b6fec18fSAlexander Duyck 	case FM10K_PCIE_LINK_SPEED_5000:
97b6fec18fSAlexander Duyck 		hw->bus.speed = fm10k_bus_speed_5000;
98b6fec18fSAlexander Duyck 		break;
99b6fec18fSAlexander Duyck 	case FM10K_PCIE_LINK_SPEED_8000:
100b6fec18fSAlexander Duyck 		hw->bus.speed = fm10k_bus_speed_8000;
101b6fec18fSAlexander Duyck 		break;
102b6fec18fSAlexander Duyck 	default:
103b6fec18fSAlexander Duyck 		hw->bus.speed = fm10k_bus_speed_unknown;
104b6fec18fSAlexander Duyck 		break;
105b6fec18fSAlexander Duyck 	}
106b6fec18fSAlexander Duyck 
107b6fec18fSAlexander Duyck 	/* Get the negotiated PCIe maximum payload size for the PCIe function */
108b6fec18fSAlexander Duyck 	device_control = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_DEV_CTRL);
109b6fec18fSAlexander Duyck 
110b6fec18fSAlexander Duyck 	switch (device_control & FM10K_PCIE_DEV_CTRL_PAYLOAD) {
111b6fec18fSAlexander Duyck 	case FM10K_PCIE_DEV_CTRL_PAYLOAD_128:
112b6fec18fSAlexander Duyck 		hw->bus.payload = fm10k_bus_payload_128;
113b6fec18fSAlexander Duyck 		break;
114b6fec18fSAlexander Duyck 	case FM10K_PCIE_DEV_CTRL_PAYLOAD_256:
115b6fec18fSAlexander Duyck 		hw->bus.payload = fm10k_bus_payload_256;
116b6fec18fSAlexander Duyck 		break;
117b6fec18fSAlexander Duyck 	case FM10K_PCIE_DEV_CTRL_PAYLOAD_512:
118b6fec18fSAlexander Duyck 		hw->bus.payload = fm10k_bus_payload_512;
119b6fec18fSAlexander Duyck 		break;
120b6fec18fSAlexander Duyck 	default:
121b6fec18fSAlexander Duyck 		hw->bus.payload = fm10k_bus_payload_unknown;
122b6fec18fSAlexander Duyck 		break;
123b6fec18fSAlexander Duyck 	}
124b6fec18fSAlexander Duyck 
125b6fec18fSAlexander Duyck 	return 0;
126b6fec18fSAlexander Duyck }
127b6fec18fSAlexander Duyck 
fm10k_get_pcie_msix_count_generic(struct fm10k_hw * hw)128b6fec18fSAlexander Duyck static u16 fm10k_get_pcie_msix_count_generic(struct fm10k_hw *hw)
129b6fec18fSAlexander Duyck {
130b6fec18fSAlexander Duyck 	u16 msix_count;
131b6fec18fSAlexander Duyck 
132b6fec18fSAlexander Duyck 	/* read in value from MSI-X capability register */
133b6fec18fSAlexander Duyck 	msix_count = fm10k_read_pci_cfg_word(hw, FM10K_PCI_MSIX_MSG_CTRL);
134b6fec18fSAlexander Duyck 	msix_count &= FM10K_PCI_MSIX_MSG_CTRL_TBL_SZ_MASK;
135b6fec18fSAlexander Duyck 
136b6fec18fSAlexander Duyck 	/* MSI-X count is zero-based in HW */
137b6fec18fSAlexander Duyck 	msix_count++;
138b6fec18fSAlexander Duyck 
139b6fec18fSAlexander Duyck 	if (msix_count > FM10K_MAX_MSIX_VECTORS)
140b6fec18fSAlexander Duyck 		msix_count = FM10K_MAX_MSIX_VECTORS;
141b6fec18fSAlexander Duyck 
142b6fec18fSAlexander Duyck 	return msix_count;
143b6fec18fSAlexander Duyck }
144b6fec18fSAlexander Duyck 
145b6fec18fSAlexander Duyck /**
146b6fec18fSAlexander Duyck  *  fm10k_get_invariants_generic - Inits constant values
147b6fec18fSAlexander Duyck  *  @hw: pointer to the hardware structure
148b6fec18fSAlexander Duyck  *
149b6fec18fSAlexander Duyck  *  Initialize the common invariants for the device.
150b6fec18fSAlexander Duyck  **/
fm10k_get_invariants_generic(struct fm10k_hw * hw)151b6fec18fSAlexander Duyck s32 fm10k_get_invariants_generic(struct fm10k_hw *hw)
152b6fec18fSAlexander Duyck {
153b6fec18fSAlexander Duyck 	struct fm10k_mac_info *mac = &hw->mac;
154b6fec18fSAlexander Duyck 
155b6fec18fSAlexander Duyck 	/* initialize GLORT state to avoid any false hits */
156b6fec18fSAlexander Duyck 	mac->dglort_map = FM10K_DGLORTMAP_NONE;
157b6fec18fSAlexander Duyck 
158b6fec18fSAlexander Duyck 	/* record maximum number of MSI-X vectors */
159b6fec18fSAlexander Duyck 	mac->max_msix_vectors = fm10k_get_pcie_msix_count_generic(hw);
160b6fec18fSAlexander Duyck 
161b6fec18fSAlexander Duyck 	return 0;
162b6fec18fSAlexander Duyck }
163b6fec18fSAlexander Duyck 
164b6fec18fSAlexander Duyck /**
165b6fec18fSAlexander Duyck  *  fm10k_start_hw_generic - Prepare hardware for Tx/Rx
166b6fec18fSAlexander Duyck  *  @hw: pointer to hardware structure
167b6fec18fSAlexander Duyck  *
168b6fec18fSAlexander Duyck  *  This function sets the Tx ready flag to indicate that the Tx path has
169b6fec18fSAlexander Duyck  *  been initialized.
170b6fec18fSAlexander Duyck  **/
fm10k_start_hw_generic(struct fm10k_hw * hw)171b6fec18fSAlexander Duyck s32 fm10k_start_hw_generic(struct fm10k_hw *hw)
172b6fec18fSAlexander Duyck {
173b6fec18fSAlexander Duyck 	/* set flag indicating we are beginning Tx */
174b6fec18fSAlexander Duyck 	hw->mac.tx_ready = true;
175b6fec18fSAlexander Duyck 
176b6fec18fSAlexander Duyck 	return 0;
177b6fec18fSAlexander Duyck }
178b6fec18fSAlexander Duyck 
179b6fec18fSAlexander Duyck /**
180b6fec18fSAlexander Duyck  *  fm10k_disable_queues_generic - Stop Tx/Rx queues
181b6fec18fSAlexander Duyck  *  @hw: pointer to hardware structure
182b6fec18fSAlexander Duyck  *  @q_cnt: number of queues to be disabled
183b6fec18fSAlexander Duyck  *
184b6fec18fSAlexander Duyck  **/
fm10k_disable_queues_generic(struct fm10k_hw * hw,u16 q_cnt)185b6fec18fSAlexander Duyck s32 fm10k_disable_queues_generic(struct fm10k_hw *hw, u16 q_cnt)
186b6fec18fSAlexander Duyck {
187b6fec18fSAlexander Duyck 	u32 reg;
188b6fec18fSAlexander Duyck 	u16 i, time;
189b6fec18fSAlexander Duyck 
190b6fec18fSAlexander Duyck 	/* clear tx_ready to prevent any false hits for reset */
191b6fec18fSAlexander Duyck 	hw->mac.tx_ready = false;
192b6fec18fSAlexander Duyck 
1935f45c830SJacob Keller 	if (FM10K_REMOVED(hw->hw_addr))
1945f45c830SJacob Keller 		return 0;
1955f45c830SJacob Keller 
196b6fec18fSAlexander Duyck 	/* clear the enable bit for all rings */
197b6fec18fSAlexander Duyck 	for (i = 0; i < q_cnt; i++) {
198b6fec18fSAlexander Duyck 		reg = fm10k_read_reg(hw, FM10K_TXDCTL(i));
199b6fec18fSAlexander Duyck 		fm10k_write_reg(hw, FM10K_TXDCTL(i),
200b6fec18fSAlexander Duyck 				reg & ~FM10K_TXDCTL_ENABLE);
201b6fec18fSAlexander Duyck 		reg = fm10k_read_reg(hw, FM10K_RXQCTL(i));
202b6fec18fSAlexander Duyck 		fm10k_write_reg(hw, FM10K_RXQCTL(i),
203b6fec18fSAlexander Duyck 				reg & ~FM10K_RXQCTL_ENABLE);
204b6fec18fSAlexander Duyck 	}
205b6fec18fSAlexander Duyck 
206b6fec18fSAlexander Duyck 	fm10k_write_flush(hw);
207b6fec18fSAlexander Duyck 	udelay(1);
208b6fec18fSAlexander Duyck 
209b6fec18fSAlexander Duyck 	/* loop through all queues to verify that they are all disabled */
210b6fec18fSAlexander Duyck 	for (i = 0, time = FM10K_QUEUE_DISABLE_TIMEOUT; time;) {
211b6fec18fSAlexander Duyck 		/* if we are at end of rings all rings are disabled */
212b6fec18fSAlexander Duyck 		if (i == q_cnt)
213b6fec18fSAlexander Duyck 			return 0;
214b6fec18fSAlexander Duyck 
215b6fec18fSAlexander Duyck 		/* if queue enables cleared, then move to next ring pair */
216b6fec18fSAlexander Duyck 		reg = fm10k_read_reg(hw, FM10K_TXDCTL(i));
217b6fec18fSAlexander Duyck 		if (!~reg || !(reg & FM10K_TXDCTL_ENABLE)) {
218b6fec18fSAlexander Duyck 			reg = fm10k_read_reg(hw, FM10K_RXQCTL(i));
219b6fec18fSAlexander Duyck 			if (!~reg || !(reg & FM10K_RXQCTL_ENABLE)) {
220b6fec18fSAlexander Duyck 				i++;
221b6fec18fSAlexander Duyck 				continue;
222b6fec18fSAlexander Duyck 			}
223b6fec18fSAlexander Duyck 		}
224b6fec18fSAlexander Duyck 
225b6fec18fSAlexander Duyck 		/* decrement time and wait 1 usec */
226b6fec18fSAlexander Duyck 		time--;
227b6fec18fSAlexander Duyck 		if (time)
228b6fec18fSAlexander Duyck 			udelay(1);
229b6fec18fSAlexander Duyck 	}
230b6fec18fSAlexander Duyck 
231b6fec18fSAlexander Duyck 	return FM10K_ERR_REQUESTS_PENDING;
232b6fec18fSAlexander Duyck }
233b6fec18fSAlexander Duyck 
234b6fec18fSAlexander Duyck /**
235b6fec18fSAlexander Duyck  *  fm10k_stop_hw_generic - Stop Tx/Rx units
236b6fec18fSAlexander Duyck  *  @hw: pointer to hardware structure
237b6fec18fSAlexander Duyck  *
238b6fec18fSAlexander Duyck  **/
fm10k_stop_hw_generic(struct fm10k_hw * hw)239b6fec18fSAlexander Duyck s32 fm10k_stop_hw_generic(struct fm10k_hw *hw)
240b6fec18fSAlexander Duyck {
241b6fec18fSAlexander Duyck 	return fm10k_disable_queues_generic(hw, hw->mac.max_queues);
242b6fec18fSAlexander Duyck }
243b6fec18fSAlexander Duyck 
244b6fec18fSAlexander Duyck /**
245b6fec18fSAlexander Duyck  *  fm10k_read_hw_stats_32b - Reads value of 32-bit registers
246b6fec18fSAlexander Duyck  *  @hw: pointer to the hardware structure
247b6fec18fSAlexander Duyck  *  @addr: address of register containing a 32-bit value
248363656ebSJacob Keller  *  @stat: pointer to structure holding hw stat information
249b6fec18fSAlexander Duyck  *
250b6fec18fSAlexander Duyck  *  Function reads the content of the register and returns the delta
251b6fec18fSAlexander Duyck  *  between the base and the current value.
252b6fec18fSAlexander Duyck  *  **/
fm10k_read_hw_stats_32b(struct fm10k_hw * hw,u32 addr,struct fm10k_hw_stat * stat)253b6fec18fSAlexander Duyck u32 fm10k_read_hw_stats_32b(struct fm10k_hw *hw, u32 addr,
254b6fec18fSAlexander Duyck 			    struct fm10k_hw_stat *stat)
255b6fec18fSAlexander Duyck {
256b6fec18fSAlexander Duyck 	u32 delta = fm10k_read_reg(hw, addr) - stat->base_l;
257b6fec18fSAlexander Duyck 
258b6fec18fSAlexander Duyck 	if (FM10K_REMOVED(hw->hw_addr))
259b6fec18fSAlexander Duyck 		stat->base_h = 0;
260b6fec18fSAlexander Duyck 
261b6fec18fSAlexander Duyck 	return delta;
262b6fec18fSAlexander Duyck }
263b6fec18fSAlexander Duyck 
264b6fec18fSAlexander Duyck /**
265b6fec18fSAlexander Duyck  *  fm10k_read_hw_stats_48b - Reads value of 48-bit registers
266b6fec18fSAlexander Duyck  *  @hw: pointer to the hardware structure
267b6fec18fSAlexander Duyck  *  @addr: address of register containing the lower 32-bit value
268363656ebSJacob Keller  *  @stat: pointer to structure holding hw stat information
269b6fec18fSAlexander Duyck  *
270b6fec18fSAlexander Duyck  *  Function reads the content of 2 registers, combined to represent a 48-bit
271b6fec18fSAlexander Duyck  *  statistical value. Extra processing is required to handle overflowing.
272b6fec18fSAlexander Duyck  *  Finally, a delta value is returned representing the difference between the
273b6fec18fSAlexander Duyck  *  values stored in registers and values stored in the statistic counters.
274b6fec18fSAlexander Duyck  *  **/
fm10k_read_hw_stats_48b(struct fm10k_hw * hw,u32 addr,struct fm10k_hw_stat * stat)275b6fec18fSAlexander Duyck static u64 fm10k_read_hw_stats_48b(struct fm10k_hw *hw, u32 addr,
276b6fec18fSAlexander Duyck 				   struct fm10k_hw_stat *stat)
277b6fec18fSAlexander Duyck {
278b6fec18fSAlexander Duyck 	u32 count_l;
279b6fec18fSAlexander Duyck 	u32 count_h;
280b6fec18fSAlexander Duyck 	u32 count_tmp;
281b6fec18fSAlexander Duyck 	u64 delta;
282b6fec18fSAlexander Duyck 
283b6fec18fSAlexander Duyck 	count_h = fm10k_read_reg(hw, addr + 1);
284b6fec18fSAlexander Duyck 
285b6fec18fSAlexander Duyck 	/* Check for overflow */
286b6fec18fSAlexander Duyck 	do {
287b6fec18fSAlexander Duyck 		count_tmp = count_h;
288b6fec18fSAlexander Duyck 		count_l = fm10k_read_reg(hw, addr);
289b6fec18fSAlexander Duyck 		count_h = fm10k_read_reg(hw, addr + 1);
290b6fec18fSAlexander Duyck 	} while (count_h != count_tmp);
291b6fec18fSAlexander Duyck 
292b6fec18fSAlexander Duyck 	delta = ((u64)(count_h - stat->base_h) << 32) + count_l;
293b6fec18fSAlexander Duyck 	delta -= stat->base_l;
294b6fec18fSAlexander Duyck 
295b6fec18fSAlexander Duyck 	return delta & FM10K_48_BIT_MASK;
296b6fec18fSAlexander Duyck }
297b6fec18fSAlexander Duyck 
298b6fec18fSAlexander Duyck /**
299b6fec18fSAlexander Duyck  *  fm10k_update_hw_base_48b - Updates 48-bit statistic base value
300b6fec18fSAlexander Duyck  *  @stat: pointer to the hardware statistic structure
301b6fec18fSAlexander Duyck  *  @delta: value to be updated into the hardware statistic structure
302b6fec18fSAlexander Duyck  *
303b6fec18fSAlexander Duyck  *  Function receives a value and determines if an update is required based on
304b6fec18fSAlexander Duyck  *  a delta calculation. Only the base value will be updated.
305b6fec18fSAlexander Duyck  **/
fm10k_update_hw_base_48b(struct fm10k_hw_stat * stat,u64 delta)306b6fec18fSAlexander Duyck static void fm10k_update_hw_base_48b(struct fm10k_hw_stat *stat, u64 delta)
307b6fec18fSAlexander Duyck {
308b6fec18fSAlexander Duyck 	if (!delta)
309b6fec18fSAlexander Duyck 		return;
310b6fec18fSAlexander Duyck 
311b6fec18fSAlexander Duyck 	/* update lower 32 bits */
312b6fec18fSAlexander Duyck 	delta += stat->base_l;
313b6fec18fSAlexander Duyck 	stat->base_l = (u32)delta;
314b6fec18fSAlexander Duyck 
315b6fec18fSAlexander Duyck 	/* update upper 32 bits */
316b6fec18fSAlexander Duyck 	stat->base_h += (u32)(delta >> 32);
317b6fec18fSAlexander Duyck }
318b6fec18fSAlexander Duyck 
319b6fec18fSAlexander Duyck /**
320b6fec18fSAlexander Duyck  *  fm10k_update_hw_stats_tx_q - Updates TX queue statistics counters
321b6fec18fSAlexander Duyck  *  @hw: pointer to the hardware structure
322b6fec18fSAlexander Duyck  *  @q: pointer to the ring of hardware statistics queue
323b6fec18fSAlexander Duyck  *  @idx: index pointing to the start of the ring iteration
324b6fec18fSAlexander Duyck  *
325b6fec18fSAlexander Duyck  *  Function updates the TX queue statistics counters that are related to the
326b6fec18fSAlexander Duyck  *  hardware.
327b6fec18fSAlexander Duyck  **/
fm10k_update_hw_stats_tx_q(struct fm10k_hw * hw,struct fm10k_hw_stats_q * q,u32 idx)328b6fec18fSAlexander Duyck static void fm10k_update_hw_stats_tx_q(struct fm10k_hw *hw,
329b6fec18fSAlexander Duyck 				       struct fm10k_hw_stats_q *q,
330b6fec18fSAlexander Duyck 				       u32 idx)
331b6fec18fSAlexander Duyck {
332b6fec18fSAlexander Duyck 	u32 id_tx, id_tx_prev, tx_packets;
333b6fec18fSAlexander Duyck 	u64 tx_bytes = 0;
334b6fec18fSAlexander Duyck 
335b6fec18fSAlexander Duyck 	/* Retrieve TX Owner Data */
336b6fec18fSAlexander Duyck 	id_tx = fm10k_read_reg(hw, FM10K_TXQCTL(idx));
337b6fec18fSAlexander Duyck 
338b6fec18fSAlexander Duyck 	/* Process TX Ring */
339b6fec18fSAlexander Duyck 	do {
340b6fec18fSAlexander Duyck 		tx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPTC(idx),
341b6fec18fSAlexander Duyck 						     &q->tx_packets);
342b6fec18fSAlexander Duyck 
343b6fec18fSAlexander Duyck 		if (tx_packets)
344b6fec18fSAlexander Duyck 			tx_bytes = fm10k_read_hw_stats_48b(hw,
345b6fec18fSAlexander Duyck 							   FM10K_QBTC_L(idx),
346b6fec18fSAlexander Duyck 							   &q->tx_bytes);
347b6fec18fSAlexander Duyck 
348b6fec18fSAlexander Duyck 		/* Re-Check Owner Data */
349b6fec18fSAlexander Duyck 		id_tx_prev = id_tx;
350b6fec18fSAlexander Duyck 		id_tx = fm10k_read_reg(hw, FM10K_TXQCTL(idx));
351b6fec18fSAlexander Duyck 	} while ((id_tx ^ id_tx_prev) & FM10K_TXQCTL_ID_MASK);
352b6fec18fSAlexander Duyck 
353b6fec18fSAlexander Duyck 	/* drop non-ID bits and set VALID ID bit */
354b6fec18fSAlexander Duyck 	id_tx &= FM10K_TXQCTL_ID_MASK;
355b6fec18fSAlexander Duyck 	id_tx |= FM10K_STAT_VALID;
356b6fec18fSAlexander Duyck 
357b6fec18fSAlexander Duyck 	/* update packet counts */
358b6fec18fSAlexander Duyck 	if (q->tx_stats_idx == id_tx) {
359b6fec18fSAlexander Duyck 		q->tx_packets.count += tx_packets;
360b6fec18fSAlexander Duyck 		q->tx_bytes.count += tx_bytes;
361b6fec18fSAlexander Duyck 	}
362b6fec18fSAlexander Duyck 
363b6fec18fSAlexander Duyck 	/* update bases and record ID */
364b6fec18fSAlexander Duyck 	fm10k_update_hw_base_32b(&q->tx_packets, tx_packets);
365b6fec18fSAlexander Duyck 	fm10k_update_hw_base_48b(&q->tx_bytes, tx_bytes);
366b6fec18fSAlexander Duyck 
367b6fec18fSAlexander Duyck 	q->tx_stats_idx = id_tx;
368b6fec18fSAlexander Duyck }
369b6fec18fSAlexander Duyck 
370b6fec18fSAlexander Duyck /**
371b6fec18fSAlexander Duyck  *  fm10k_update_hw_stats_rx_q - Updates RX queue statistics counters
372b6fec18fSAlexander Duyck  *  @hw: pointer to the hardware structure
373b6fec18fSAlexander Duyck  *  @q: pointer to the ring of hardware statistics queue
374b6fec18fSAlexander Duyck  *  @idx: index pointing to the start of the ring iteration
375b6fec18fSAlexander Duyck  *
376b6fec18fSAlexander Duyck  *  Function updates the RX queue statistics counters that are related to the
377b6fec18fSAlexander Duyck  *  hardware.
378b6fec18fSAlexander Duyck  **/
fm10k_update_hw_stats_rx_q(struct fm10k_hw * hw,struct fm10k_hw_stats_q * q,u32 idx)379b6fec18fSAlexander Duyck static void fm10k_update_hw_stats_rx_q(struct fm10k_hw *hw,
380b6fec18fSAlexander Duyck 				       struct fm10k_hw_stats_q *q,
381b6fec18fSAlexander Duyck 				       u32 idx)
382b6fec18fSAlexander Duyck {
383b6fec18fSAlexander Duyck 	u32 id_rx, id_rx_prev, rx_packets, rx_drops;
384b6fec18fSAlexander Duyck 	u64 rx_bytes = 0;
385b6fec18fSAlexander Duyck 
386b6fec18fSAlexander Duyck 	/* Retrieve RX Owner Data */
387b6fec18fSAlexander Duyck 	id_rx = fm10k_read_reg(hw, FM10K_RXQCTL(idx));
388b6fec18fSAlexander Duyck 
389b6fec18fSAlexander Duyck 	/* Process RX Ring */
390b6fec18fSAlexander Duyck 	do {
391b6fec18fSAlexander Duyck 		rx_drops = fm10k_read_hw_stats_32b(hw, FM10K_QPRDC(idx),
392b6fec18fSAlexander Duyck 						   &q->rx_drops);
393b6fec18fSAlexander Duyck 
394b6fec18fSAlexander Duyck 		rx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPRC(idx),
395b6fec18fSAlexander Duyck 						     &q->rx_packets);
396b6fec18fSAlexander Duyck 
397b6fec18fSAlexander Duyck 		if (rx_packets)
398b6fec18fSAlexander Duyck 			rx_bytes = fm10k_read_hw_stats_48b(hw,
399b6fec18fSAlexander Duyck 							   FM10K_QBRC_L(idx),
400b6fec18fSAlexander Duyck 							   &q->rx_bytes);
401b6fec18fSAlexander Duyck 
402b6fec18fSAlexander Duyck 		/* Re-Check Owner Data */
403b6fec18fSAlexander Duyck 		id_rx_prev = id_rx;
404b6fec18fSAlexander Duyck 		id_rx = fm10k_read_reg(hw, FM10K_RXQCTL(idx));
405b6fec18fSAlexander Duyck 	} while ((id_rx ^ id_rx_prev) & FM10K_RXQCTL_ID_MASK);
406b6fec18fSAlexander Duyck 
407b6fec18fSAlexander Duyck 	/* drop non-ID bits and set VALID ID bit */
408b6fec18fSAlexander Duyck 	id_rx &= FM10K_RXQCTL_ID_MASK;
409b6fec18fSAlexander Duyck 	id_rx |= FM10K_STAT_VALID;
410b6fec18fSAlexander Duyck 
411b6fec18fSAlexander Duyck 	/* update packet counts */
412b6fec18fSAlexander Duyck 	if (q->rx_stats_idx == id_rx) {
413b6fec18fSAlexander Duyck 		q->rx_drops.count += rx_drops;
414b6fec18fSAlexander Duyck 		q->rx_packets.count += rx_packets;
415b6fec18fSAlexander Duyck 		q->rx_bytes.count += rx_bytes;
416b6fec18fSAlexander Duyck 	}
417b6fec18fSAlexander Duyck 
418b6fec18fSAlexander Duyck 	/* update bases and record ID */
419b6fec18fSAlexander Duyck 	fm10k_update_hw_base_32b(&q->rx_drops, rx_drops);
420b6fec18fSAlexander Duyck 	fm10k_update_hw_base_32b(&q->rx_packets, rx_packets);
421b6fec18fSAlexander Duyck 	fm10k_update_hw_base_48b(&q->rx_bytes, rx_bytes);
422b6fec18fSAlexander Duyck 
423b6fec18fSAlexander Duyck 	q->rx_stats_idx = id_rx;
424b6fec18fSAlexander Duyck }
425b6fec18fSAlexander Duyck 
426b6fec18fSAlexander Duyck /**
427b6fec18fSAlexander Duyck  *  fm10k_update_hw_stats_q - Updates queue statistics counters
428b6fec18fSAlexander Duyck  *  @hw: pointer to the hardware structure
429b6fec18fSAlexander Duyck  *  @q: pointer to the ring of hardware statistics queue
430b6fec18fSAlexander Duyck  *  @idx: index pointing to the start of the ring iteration
431b6fec18fSAlexander Duyck  *  @count: number of queues to iterate over
432b6fec18fSAlexander Duyck  *
433b6fec18fSAlexander Duyck  *  Function updates the queue statistics counters that are related to the
434b6fec18fSAlexander Duyck  *  hardware.
435b6fec18fSAlexander Duyck  **/
fm10k_update_hw_stats_q(struct fm10k_hw * hw,struct fm10k_hw_stats_q * q,u32 idx,u32 count)436b6fec18fSAlexander Duyck void fm10k_update_hw_stats_q(struct fm10k_hw *hw, struct fm10k_hw_stats_q *q,
437b6fec18fSAlexander Duyck 			     u32 idx, u32 count)
438b6fec18fSAlexander Duyck {
439b6fec18fSAlexander Duyck 	u32 i;
440b6fec18fSAlexander Duyck 
441b6fec18fSAlexander Duyck 	for (i = 0; i < count; i++, idx++, q++) {
442b6fec18fSAlexander Duyck 		fm10k_update_hw_stats_tx_q(hw, q, idx);
443b6fec18fSAlexander Duyck 		fm10k_update_hw_stats_rx_q(hw, q, idx);
444b6fec18fSAlexander Duyck 	}
445b6fec18fSAlexander Duyck }
446b6fec18fSAlexander Duyck 
447b6fec18fSAlexander Duyck /**
448b6fec18fSAlexander Duyck  *  fm10k_unbind_hw_stats_q - Unbind the queue counters from their queues
449b6fec18fSAlexander Duyck  *  @q: pointer to the ring of hardware statistics queue
450b6fec18fSAlexander Duyck  *  @idx: index pointing to the start of the ring iteration
451b6fec18fSAlexander Duyck  *  @count: number of queues to iterate over
452b6fec18fSAlexander Duyck  *
453b6fec18fSAlexander Duyck  *  Function invalidates the index values for the queues so any updates that
454b6fec18fSAlexander Duyck  *  may have happened are ignored and the base for the queue stats is reset.
455b6fec18fSAlexander Duyck  **/
fm10k_unbind_hw_stats_q(struct fm10k_hw_stats_q * q,u32 idx,u32 count)456b6fec18fSAlexander Duyck void fm10k_unbind_hw_stats_q(struct fm10k_hw_stats_q *q, u32 idx, u32 count)
457b6fec18fSAlexander Duyck {
458b6fec18fSAlexander Duyck 	u32 i;
459b6fec18fSAlexander Duyck 
460b6fec18fSAlexander Duyck 	for (i = 0; i < count; i++, idx++, q++) {
461b6fec18fSAlexander Duyck 		q->rx_stats_idx = 0;
462b6fec18fSAlexander Duyck 		q->tx_stats_idx = 0;
463b6fec18fSAlexander Duyck 	}
464b6fec18fSAlexander Duyck }
465b6fec18fSAlexander Duyck 
466b6fec18fSAlexander Duyck /**
467b6fec18fSAlexander Duyck  *  fm10k_get_host_state_generic - Returns the state of the host
468b6fec18fSAlexander Duyck  *  @hw: pointer to hardware structure
469b6fec18fSAlexander Duyck  *  @host_ready: pointer to boolean value that will record host state
470b6fec18fSAlexander Duyck  *
471b6fec18fSAlexander Duyck  *  This function will check the health of the mailbox and Tx queue 0
472b6fec18fSAlexander Duyck  *  in order to determine if we should report that the link is up or not.
473b6fec18fSAlexander Duyck  **/
fm10k_get_host_state_generic(struct fm10k_hw * hw,bool * host_ready)474b6fec18fSAlexander Duyck s32 fm10k_get_host_state_generic(struct fm10k_hw *hw, bool *host_ready)
475b6fec18fSAlexander Duyck {
476b6fec18fSAlexander Duyck 	struct fm10k_mbx_info *mbx = &hw->mbx;
477b6fec18fSAlexander Duyck 	struct fm10k_mac_info *mac = &hw->mac;
478b6fec18fSAlexander Duyck 	s32 ret_val = 0;
479b6fec18fSAlexander Duyck 	u32 txdctl = fm10k_read_reg(hw, FM10K_TXDCTL(0));
480b6fec18fSAlexander Duyck 
481b6fec18fSAlexander Duyck 	/* process upstream mailbox in case interrupts were disabled */
482b6fec18fSAlexander Duyck 	mbx->ops.process(hw, mbx);
483b6fec18fSAlexander Duyck 
484b6fec18fSAlexander Duyck 	/* If Tx is no longer enabled link should come down */
485b6fec18fSAlexander Duyck 	if (!(~txdctl) || !(txdctl & FM10K_TXDCTL_ENABLE))
486b6fec18fSAlexander Duyck 		mac->get_host_state = true;
487b6fec18fSAlexander Duyck 
488b6fec18fSAlexander Duyck 	/* exit if not checking for link, or link cannot be changed */
489b6fec18fSAlexander Duyck 	if (!mac->get_host_state || !(~txdctl))
490b6fec18fSAlexander Duyck 		goto out;
491b6fec18fSAlexander Duyck 
492b6fec18fSAlexander Duyck 	/* if we somehow dropped the Tx enable we should reset */
49350bfaee5SNgai-Mint Kwan 	if (mac->tx_ready && !(txdctl & FM10K_TXDCTL_ENABLE)) {
494b6fec18fSAlexander Duyck 		ret_val = FM10K_ERR_RESET_REQUESTED;
495b6fec18fSAlexander Duyck 		goto out;
496b6fec18fSAlexander Duyck 	}
497b6fec18fSAlexander Duyck 
498b6fec18fSAlexander Duyck 	/* if Mailbox timed out we should request reset */
499b6fec18fSAlexander Duyck 	if (!mbx->timeout) {
500b6fec18fSAlexander Duyck 		ret_val = FM10K_ERR_RESET_REQUESTED;
501b6fec18fSAlexander Duyck 		goto out;
502b6fec18fSAlexander Duyck 	}
503b6fec18fSAlexander Duyck 
5045c66d125SJacob Keller 	/* verify Mailbox is still open */
5055c66d125SJacob Keller 	if (mbx->state != FM10K_STATE_OPEN)
506b6fec18fSAlexander Duyck 		goto out;
507b6fec18fSAlexander Duyck 
508b6fec18fSAlexander Duyck 	/* interface cannot receive traffic without logical ports */
5090afd20e5SJacob Keller 	if (mac->dglort_map == FM10K_DGLORTMAP_NONE) {
51050bfaee5SNgai-Mint Kwan 		if (mac->ops.request_lport_map)
51150bfaee5SNgai-Mint Kwan 			ret_val = mac->ops.request_lport_map(hw);
5120afd20e5SJacob Keller 
513b6fec18fSAlexander Duyck 		goto out;
5140afd20e5SJacob Keller 	}
515b6fec18fSAlexander Duyck 
516b6fec18fSAlexander Duyck 	/* if we passed all the tests above then the switch is ready and we no
517b6fec18fSAlexander Duyck 	 * longer need to check for link
518b6fec18fSAlexander Duyck 	 */
519b6fec18fSAlexander Duyck 	mac->get_host_state = false;
520b6fec18fSAlexander Duyck 
521b6fec18fSAlexander Duyck out:
522b6fec18fSAlexander Duyck 	*host_ready = !mac->get_host_state;
523b6fec18fSAlexander Duyck 	return ret_val;
524b6fec18fSAlexander Duyck }
525