Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright(c) 2013 - 2018 Intel Corporation. */
0003 
0004 #include "fm10k_common.h"
0005 
0006 /**
0007  *  fm10k_get_bus_info_generic - Generic set PCI bus info
0008  *  @hw: pointer to hardware structure
0009  *
0010  *  Gets the PCI bus info (speed, width, type) then calls helper function to
0011  *  store this data within the fm10k_hw structure.
0012  **/
0013 s32 fm10k_get_bus_info_generic(struct fm10k_hw *hw)
0014 {
0015     u16 link_cap, link_status, device_cap, device_control;
0016 
0017     /* Get the maximum link width and speed from PCIe config space */
0018     link_cap = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_LINK_CAP);
0019 
0020     switch (link_cap & FM10K_PCIE_LINK_WIDTH) {
0021     case FM10K_PCIE_LINK_WIDTH_1:
0022         hw->bus_caps.width = fm10k_bus_width_pcie_x1;
0023         break;
0024     case FM10K_PCIE_LINK_WIDTH_2:
0025         hw->bus_caps.width = fm10k_bus_width_pcie_x2;
0026         break;
0027     case FM10K_PCIE_LINK_WIDTH_4:
0028         hw->bus_caps.width = fm10k_bus_width_pcie_x4;
0029         break;
0030     case FM10K_PCIE_LINK_WIDTH_8:
0031         hw->bus_caps.width = fm10k_bus_width_pcie_x8;
0032         break;
0033     default:
0034         hw->bus_caps.width = fm10k_bus_width_unknown;
0035         break;
0036     }
0037 
0038     switch (link_cap & FM10K_PCIE_LINK_SPEED) {
0039     case FM10K_PCIE_LINK_SPEED_2500:
0040         hw->bus_caps.speed = fm10k_bus_speed_2500;
0041         break;
0042     case FM10K_PCIE_LINK_SPEED_5000:
0043         hw->bus_caps.speed = fm10k_bus_speed_5000;
0044         break;
0045     case FM10K_PCIE_LINK_SPEED_8000:
0046         hw->bus_caps.speed = fm10k_bus_speed_8000;
0047         break;
0048     default:
0049         hw->bus_caps.speed = fm10k_bus_speed_unknown;
0050         break;
0051     }
0052 
0053     /* Get the PCIe maximum payload size for the PCIe function */
0054     device_cap = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_DEV_CAP);
0055 
0056     switch (device_cap & FM10K_PCIE_DEV_CAP_PAYLOAD) {
0057     case FM10K_PCIE_DEV_CAP_PAYLOAD_128:
0058         hw->bus_caps.payload = fm10k_bus_payload_128;
0059         break;
0060     case FM10K_PCIE_DEV_CAP_PAYLOAD_256:
0061         hw->bus_caps.payload = fm10k_bus_payload_256;
0062         break;
0063     case FM10K_PCIE_DEV_CAP_PAYLOAD_512:
0064         hw->bus_caps.payload = fm10k_bus_payload_512;
0065         break;
0066     default:
0067         hw->bus_caps.payload = fm10k_bus_payload_unknown;
0068         break;
0069     }
0070 
0071     /* Get the negotiated link width and speed from PCIe config space */
0072     link_status = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_LINK_STATUS);
0073 
0074     switch (link_status & FM10K_PCIE_LINK_WIDTH) {
0075     case FM10K_PCIE_LINK_WIDTH_1:
0076         hw->bus.width = fm10k_bus_width_pcie_x1;
0077         break;
0078     case FM10K_PCIE_LINK_WIDTH_2:
0079         hw->bus.width = fm10k_bus_width_pcie_x2;
0080         break;
0081     case FM10K_PCIE_LINK_WIDTH_4:
0082         hw->bus.width = fm10k_bus_width_pcie_x4;
0083         break;
0084     case FM10K_PCIE_LINK_WIDTH_8:
0085         hw->bus.width = fm10k_bus_width_pcie_x8;
0086         break;
0087     default:
0088         hw->bus.width = fm10k_bus_width_unknown;
0089         break;
0090     }
0091 
0092     switch (link_status & FM10K_PCIE_LINK_SPEED) {
0093     case FM10K_PCIE_LINK_SPEED_2500:
0094         hw->bus.speed = fm10k_bus_speed_2500;
0095         break;
0096     case FM10K_PCIE_LINK_SPEED_5000:
0097         hw->bus.speed = fm10k_bus_speed_5000;
0098         break;
0099     case FM10K_PCIE_LINK_SPEED_8000:
0100         hw->bus.speed = fm10k_bus_speed_8000;
0101         break;
0102     default:
0103         hw->bus.speed = fm10k_bus_speed_unknown;
0104         break;
0105     }
0106 
0107     /* Get the negotiated PCIe maximum payload size for the PCIe function */
0108     device_control = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_DEV_CTRL);
0109 
0110     switch (device_control & FM10K_PCIE_DEV_CTRL_PAYLOAD) {
0111     case FM10K_PCIE_DEV_CTRL_PAYLOAD_128:
0112         hw->bus.payload = fm10k_bus_payload_128;
0113         break;
0114     case FM10K_PCIE_DEV_CTRL_PAYLOAD_256:
0115         hw->bus.payload = fm10k_bus_payload_256;
0116         break;
0117     case FM10K_PCIE_DEV_CTRL_PAYLOAD_512:
0118         hw->bus.payload = fm10k_bus_payload_512;
0119         break;
0120     default:
0121         hw->bus.payload = fm10k_bus_payload_unknown;
0122         break;
0123     }
0124 
0125     return 0;
0126 }
0127 
0128 static u16 fm10k_get_pcie_msix_count_generic(struct fm10k_hw *hw)
0129 {
0130     u16 msix_count;
0131 
0132     /* read in value from MSI-X capability register */
0133     msix_count = fm10k_read_pci_cfg_word(hw, FM10K_PCI_MSIX_MSG_CTRL);
0134     msix_count &= FM10K_PCI_MSIX_MSG_CTRL_TBL_SZ_MASK;
0135 
0136     /* MSI-X count is zero-based in HW */
0137     msix_count++;
0138 
0139     if (msix_count > FM10K_MAX_MSIX_VECTORS)
0140         msix_count = FM10K_MAX_MSIX_VECTORS;
0141 
0142     return msix_count;
0143 }
0144 
0145 /**
0146  *  fm10k_get_invariants_generic - Inits constant values
0147  *  @hw: pointer to the hardware structure
0148  *
0149  *  Initialize the common invariants for the device.
0150  **/
0151 s32 fm10k_get_invariants_generic(struct fm10k_hw *hw)
0152 {
0153     struct fm10k_mac_info *mac = &hw->mac;
0154 
0155     /* initialize GLORT state to avoid any false hits */
0156     mac->dglort_map = FM10K_DGLORTMAP_NONE;
0157 
0158     /* record maximum number of MSI-X vectors */
0159     mac->max_msix_vectors = fm10k_get_pcie_msix_count_generic(hw);
0160 
0161     return 0;
0162 }
0163 
0164 /**
0165  *  fm10k_start_hw_generic - Prepare hardware for Tx/Rx
0166  *  @hw: pointer to hardware structure
0167  *
0168  *  This function sets the Tx ready flag to indicate that the Tx path has
0169  *  been initialized.
0170  **/
0171 s32 fm10k_start_hw_generic(struct fm10k_hw *hw)
0172 {
0173     /* set flag indicating we are beginning Tx */
0174     hw->mac.tx_ready = true;
0175 
0176     return 0;
0177 }
0178 
0179 /**
0180  *  fm10k_disable_queues_generic - Stop Tx/Rx queues
0181  *  @hw: pointer to hardware structure
0182  *  @q_cnt: number of queues to be disabled
0183  *
0184  **/
0185 s32 fm10k_disable_queues_generic(struct fm10k_hw *hw, u16 q_cnt)
0186 {
0187     u32 reg;
0188     u16 i, time;
0189 
0190     /* clear tx_ready to prevent any false hits for reset */
0191     hw->mac.tx_ready = false;
0192 
0193     if (FM10K_REMOVED(hw->hw_addr))
0194         return 0;
0195 
0196     /* clear the enable bit for all rings */
0197     for (i = 0; i < q_cnt; i++) {
0198         reg = fm10k_read_reg(hw, FM10K_TXDCTL(i));
0199         fm10k_write_reg(hw, FM10K_TXDCTL(i),
0200                 reg & ~FM10K_TXDCTL_ENABLE);
0201         reg = fm10k_read_reg(hw, FM10K_RXQCTL(i));
0202         fm10k_write_reg(hw, FM10K_RXQCTL(i),
0203                 reg & ~FM10K_RXQCTL_ENABLE);
0204     }
0205 
0206     fm10k_write_flush(hw);
0207     udelay(1);
0208 
0209     /* loop through all queues to verify that they are all disabled */
0210     for (i = 0, time = FM10K_QUEUE_DISABLE_TIMEOUT; time;) {
0211         /* if we are at end of rings all rings are disabled */
0212         if (i == q_cnt)
0213             return 0;
0214 
0215         /* if queue enables cleared, then move to next ring pair */
0216         reg = fm10k_read_reg(hw, FM10K_TXDCTL(i));
0217         if (!~reg || !(reg & FM10K_TXDCTL_ENABLE)) {
0218             reg = fm10k_read_reg(hw, FM10K_RXQCTL(i));
0219             if (!~reg || !(reg & FM10K_RXQCTL_ENABLE)) {
0220                 i++;
0221                 continue;
0222             }
0223         }
0224 
0225         /* decrement time and wait 1 usec */
0226         time--;
0227         if (time)
0228             udelay(1);
0229     }
0230 
0231     return FM10K_ERR_REQUESTS_PENDING;
0232 }
0233 
0234 /**
0235  *  fm10k_stop_hw_generic - Stop Tx/Rx units
0236  *  @hw: pointer to hardware structure
0237  *
0238  **/
0239 s32 fm10k_stop_hw_generic(struct fm10k_hw *hw)
0240 {
0241     return fm10k_disable_queues_generic(hw, hw->mac.max_queues);
0242 }
0243 
0244 /**
0245  *  fm10k_read_hw_stats_32b - Reads value of 32-bit registers
0246  *  @hw: pointer to the hardware structure
0247  *  @addr: address of register containing a 32-bit value
0248  *  @stat: pointer to structure holding hw stat information
0249  *
0250  *  Function reads the content of the register and returns the delta
0251  *  between the base and the current value.
0252  *  **/
0253 u32 fm10k_read_hw_stats_32b(struct fm10k_hw *hw, u32 addr,
0254                 struct fm10k_hw_stat *stat)
0255 {
0256     u32 delta = fm10k_read_reg(hw, addr) - stat->base_l;
0257 
0258     if (FM10K_REMOVED(hw->hw_addr))
0259         stat->base_h = 0;
0260 
0261     return delta;
0262 }
0263 
0264 /**
0265  *  fm10k_read_hw_stats_48b - Reads value of 48-bit registers
0266  *  @hw: pointer to the hardware structure
0267  *  @addr: address of register containing the lower 32-bit value
0268  *  @stat: pointer to structure holding hw stat information
0269  *
0270  *  Function reads the content of 2 registers, combined to represent a 48-bit
0271  *  statistical value. Extra processing is required to handle overflowing.
0272  *  Finally, a delta value is returned representing the difference between the
0273  *  values stored in registers and values stored in the statistic counters.
0274  *  **/
0275 static u64 fm10k_read_hw_stats_48b(struct fm10k_hw *hw, u32 addr,
0276                    struct fm10k_hw_stat *stat)
0277 {
0278     u32 count_l;
0279     u32 count_h;
0280     u32 count_tmp;
0281     u64 delta;
0282 
0283     count_h = fm10k_read_reg(hw, addr + 1);
0284 
0285     /* Check for overflow */
0286     do {
0287         count_tmp = count_h;
0288         count_l = fm10k_read_reg(hw, addr);
0289         count_h = fm10k_read_reg(hw, addr + 1);
0290     } while (count_h != count_tmp);
0291 
0292     delta = ((u64)(count_h - stat->base_h) << 32) + count_l;
0293     delta -= stat->base_l;
0294 
0295     return delta & FM10K_48_BIT_MASK;
0296 }
0297 
0298 /**
0299  *  fm10k_update_hw_base_48b - Updates 48-bit statistic base value
0300  *  @stat: pointer to the hardware statistic structure
0301  *  @delta: value to be updated into the hardware statistic structure
0302  *
0303  *  Function receives a value and determines if an update is required based on
0304  *  a delta calculation. Only the base value will be updated.
0305  **/
0306 static void fm10k_update_hw_base_48b(struct fm10k_hw_stat *stat, u64 delta)
0307 {
0308     if (!delta)
0309         return;
0310 
0311     /* update lower 32 bits */
0312     delta += stat->base_l;
0313     stat->base_l = (u32)delta;
0314 
0315     /* update upper 32 bits */
0316     stat->base_h += (u32)(delta >> 32);
0317 }
0318 
0319 /**
0320  *  fm10k_update_hw_stats_tx_q - Updates TX queue statistics counters
0321  *  @hw: pointer to the hardware structure
0322  *  @q: pointer to the ring of hardware statistics queue
0323  *  @idx: index pointing to the start of the ring iteration
0324  *
0325  *  Function updates the TX queue statistics counters that are related to the
0326  *  hardware.
0327  **/
0328 static void fm10k_update_hw_stats_tx_q(struct fm10k_hw *hw,
0329                        struct fm10k_hw_stats_q *q,
0330                        u32 idx)
0331 {
0332     u32 id_tx, id_tx_prev, tx_packets;
0333     u64 tx_bytes = 0;
0334 
0335     /* Retrieve TX Owner Data */
0336     id_tx = fm10k_read_reg(hw, FM10K_TXQCTL(idx));
0337 
0338     /* Process TX Ring */
0339     do {
0340         tx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPTC(idx),
0341                              &q->tx_packets);
0342 
0343         if (tx_packets)
0344             tx_bytes = fm10k_read_hw_stats_48b(hw,
0345                                FM10K_QBTC_L(idx),
0346                                &q->tx_bytes);
0347 
0348         /* Re-Check Owner Data */
0349         id_tx_prev = id_tx;
0350         id_tx = fm10k_read_reg(hw, FM10K_TXQCTL(idx));
0351     } while ((id_tx ^ id_tx_prev) & FM10K_TXQCTL_ID_MASK);
0352 
0353     /* drop non-ID bits and set VALID ID bit */
0354     id_tx &= FM10K_TXQCTL_ID_MASK;
0355     id_tx |= FM10K_STAT_VALID;
0356 
0357     /* update packet counts */
0358     if (q->tx_stats_idx == id_tx) {
0359         q->tx_packets.count += tx_packets;
0360         q->tx_bytes.count += tx_bytes;
0361     }
0362 
0363     /* update bases and record ID */
0364     fm10k_update_hw_base_32b(&q->tx_packets, tx_packets);
0365     fm10k_update_hw_base_48b(&q->tx_bytes, tx_bytes);
0366 
0367     q->tx_stats_idx = id_tx;
0368 }
0369 
0370 /**
0371  *  fm10k_update_hw_stats_rx_q - Updates RX queue statistics counters
0372  *  @hw: pointer to the hardware structure
0373  *  @q: pointer to the ring of hardware statistics queue
0374  *  @idx: index pointing to the start of the ring iteration
0375  *
0376  *  Function updates the RX queue statistics counters that are related to the
0377  *  hardware.
0378  **/
0379 static void fm10k_update_hw_stats_rx_q(struct fm10k_hw *hw,
0380                        struct fm10k_hw_stats_q *q,
0381                        u32 idx)
0382 {
0383     u32 id_rx, id_rx_prev, rx_packets, rx_drops;
0384     u64 rx_bytes = 0;
0385 
0386     /* Retrieve RX Owner Data */
0387     id_rx = fm10k_read_reg(hw, FM10K_RXQCTL(idx));
0388 
0389     /* Process RX Ring */
0390     do {
0391         rx_drops = fm10k_read_hw_stats_32b(hw, FM10K_QPRDC(idx),
0392                            &q->rx_drops);
0393 
0394         rx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPRC(idx),
0395                              &q->rx_packets);
0396 
0397         if (rx_packets)
0398             rx_bytes = fm10k_read_hw_stats_48b(hw,
0399                                FM10K_QBRC_L(idx),
0400                                &q->rx_bytes);
0401 
0402         /* Re-Check Owner Data */
0403         id_rx_prev = id_rx;
0404         id_rx = fm10k_read_reg(hw, FM10K_RXQCTL(idx));
0405     } while ((id_rx ^ id_rx_prev) & FM10K_RXQCTL_ID_MASK);
0406 
0407     /* drop non-ID bits and set VALID ID bit */
0408     id_rx &= FM10K_RXQCTL_ID_MASK;
0409     id_rx |= FM10K_STAT_VALID;
0410 
0411     /* update packet counts */
0412     if (q->rx_stats_idx == id_rx) {
0413         q->rx_drops.count += rx_drops;
0414         q->rx_packets.count += rx_packets;
0415         q->rx_bytes.count += rx_bytes;
0416     }
0417 
0418     /* update bases and record ID */
0419     fm10k_update_hw_base_32b(&q->rx_drops, rx_drops);
0420     fm10k_update_hw_base_32b(&q->rx_packets, rx_packets);
0421     fm10k_update_hw_base_48b(&q->rx_bytes, rx_bytes);
0422 
0423     q->rx_stats_idx = id_rx;
0424 }
0425 
0426 /**
0427  *  fm10k_update_hw_stats_q - Updates queue statistics counters
0428  *  @hw: pointer to the hardware structure
0429  *  @q: pointer to the ring of hardware statistics queue
0430  *  @idx: index pointing to the start of the ring iteration
0431  *  @count: number of queues to iterate over
0432  *
0433  *  Function updates the queue statistics counters that are related to the
0434  *  hardware.
0435  **/
0436 void fm10k_update_hw_stats_q(struct fm10k_hw *hw, struct fm10k_hw_stats_q *q,
0437                  u32 idx, u32 count)
0438 {
0439     u32 i;
0440 
0441     for (i = 0; i < count; i++, idx++, q++) {
0442         fm10k_update_hw_stats_tx_q(hw, q, idx);
0443         fm10k_update_hw_stats_rx_q(hw, q, idx);
0444     }
0445 }
0446 
0447 /**
0448  *  fm10k_unbind_hw_stats_q - Unbind the queue counters from their queues
0449  *  @q: pointer to the ring of hardware statistics queue
0450  *  @idx: index pointing to the start of the ring iteration
0451  *  @count: number of queues to iterate over
0452  *
0453  *  Function invalidates the index values for the queues so any updates that
0454  *  may have happened are ignored and the base for the queue stats is reset.
0455  **/
0456 void fm10k_unbind_hw_stats_q(struct fm10k_hw_stats_q *q, u32 idx, u32 count)
0457 {
0458     u32 i;
0459 
0460     for (i = 0; i < count; i++, idx++, q++) {
0461         q->rx_stats_idx = 0;
0462         q->tx_stats_idx = 0;
0463     }
0464 }
0465 
0466 /**
0467  *  fm10k_get_host_state_generic - Returns the state of the host
0468  *  @hw: pointer to hardware structure
0469  *  @host_ready: pointer to boolean value that will record host state
0470  *
0471  *  This function will check the health of the mailbox and Tx queue 0
0472  *  in order to determine if we should report that the link is up or not.
0473  **/
0474 s32 fm10k_get_host_state_generic(struct fm10k_hw *hw, bool *host_ready)
0475 {
0476     struct fm10k_mbx_info *mbx = &hw->mbx;
0477     struct fm10k_mac_info *mac = &hw->mac;
0478     s32 ret_val = 0;
0479     u32 txdctl = fm10k_read_reg(hw, FM10K_TXDCTL(0));
0480 
0481     /* process upstream mailbox in case interrupts were disabled */
0482     mbx->ops.process(hw, mbx);
0483 
0484     /* If Tx is no longer enabled link should come down */
0485     if (!(~txdctl) || !(txdctl & FM10K_TXDCTL_ENABLE))
0486         mac->get_host_state = true;
0487 
0488     /* exit if not checking for link, or link cannot be changed */
0489     if (!mac->get_host_state || !(~txdctl))
0490         goto out;
0491 
0492     /* if we somehow dropped the Tx enable we should reset */
0493     if (mac->tx_ready && !(txdctl & FM10K_TXDCTL_ENABLE)) {
0494         ret_val = FM10K_ERR_RESET_REQUESTED;
0495         goto out;
0496     }
0497 
0498     /* if Mailbox timed out we should request reset */
0499     if (!mbx->timeout) {
0500         ret_val = FM10K_ERR_RESET_REQUESTED;
0501         goto out;
0502     }
0503 
0504     /* verify Mailbox is still open */
0505     if (mbx->state != FM10K_STATE_OPEN)
0506         goto out;
0507 
0508     /* interface cannot receive traffic without logical ports */
0509     if (mac->dglort_map == FM10K_DGLORTMAP_NONE) {
0510         if (mac->ops.request_lport_map)
0511             ret_val = mac->ops.request_lport_map(hw);
0512 
0513         goto out;
0514     }
0515 
0516     /* if we passed all the tests above then the switch is ready and we no
0517      * longer need to check for link
0518      */
0519     mac->get_host_state = false;
0520 
0521 out:
0522     *host_ready = !mac->get_host_state;
0523     return ret_val;
0524 }