525 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright(c) 2013 - 2018 Intel Corporation. */3 4#include "fm10k_common.h"5 6/**7 * fm10k_get_bus_info_generic - Generic set PCI bus info8 * @hw: pointer to hardware structure9 *10 * Gets the PCI bus info (speed, width, type) then calls helper function to11 * store this data within the fm10k_hw structure.12 **/13s32 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 128static 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 values147 * @hw: pointer to the hardware structure148 *149 * Initialize the common invariants for the device.150 **/151s32 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/Rx166 * @hw: pointer to hardware structure167 *168 * This function sets the Tx ready flag to indicate that the Tx path has169 * been initialized.170 **/171s32 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 queues181 * @hw: pointer to hardware structure182 * @q_cnt: number of queues to be disabled183 *184 **/185s32 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 units236 * @hw: pointer to hardware structure237 *238 **/239s32 fm10k_stop_hw_generic(struct fm10k_hw *hw)240{241 return fm10k_disable_queues_generic(hw, hw->mac.max_queues);242}243 244/**245 * fm10k_read_hw_stats_32b - Reads value of 32-bit registers246 * @hw: pointer to the hardware structure247 * @addr: address of register containing a 32-bit value248 * @stat: pointer to structure holding hw stat information249 *250 * Function reads the content of the register and returns the delta251 * between the base and the current value.252 * **/253u32 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, 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 registers266 * @hw: pointer to the hardware structure267 * @addr: address of register containing the lower 32-bit value268 * @stat: pointer to structure holding hw stat information269 *270 * Function reads the content of 2 registers, combined to represent a 48-bit271 * statistical value. Extra processing is required to handle overflowing.272 * Finally, a delta value is returned representing the difference between the273 * values stored in registers and values stored in the statistic counters.274 * **/275static 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, addr + 1);284 285 /* Check for overflow */286 do {287 count_tmp = count_h;288 count_l = fm10k_read_reg(hw, addr);289 count_h = fm10k_read_reg(hw, 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 value300 * @stat: pointer to the hardware statistic structure301 * @delta: value to be updated into the hardware statistic structure302 *303 * Function receives a value and determines if an update is required based on304 * a delta calculation. Only the base value will be updated.305 **/306static 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 counters321 * @hw: pointer to the hardware structure322 * @q: pointer to the ring of hardware statistics queue323 * @idx: index pointing to the start of the ring iteration324 *325 * Function updates the TX queue statistics counters that are related to the326 * hardware.327 **/328static 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 &q->tx_packets);342 343 if (tx_packets)344 tx_bytes = fm10k_read_hw_stats_48b(hw,345 FM10K_QBTC_L(idx),346 &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(&q->tx_bytes, tx_bytes);366 367 q->tx_stats_idx = id_tx;368}369 370/**371 * fm10k_update_hw_stats_rx_q - Updates RX queue statistics counters372 * @hw: pointer to the hardware structure373 * @q: pointer to the ring of hardware statistics queue374 * @idx: index pointing to the start of the ring iteration375 *376 * Function updates the RX queue statistics counters that are related to the377 * hardware.378 **/379static 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 &q->rx_drops);393 394 rx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPRC(idx),395 &q->rx_packets);396 397 if (rx_packets)398 rx_bytes = fm10k_read_hw_stats_48b(hw,399 FM10K_QBRC_L(idx),400 &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(&q->rx_bytes, rx_bytes);422 423 q->rx_stats_idx = id_rx;424}425 426/**427 * fm10k_update_hw_stats_q - Updates queue statistics counters428 * @hw: pointer to the hardware structure429 * @q: pointer to the ring of hardware statistics queue430 * @idx: index pointing to the start of the ring iteration431 * @count: number of queues to iterate over432 *433 * Function updates the queue statistics counters that are related to the434 * hardware.435 **/436void 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 queues449 * @q: pointer to the ring of hardware statistics queue450 * @idx: index pointing to the start of the ring iteration451 * @count: number of queues to iterate over452 *453 * Function invalidates the index values for the queues so any updates that454 * may have happened are ignored and the base for the queue stats is reset.455 **/456void 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 host468 * @hw: pointer to hardware structure469 * @host_ready: pointer to boolean value that will record host state470 *471 * This function will check the health of the mailbox and Tx queue 0472 * in order to determine if we should report that the link is up or not.473 **/474s32 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 no517 * longer need to check for link518 */519 mac->get_host_state = false;520 521out:522 *host_ready = !mac->get_host_state;523 return ret_val;524}525