1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */ 3 4 #include "fbnic.h" 5 6 static void fbnic_hw_stat_rst32(struct fbnic_dev *fbd, u32 reg, 7 struct fbnic_stat_counter *stat) 8 { 9 /* We do not touch the "value" field here. 10 * It gets zeroed out on fbd structure allocation. 11 * After that we want it to grow continuously 12 * through device resets and power state changes. 13 */ 14 stat->u.old_reg_value_32 = rd32(fbd, reg); 15 } 16 17 static void fbnic_hw_stat_rd32(struct fbnic_dev *fbd, u32 reg, 18 struct fbnic_stat_counter *stat) 19 { 20 u32 new_reg_value; 21 22 new_reg_value = rd32(fbd, reg); 23 stat->value += new_reg_value - stat->u.old_reg_value_32; 24 stat->u.old_reg_value_32 = new_reg_value; 25 } 26 27 u64 fbnic_stat_rd64(struct fbnic_dev *fbd, u32 reg, u32 offset) 28 { 29 u32 prev_upper, upper, lower, diff; 30 31 prev_upper = rd32(fbd, reg + offset); 32 lower = rd32(fbd, reg); 33 upper = rd32(fbd, reg + offset); 34 35 diff = upper - prev_upper; 36 if (!diff) 37 return ((u64)upper << 32) | lower; 38 39 if (diff > 1) 40 dev_warn_once(fbd->dev, 41 "Stats inconsistent, upper 32b of %#010x updating too quickly\n", 42 reg * 4); 43 44 /* Return only the upper bits as we cannot guarantee 45 * the accuracy of the lower bits. We will add them in 46 * when the counter slows down enough that we can get 47 * a snapshot with both upper values being the same 48 * between reads. 49 */ 50 return ((u64)upper << 32); 51 } 52 53 static void fbnic_hw_stat_rst64(struct fbnic_dev *fbd, u32 reg, s32 offset, 54 struct fbnic_stat_counter *stat) 55 { 56 /* Record initial counter values and compute deltas from there to ensure 57 * stats start at 0 after reboot/reset. This avoids exposing absolute 58 * hardware counter values to userspace. 59 */ 60 stat->u.old_reg_value_64 = fbnic_stat_rd64(fbd, reg, offset); 61 } 62 63 static void fbnic_hw_stat_rd64(struct fbnic_dev *fbd, u32 reg, s32 offset, 64 struct fbnic_stat_counter *stat) 65 { 66 u64 new_reg_value; 67 68 new_reg_value = fbnic_stat_rd64(fbd, reg, offset); 69 stat->value += new_reg_value - stat->u.old_reg_value_64; 70 stat->u.old_reg_value_64 = new_reg_value; 71 } 72 73 static void fbnic_reset_rpc_stats(struct fbnic_dev *fbd, 74 struct fbnic_rpc_stats *rpc) 75 { 76 fbnic_hw_stat_rst32(fbd, 77 FBNIC_RPC_CNTR_UNKN_ETYPE, 78 &rpc->unkn_etype); 79 fbnic_hw_stat_rst32(fbd, 80 FBNIC_RPC_CNTR_UNKN_EXT_HDR, 81 &rpc->unkn_ext_hdr); 82 fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV4_FRAG, &rpc->ipv4_frag); 83 fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV6_FRAG, &rpc->ipv6_frag); 84 fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV4_ESP, &rpc->ipv4_esp); 85 fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV6_ESP, &rpc->ipv6_esp); 86 fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_TCP_OPT_ERR, &rpc->tcp_opt_err); 87 fbnic_hw_stat_rst32(fbd, 88 FBNIC_RPC_CNTR_OUT_OF_HDR_ERR, 89 &rpc->out_of_hdr_err); 90 fbnic_hw_stat_rst32(fbd, 91 FBNIC_RPC_CNTR_OVR_SIZE_ERR, 92 &rpc->ovr_size_err); 93 } 94 95 static void fbnic_get_rpc_stats32(struct fbnic_dev *fbd, 96 struct fbnic_rpc_stats *rpc) 97 { 98 fbnic_hw_stat_rd32(fbd, 99 FBNIC_RPC_CNTR_UNKN_ETYPE, 100 &rpc->unkn_etype); 101 fbnic_hw_stat_rd32(fbd, 102 FBNIC_RPC_CNTR_UNKN_EXT_HDR, 103 &rpc->unkn_ext_hdr); 104 105 fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV4_FRAG, &rpc->ipv4_frag); 106 fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV6_FRAG, &rpc->ipv6_frag); 107 108 fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV4_ESP, &rpc->ipv4_esp); 109 fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV6_ESP, &rpc->ipv6_esp); 110 111 fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_TCP_OPT_ERR, &rpc->tcp_opt_err); 112 fbnic_hw_stat_rd32(fbd, 113 FBNIC_RPC_CNTR_OUT_OF_HDR_ERR, 114 &rpc->out_of_hdr_err); 115 fbnic_hw_stat_rd32(fbd, 116 FBNIC_RPC_CNTR_OVR_SIZE_ERR, 117 &rpc->ovr_size_err); 118 } 119 120 static void fbnic_reset_pcie_stats_asic(struct fbnic_dev *fbd, 121 struct fbnic_pcie_stats *pcie) 122 { 123 fbnic_hw_stat_rst64(fbd, 124 FBNIC_PUL_USER_OB_RD_TLP_CNT_31_0, 125 1, 126 &pcie->ob_rd_tlp); 127 fbnic_hw_stat_rst64(fbd, 128 FBNIC_PUL_USER_OB_RD_DWORD_CNT_31_0, 129 1, 130 &pcie->ob_rd_dword); 131 fbnic_hw_stat_rst64(fbd, 132 FBNIC_PUL_USER_OB_CPL_TLP_CNT_31_0, 133 1, 134 &pcie->ob_cpl_tlp); 135 fbnic_hw_stat_rst64(fbd, 136 FBNIC_PUL_USER_OB_CPL_DWORD_CNT_31_0, 137 1, 138 &pcie->ob_cpl_dword); 139 fbnic_hw_stat_rst64(fbd, 140 FBNIC_PUL_USER_OB_WR_TLP_CNT_31_0, 141 1, 142 &pcie->ob_wr_tlp); 143 fbnic_hw_stat_rst64(fbd, 144 FBNIC_PUL_USER_OB_WR_DWORD_CNT_31_0, 145 1, 146 &pcie->ob_wr_dword); 147 148 fbnic_hw_stat_rst64(fbd, 149 FBNIC_PUL_USER_OB_RD_DBG_CNT_TAG_31_0, 150 1, 151 &pcie->ob_rd_no_tag); 152 fbnic_hw_stat_rst64(fbd, 153 FBNIC_PUL_USER_OB_RD_DBG_CNT_CPL_CRED_31_0, 154 1, 155 &pcie->ob_rd_no_cpl_cred); 156 fbnic_hw_stat_rst64(fbd, 157 FBNIC_PUL_USER_OB_RD_DBG_CNT_NP_CRED_31_0, 158 1, 159 &pcie->ob_rd_no_np_cred); 160 } 161 162 static void fbnic_get_pcie_stats_asic64(struct fbnic_dev *fbd, 163 struct fbnic_pcie_stats *pcie) 164 { 165 fbnic_hw_stat_rd64(fbd, 166 FBNIC_PUL_USER_OB_RD_TLP_CNT_31_0, 167 1, 168 &pcie->ob_rd_tlp); 169 fbnic_hw_stat_rd64(fbd, 170 FBNIC_PUL_USER_OB_RD_DWORD_CNT_31_0, 171 1, 172 &pcie->ob_rd_dword); 173 fbnic_hw_stat_rd64(fbd, 174 FBNIC_PUL_USER_OB_WR_TLP_CNT_31_0, 175 1, 176 &pcie->ob_wr_tlp); 177 fbnic_hw_stat_rd64(fbd, 178 FBNIC_PUL_USER_OB_WR_DWORD_CNT_31_0, 179 1, 180 &pcie->ob_wr_dword); 181 fbnic_hw_stat_rd64(fbd, 182 FBNIC_PUL_USER_OB_CPL_TLP_CNT_31_0, 183 1, 184 &pcie->ob_cpl_tlp); 185 fbnic_hw_stat_rd64(fbd, 186 FBNIC_PUL_USER_OB_CPL_DWORD_CNT_31_0, 187 1, 188 &pcie->ob_cpl_dword); 189 190 fbnic_hw_stat_rd64(fbd, 191 FBNIC_PUL_USER_OB_RD_DBG_CNT_TAG_31_0, 192 1, 193 &pcie->ob_rd_no_tag); 194 fbnic_hw_stat_rd64(fbd, 195 FBNIC_PUL_USER_OB_RD_DBG_CNT_CPL_CRED_31_0, 196 1, 197 &pcie->ob_rd_no_cpl_cred); 198 fbnic_hw_stat_rd64(fbd, 199 FBNIC_PUL_USER_OB_RD_DBG_CNT_NP_CRED_31_0, 200 1, 201 &pcie->ob_rd_no_np_cred); 202 } 203 204 void fbnic_reset_hw_stats(struct fbnic_dev *fbd) 205 { 206 fbnic_reset_rpc_stats(fbd, &fbd->hw_stats.rpc); 207 fbnic_reset_pcie_stats_asic(fbd, &fbd->hw_stats.pcie); 208 } 209 210 void fbnic_get_hw_stats32(struct fbnic_dev *fbd) 211 { 212 fbnic_get_rpc_stats32(fbd, &fbd->hw_stats.rpc); 213 } 214 215 void fbnic_get_hw_stats(struct fbnic_dev *fbd) 216 { 217 fbnic_get_hw_stats32(fbd); 218 219 fbnic_get_pcie_stats_asic64(fbd, &fbd->hw_stats.pcie); 220 } 221