diff options
-rw-r--r-- | sys/dev/pci/if_ice.c | 310 | ||||
-rw-r--r-- | sys/dev/pci/if_icevar.h | 79 |
2 files changed, 385 insertions, 4 deletions
diff --git a/sys/dev/pci/if_ice.c b/sys/dev/pci/if_ice.c index aab1769d504..15855060b4b 100644 --- a/sys/dev/pci/if_ice.c +++ b/sys/dev/pci/if_ice.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_ice.c,v 1.10 2024/11/19 09:39:57 stsp Exp $ */ +/* $OpenBSD: if_ice.c,v 1.11 2024/11/19 09:41:32 stsp Exp $ */ /* Copyright (c) 2024, Intel Corporation * All rights reserved. @@ -180,6 +180,9 @@ uint32_t ice_debug = 0xffffffff & ~(ICE_DBG_AQ); #define ICE_READ(hw, reg) \ bus_space_read_4((hw)->hw_sc->sc_st, (hw)->hw_sc->sc_sh, (reg)) +#define ICE_READ_8(hw, reg) \ + bus_space_read_8((hw)->hw_sc->sc_st, (hw)->hw_sc->sc_sh, (reg)) + #define ICE_WRITE(hw, reg, val) \ bus_space_write_4((hw)->hw_sc->sc_st, (hw)->hw_sc->sc_sh, (reg), (val)) @@ -315,6 +318,10 @@ struct ice_softc { struct ice_resmgr tx_qmgr; struct ice_resmgr rx_qmgr; + /* device statistics */ + struct ice_pf_hw_stats stats; + struct ice_pf_sw_stats soft_stats; + struct ice_vsi **all_vsi; /* Array of VSI pointers */ uint16_t num_available_vsi; /* Size of VSI array */ @@ -17772,11 +17779,9 @@ ice_clean_all_vsi_rss_cfg(struct ice_softc *sc) void ice_reset_pf_stats(struct ice_softc *sc) { -#if 0 memset(&sc->stats.prev, 0, sizeof(sc->stats.prev)); memset(&sc->stats.cur, 0, sizeof(sc->stats.cur)); sc->stats.offsets_loaded = false; -#endif } /** @@ -22790,6 +22795,302 @@ ice_poll_for_media_avail(struct ice_softc *sc) } /** + * ice_stat_update40 - read 40 bit stat from the chip and update stat values + * @hw: ptr to the hardware info + * @reg: offset of 64 bit HW register to read from + * @prev_stat_loaded: bool to specify if previous stats are loaded + * @prev_stat: ptr to previous loaded stat value + * @cur_stat: ptr to current stat value + */ +void +ice_stat_update40(struct ice_hw *hw, uint32_t reg, bool prev_stat_loaded, + uint64_t *prev_stat, uint64_t *cur_stat) +{ + uint64_t new_data = ICE_READ_8(hw, reg) & (BIT_ULL(40) - 1); + + /* + * Device stats are not reset at PFR, they likely will not be zeroed + * when the driver starts. Thus, save the value from the first read + * without adding to the statistic value so that we report stats which + * count up from zero. + */ + if (!prev_stat_loaded) { + *prev_stat = new_data; + return; + } + + /* + * Calculate the difference between the new and old values, and then + * add it to the software stat value. + */ + if (new_data >= *prev_stat) + *cur_stat += new_data - *prev_stat; + else + /* to manage the potential roll-over */ + *cur_stat += (new_data + BIT_ULL(40)) - *prev_stat; + + /* Update the previously stored value to prepare for next read */ + *prev_stat = new_data; +} + +/** + * ice_stat_update32 - read 32 bit stat from the chip and update stat values + * @hw: ptr to the hardware info + * @reg: offset of HW register to read from + * @prev_stat_loaded: bool to specify if previous stats are loaded + * @prev_stat: ptr to previous loaded stat value + * @cur_stat: ptr to current stat value + */ +void +ice_stat_update32(struct ice_hw *hw, uint32_t reg, bool prev_stat_loaded, + uint64_t *prev_stat, uint64_t *cur_stat) +{ + uint32_t new_data; + + new_data = ICE_READ(hw, reg); + + /* + * Device stats are not reset at PFR, they likely will not be zeroed + * when the driver starts. Thus, save the value from the first read + * without adding to the statistic value so that we report stats which + * count up from zero. + */ + if (!prev_stat_loaded) { + *prev_stat = new_data; + return; + } + + /* + * Calculate the difference between the new and old values, and then + * add it to the software stat value. + */ + if (new_data >= *prev_stat) + *cur_stat += new_data - *prev_stat; + else + /* to manage the potential roll-over */ + *cur_stat += (new_data + BIT_ULL(32)) - *prev_stat; + + /* Update the previously stored value to prepare for next read */ + *prev_stat = new_data; +} + +/** + * ice_stat_update_repc - read GLV_REPC stats from chip and update stat values + * @hw: ptr to the hardware info + * @vsi_handle: VSI handle + * @prev_stat_loaded: bool to specify if the previous stat values are loaded + * @cur_stats: ptr to current stats structure + * + * The GLV_REPC statistic register actually tracks two 16bit statistics, and + * thus cannot be read using the normal ice_stat_update32 function. + * + * Read the GLV_REPC register associated with the given VSI, and update the + * rx_no_desc and rx_error values in the ice_eth_stats structure. + * + * Because the statistics in GLV_REPC stick at 0xFFFF, the register must be + * cleared each time it's read. + * + * Note that the GLV_RDPC register also counts the causes that would trigger + * GLV_REPC. However, it does not give the finer grained detail about why the + * packets are being dropped. The GLV_REPC values can be used to distinguish + * whether Rx packets are dropped due to errors or due to no available + * descriptors. + */ +void +ice_stat_update_repc(struct ice_hw *hw, uint16_t vsi_handle, + bool prev_stat_loaded, struct ice_eth_stats *cur_stats) +{ + uint16_t vsi_num, no_desc, error_cnt; + uint32_t repc; + + if (!ice_is_vsi_valid(hw, vsi_handle)) + return; + + vsi_num = hw->vsi_ctx[vsi_handle]->vsi_num; + + /* If we haven't loaded stats yet, just clear the current value */ + if (!prev_stat_loaded) { + ICE_WRITE(hw, GLV_REPC(vsi_num), 0); + return; + } + + repc = ICE_READ(hw, GLV_REPC(vsi_num)); + no_desc = (repc & GLV_REPC_NO_DESC_CNT_M) >> GLV_REPC_NO_DESC_CNT_S; + error_cnt = (repc & GLV_REPC_ERROR_CNT_M) >> GLV_REPC_ERROR_CNT_S; + + /* Clear the count by writing to the stats register */ + ICE_WRITE(hw, GLV_REPC(vsi_num), 0); + + cur_stats->rx_no_desc += no_desc; + cur_stats->rx_errors += error_cnt; +} + +/** + * ice_update_pf_stats - Update port stats counters + * @sc: device private softc structure + * + * Reads hardware statistics registers and updates the software tracking + * structure with new values. + */ +void +ice_update_pf_stats(struct ice_softc *sc) +{ + struct ice_hw_port_stats *prev_ps, *cur_ps; + struct ice_hw *hw = &sc->hw; + uint8_t lport; + + KASSERT(hw->port_info); + + prev_ps = &sc->stats.prev; + cur_ps = &sc->stats.cur; + lport = hw->port_info->lport; + +#define ICE_PF_STAT_PFC(name, location, index) \ + ice_stat_update40(hw, name(lport, index), \ + sc->stats.offsets_loaded, \ + &prev_ps->location[index], &cur_ps->location[index]) + +#define ICE_PF_STAT40(name, location) \ + ice_stat_update40(hw, name ## L(lport), \ + sc->stats.offsets_loaded, \ + &prev_ps->location, &cur_ps->location) + +#define ICE_PF_STAT32(name, location) \ + ice_stat_update32(hw, name(lport), \ + sc->stats.offsets_loaded, \ + &prev_ps->location, &cur_ps->location) + + ICE_PF_STAT40(GLPRT_GORC, eth.rx_bytes); + ICE_PF_STAT40(GLPRT_UPRC, eth.rx_unicast); + ICE_PF_STAT40(GLPRT_MPRC, eth.rx_multicast); + ICE_PF_STAT40(GLPRT_BPRC, eth.rx_broadcast); + ICE_PF_STAT40(GLPRT_GOTC, eth.tx_bytes); + ICE_PF_STAT40(GLPRT_UPTC, eth.tx_unicast); + ICE_PF_STAT40(GLPRT_MPTC, eth.tx_multicast); + ICE_PF_STAT40(GLPRT_BPTC, eth.tx_broadcast); + /* This stat register doesn't have an lport */ + ice_stat_update32(hw, PRTRPB_RDPC, + sc->stats.offsets_loaded, + &prev_ps->eth.rx_discards, &cur_ps->eth.rx_discards); + + ICE_PF_STAT32(GLPRT_TDOLD, tx_dropped_link_down); + ICE_PF_STAT40(GLPRT_PRC64, rx_size_64); + ICE_PF_STAT40(GLPRT_PRC127, rx_size_127); + ICE_PF_STAT40(GLPRT_PRC255, rx_size_255); + ICE_PF_STAT40(GLPRT_PRC511, rx_size_511); + ICE_PF_STAT40(GLPRT_PRC1023, rx_size_1023); + ICE_PF_STAT40(GLPRT_PRC1522, rx_size_1522); + ICE_PF_STAT40(GLPRT_PRC9522, rx_size_big); + ICE_PF_STAT40(GLPRT_PTC64, tx_size_64); + ICE_PF_STAT40(GLPRT_PTC127, tx_size_127); + ICE_PF_STAT40(GLPRT_PTC255, tx_size_255); + ICE_PF_STAT40(GLPRT_PTC511, tx_size_511); + ICE_PF_STAT40(GLPRT_PTC1023, tx_size_1023); + ICE_PF_STAT40(GLPRT_PTC1522, tx_size_1522); + ICE_PF_STAT40(GLPRT_PTC9522, tx_size_big); + + /* Update Priority Flow Control Stats */ + for (int i = 0; i <= GLPRT_PXOFFRXC_MAX_INDEX; i++) { + ICE_PF_STAT_PFC(GLPRT_PXONRXC, priority_xon_rx, i); + ICE_PF_STAT_PFC(GLPRT_PXOFFRXC, priority_xoff_rx, i); + ICE_PF_STAT_PFC(GLPRT_PXONTXC, priority_xon_tx, i); + ICE_PF_STAT_PFC(GLPRT_PXOFFTXC, priority_xoff_tx, i); + ICE_PF_STAT_PFC(GLPRT_RXON2OFFCNT, priority_xon_2_xoff, i); + } + + ICE_PF_STAT32(GLPRT_LXONRXC, link_xon_rx); + ICE_PF_STAT32(GLPRT_LXOFFRXC, link_xoff_rx); + ICE_PF_STAT32(GLPRT_LXONTXC, link_xon_tx); + ICE_PF_STAT32(GLPRT_LXOFFTXC, link_xoff_tx); + ICE_PF_STAT32(GLPRT_CRCERRS, crc_errors); + ICE_PF_STAT32(GLPRT_ILLERRC, illegal_bytes); + ICE_PF_STAT32(GLPRT_MLFC, mac_local_faults); + ICE_PF_STAT32(GLPRT_MRFC, mac_remote_faults); + ICE_PF_STAT32(GLPRT_RLEC, rx_len_errors); + ICE_PF_STAT32(GLPRT_RUC, rx_undersize); + ICE_PF_STAT32(GLPRT_RFC, rx_fragments); + ICE_PF_STAT32(GLPRT_ROC, rx_oversize); + ICE_PF_STAT32(GLPRT_RJC, rx_jabber); + +#undef ICE_PF_STAT40 +#undef ICE_PF_STAT32 +#undef ICE_PF_STAT_PFC + + sc->stats.offsets_loaded = true; +} + +/** + * ice_update_vsi_hw_stats - Update VSI-specific ethernet statistics counters + * @vsi: the VSI to be updated + * + * Reads hardware stats and updates the ice_vsi_hw_stats tracking structure with + * the updated values. + */ +void +ice_update_vsi_hw_stats(struct ice_vsi *vsi) +{ + struct ice_eth_stats *prev_es, *cur_es; + struct ice_hw *hw = &vsi->sc->hw; + uint16_t vsi_num; + + if (!ice_is_vsi_valid(hw, vsi->idx)) + return; + + /* HW absolute index of a VSI */ + vsi_num = hw->vsi_ctx[vsi->idx]->vsi_num; + prev_es = &vsi->hw_stats.prev; + cur_es = &vsi->hw_stats.cur; + +#define ICE_VSI_STAT40(name, location) \ + ice_stat_update40(hw, name ## L(vsi_num), \ + vsi->hw_stats.offsets_loaded, \ + &prev_es->location, &cur_es->location) + +#define ICE_VSI_STAT32(name, location) \ + ice_stat_update32(hw, name(vsi_num), \ + vsi->hw_stats.offsets_loaded, \ + &prev_es->location, &cur_es->location) + + ICE_VSI_STAT40(GLV_GORC, rx_bytes); + ICE_VSI_STAT40(GLV_UPRC, rx_unicast); + ICE_VSI_STAT40(GLV_MPRC, rx_multicast); + ICE_VSI_STAT40(GLV_BPRC, rx_broadcast); + ICE_VSI_STAT32(GLV_RDPC, rx_discards); + ICE_VSI_STAT40(GLV_GOTC, tx_bytes); + ICE_VSI_STAT40(GLV_UPTC, tx_unicast); + ICE_VSI_STAT40(GLV_MPTC, tx_multicast); + ICE_VSI_STAT40(GLV_BPTC, tx_broadcast); + ICE_VSI_STAT32(GLV_TEPC, tx_errors); + + ice_stat_update_repc(hw, vsi->idx, vsi->hw_stats.offsets_loaded, + cur_es); + +#undef ICE_VSI_STAT40 +#undef ICE_VSI_STAT32 + + vsi->hw_stats.offsets_loaded = true; +} + +void +ice_update_stats(struct ice_softc *sc) +{ + /* Do not attempt to update stats when in recovery mode */ + if (ice_test_state(&sc->state, ICE_STATE_RECOVERY_MODE)) + return; + + /* Update device statistics */ + ice_update_pf_stats(sc); + + /* Update the primary VSI stats */ + ice_update_vsi_hw_stats(&sc->pf_vsi); +#if 0 + /* Update mirror VSI stats */ + if (sc->mirr_if && sc->mirr_if->if_attached) + ice_update_vsi_hw_stats(sc->mirr_if->vsi); +#endif +} + +/** * ice_if_update_admin_status - update admin status * @ctx: iflib ctx structure * @@ -22872,6 +23173,9 @@ ice_if_update_admin_status(void *arg) /* Check and update link status */ ice_update_link_status(sc, false); + /* Update statistics. */ + ice_update_stats(sc); + /* * If there are still messages to process, we need to reschedule * ourselves. Otherwise, we can just re-enable the interrupt. We'll be diff --git a/sys/dev/pci/if_icevar.h b/sys/dev/pci/if_icevar.h index 1a59040aa72..28725a5ac32 100644 --- a/sys/dev/pci/if_icevar.h +++ b/sys/dev/pci/if_icevar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_icevar.h,v 1.2 2024/11/15 15:41:10 stsp Exp $ */ +/* $OpenBSD: if_icevar.h,v 1.3 2024/11/19 09:41:32 stsp Exp $ */ /* Copyright (c) 2024, Intel Corporation * All rights reserved. @@ -4133,6 +4133,83 @@ struct ice_vsi_hw_stats { bool offsets_loaded; }; +/* Statistics collected by the MAC */ +struct ice_hw_port_stats { + /* eth stats collected by the port */ + struct ice_eth_stats eth; + /* additional port specific stats */ + uint64_t tx_dropped_link_down; /* tdold */ + uint64_t crc_errors; /* crcerrs */ + uint64_t illegal_bytes; /* illerrc */ + uint64_t error_bytes; /* errbc */ + uint64_t mac_local_faults; /* mlfc */ + uint64_t mac_remote_faults; /* mrfc */ + uint64_t rx_len_errors; /* rlec */ + uint64_t link_xon_rx; /* lxonrxc */ + uint64_t link_xoff_rx; /* lxoffrxc */ + uint64_t link_xon_tx; /* lxontxc */ + uint64_t link_xoff_tx; /* lxofftxc */ + uint64_t priority_xon_rx[8]; /* pxonrxc[8] */ + uint64_t priority_xoff_rx[8]; /* pxoffrxc[8] */ + uint64_t priority_xon_tx[8]; /* pxontxc[8] */ + uint64_t priority_xoff_tx[8]; /* pxofftxc[8] */ + uint64_t priority_xon_2_xoff[8];/* pxon2offc[8] */ + uint64_t rx_size_64; /* prc64 */ + uint64_t rx_size_127; /* prc127 */ + uint64_t rx_size_255; /* prc255 */ + uint64_t rx_size_511; /* prc511 */ + uint64_t rx_size_1023; /* prc1023 */ + uint64_t rx_size_1522; /* prc1522 */ + uint64_t rx_size_big; /* prc9522 */ + uint64_t rx_undersize; /* ruc */ + uint64_t rx_fragments; /* rfc */ + uint64_t rx_oversize; /* roc */ + uint64_t rx_jabber; /* rjc */ + uint64_t tx_size_64; /* ptc64 */ + uint64_t tx_size_127; /* ptc127 */ + uint64_t tx_size_255; /* ptc255 */ + uint64_t tx_size_511; /* ptc511 */ + uint64_t tx_size_1023; /* ptc1023 */ + uint64_t tx_size_1522; /* ptc1522 */ + uint64_t tx_size_big; /* ptc9522 */ + uint64_t mac_short_pkt_dropped; /* mspdc */ + /* EEE LPI */ + uint32_t tx_lpi_status; + uint32_t rx_lpi_status; + uint64_t tx_lpi_count; /* etlpic */ + uint64_t rx_lpi_count; /* erlpic */ +}; + +/** + * @struct ice_pf_hw_stats + * @brief hardware statistics for a PF + * + * Stores statistics that are generated by hardware for each PF. + */ +struct ice_pf_hw_stats { + struct ice_hw_port_stats prev; + struct ice_hw_port_stats cur; + bool offsets_loaded; +}; + +/** + * @struct ice_pf_sw_stats + * @brief software statistics for a PF + * + * Contains software generated statistics relevant to a PF. + */ +struct ice_pf_sw_stats { + /* # of reset events handled, by type */ + uint32_t corer_count; + uint32_t globr_count; + uint32_t empr_count; + uint32_t pfr_count; + + /* # of detected MDD events for Tx and Rx */ + uint32_t tx_mdd_count; + uint32_t rx_mdd_count; +}; + struct ice_tx_map { struct mbuf *txm_m; bus_dmamap_t txm_map; |