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