1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 /* Copyright (C) 2018 Netronome Systems, Inc. */ 3 4 #include <linux/kernel.h> 5 6 #include "../nfpcore/nfp_cpp.h" 7 #include "../nfpcore/nfp_nffw.h" 8 #include "../nfp_app.h" 9 #include "../nfp_abi.h" 10 #include "../nfp_main.h" 11 #include "../nfp_net.h" 12 #include "main.h" 13 14 #define NFP_QLVL_SYM_NAME "_abi_nfd_out_q_lvls_%u" 15 #define NFP_QLVL_STRIDE 16 16 #define NFP_QLVL_BLOG_BYTES 0 17 #define NFP_QLVL_BLOG_PKTS 4 18 #define NFP_QLVL_THRS 8 19 20 #define NFP_QMSTAT_SYM_NAME "_abi_nfdqm%u_stats" 21 #define NFP_QMSTAT_STRIDE 32 22 #define NFP_QMSTAT_NON_STO 0 23 #define NFP_QMSTAT_STO 8 24 #define NFP_QMSTAT_DROP 16 25 #define NFP_QMSTAT_ECN 24 26 27 static int 28 nfp_abm_ctrl_stat(struct nfp_abm_link *alink, const struct nfp_rtsym *sym, 29 unsigned int stride, unsigned int offset, unsigned int i, 30 bool is_u64, u64 *res) 31 { 32 struct nfp_cpp *cpp = alink->abm->app->cpp; 33 u64 val, sym_offset; 34 u32 val32; 35 int err; 36 37 sym_offset = (alink->queue_base + i) * stride + offset; 38 if (is_u64) 39 err = __nfp_rtsym_readq(cpp, sym, 3, 0, sym_offset, &val); 40 else 41 err = __nfp_rtsym_readl(cpp, sym, 3, 0, sym_offset, &val32); 42 if (err) { 43 nfp_err(cpp, 44 "RED offload reading stat failed on vNIC %d queue %d\n", 45 alink->id, i); 46 return err; 47 } 48 49 *res = is_u64 ? val : val32; 50 return 0; 51 } 52 53 static int 54 nfp_abm_ctrl_stat_all(struct nfp_abm_link *alink, const struct nfp_rtsym *sym, 55 unsigned int stride, unsigned int offset, bool is_u64, 56 u64 *res) 57 { 58 u64 val, sum = 0; 59 unsigned int i; 60 int err; 61 62 for (i = 0; i < alink->vnic->max_rx_rings; i++) { 63 err = nfp_abm_ctrl_stat(alink, sym, stride, offset, i, 64 is_u64, &val); 65 if (err) 66 return err; 67 sum += val; 68 } 69 70 *res = sum; 71 return 0; 72 } 73 74 int nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int i, u32 val) 75 { 76 struct nfp_cpp *cpp = alink->abm->app->cpp; 77 u64 sym_offset; 78 int err; 79 80 sym_offset = (alink->queue_base + i) * NFP_QLVL_STRIDE + NFP_QLVL_THRS; 81 err = __nfp_rtsym_writel(cpp, alink->abm->q_lvls, 4, 0, 82 sym_offset, val); 83 if (err) { 84 nfp_err(cpp, "RED offload setting level failed on vNIC %d queue %d\n", 85 alink->id, i); 86 return err; 87 } 88 89 return 0; 90 } 91 92 int nfp_abm_ctrl_set_all_q_lvls(struct nfp_abm_link *alink, u32 val) 93 { 94 int i, err; 95 96 for (i = 0; i < alink->vnic->max_rx_rings; i++) { 97 err = nfp_abm_ctrl_set_q_lvl(alink, i, val); 98 if (err) 99 return err; 100 } 101 102 return 0; 103 } 104 105 u64 nfp_abm_ctrl_stat_non_sto(struct nfp_abm_link *alink, unsigned int i) 106 { 107 u64 val; 108 109 if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, NFP_QMSTAT_STRIDE, 110 NFP_QMSTAT_NON_STO, i, true, &val)) 111 return 0; 112 return val; 113 } 114 115 u64 nfp_abm_ctrl_stat_sto(struct nfp_abm_link *alink, unsigned int i) 116 { 117 u64 val; 118 119 if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, NFP_QMSTAT_STRIDE, 120 NFP_QMSTAT_STO, i, true, &val)) 121 return 0; 122 return val; 123 } 124 125 int nfp_abm_ctrl_read_q_stats(struct nfp_abm_link *alink, unsigned int i, 126 struct nfp_alink_stats *stats) 127 { 128 int err; 129 130 stats->tx_pkts = nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i)); 131 stats->tx_bytes = nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i) + 8); 132 133 err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls, 134 NFP_QLVL_STRIDE, NFP_QLVL_BLOG_BYTES, 135 i, false, &stats->backlog_bytes); 136 if (err) 137 return err; 138 139 err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls, 140 NFP_QLVL_STRIDE, NFP_QLVL_BLOG_PKTS, 141 i, false, &stats->backlog_pkts); 142 if (err) 143 return err; 144 145 err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 146 NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP, 147 i, true, &stats->drops); 148 if (err) 149 return err; 150 151 return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 152 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN, 153 i, true, &stats->overlimits); 154 } 155 156 int nfp_abm_ctrl_read_stats(struct nfp_abm_link *alink, 157 struct nfp_alink_stats *stats) 158 { 159 u64 pkts = 0, bytes = 0; 160 int i, err; 161 162 for (i = 0; i < alink->vnic->max_rx_rings; i++) { 163 pkts += nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i)); 164 bytes += nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i) + 8); 165 } 166 stats->tx_pkts = pkts; 167 stats->tx_bytes = bytes; 168 169 err = nfp_abm_ctrl_stat_all(alink, alink->abm->q_lvls, 170 NFP_QLVL_STRIDE, NFP_QLVL_BLOG_BYTES, 171 false, &stats->backlog_bytes); 172 if (err) 173 return err; 174 175 err = nfp_abm_ctrl_stat_all(alink, alink->abm->q_lvls, 176 NFP_QLVL_STRIDE, NFP_QLVL_BLOG_PKTS, 177 false, &stats->backlog_pkts); 178 if (err) 179 return err; 180 181 err = nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats, 182 NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP, 183 true, &stats->drops); 184 if (err) 185 return err; 186 187 return nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats, 188 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN, 189 true, &stats->overlimits); 190 } 191 192 int nfp_abm_ctrl_read_q_xstats(struct nfp_abm_link *alink, unsigned int i, 193 struct nfp_alink_xstats *xstats) 194 { 195 int err; 196 197 err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 198 NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP, 199 i, true, &xstats->pdrop); 200 if (err) 201 return err; 202 203 return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 204 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN, 205 i, true, &xstats->ecn_marked); 206 } 207 208 int nfp_abm_ctrl_read_xstats(struct nfp_abm_link *alink, 209 struct nfp_alink_xstats *xstats) 210 { 211 int err; 212 213 err = nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats, 214 NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP, 215 true, &xstats->pdrop); 216 if (err) 217 return err; 218 219 return nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats, 220 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN, 221 true, &xstats->ecn_marked); 222 } 223 224 int nfp_abm_ctrl_qm_enable(struct nfp_abm *abm) 225 { 226 return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_ENABLE, 227 NULL, 0, NULL, 0); 228 } 229 230 int nfp_abm_ctrl_qm_disable(struct nfp_abm *abm) 231 { 232 return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_DISABLE, 233 NULL, 0, NULL, 0); 234 } 235 236 void nfp_abm_ctrl_read_params(struct nfp_abm_link *alink) 237 { 238 alink->queue_base = nn_readl(alink->vnic, NFP_NET_CFG_START_RXQ); 239 alink->queue_base /= alink->vnic->stride_rx; 240 } 241 242 static const struct nfp_rtsym * 243 nfp_abm_ctrl_find_rtsym(struct nfp_pf *pf, const char *name, unsigned int size) 244 { 245 const struct nfp_rtsym *sym; 246 247 sym = nfp_rtsym_lookup(pf->rtbl, name); 248 if (!sym) { 249 nfp_err(pf->cpp, "Symbol '%s' not found\n", name); 250 return ERR_PTR(-ENOENT); 251 } 252 if (nfp_rtsym_size(sym) != size) { 253 nfp_err(pf->cpp, 254 "Symbol '%s' wrong size: expected %u got %llu\n", 255 name, size, nfp_rtsym_size(sym)); 256 return ERR_PTR(-EINVAL); 257 } 258 259 return sym; 260 } 261 262 static const struct nfp_rtsym * 263 nfp_abm_ctrl_find_q_rtsym(struct nfp_pf *pf, const char *name, 264 unsigned int size) 265 { 266 return nfp_abm_ctrl_find_rtsym(pf, name, size * NFP_NET_MAX_RX_RINGS); 267 } 268 269 int nfp_abm_ctrl_find_addrs(struct nfp_abm *abm) 270 { 271 struct nfp_pf *pf = abm->app->pf; 272 const struct nfp_rtsym *sym; 273 unsigned int pf_id; 274 char pf_symbol[64]; 275 276 pf_id = nfp_cppcore_pcie_unit(pf->cpp); 277 abm->pf_id = pf_id; 278 279 snprintf(pf_symbol, sizeof(pf_symbol), NFP_QLVL_SYM_NAME, pf_id); 280 sym = nfp_abm_ctrl_find_q_rtsym(pf, pf_symbol, NFP_QLVL_STRIDE); 281 if (IS_ERR(sym)) 282 return PTR_ERR(sym); 283 abm->q_lvls = sym; 284 285 snprintf(pf_symbol, sizeof(pf_symbol), NFP_QMSTAT_SYM_NAME, pf_id); 286 sym = nfp_abm_ctrl_find_q_rtsym(pf, pf_symbol, NFP_QMSTAT_STRIDE); 287 if (IS_ERR(sym)) 288 return PTR_ERR(sym); 289 abm->qm_stats = sym; 290 291 return 0; 292 } 293