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