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 #include <linux/log2.h> 6 7 #include "../nfpcore/nfp_cpp.h" 8 #include "../nfpcore/nfp_nffw.h" 9 #include "../nfp_app.h" 10 #include "../nfp_abi.h" 11 #include "../nfp_main.h" 12 #include "../nfp_net.h" 13 #include "main.h" 14 15 #define NFP_NUM_PRIOS_SYM_NAME "_abi_pci_dscp_num_prio_%u" 16 #define NFP_NUM_BANDS_SYM_NAME "_abi_pci_dscp_num_band_%u" 17 18 #define NFP_QLVL_SYM_NAME "_abi_nfd_out_q_lvls_%u%s" 19 #define NFP_QLVL_STRIDE 16 20 #define NFP_QLVL_BLOG_BYTES 0 21 #define NFP_QLVL_BLOG_PKTS 4 22 #define NFP_QLVL_THRS 8 23 24 #define NFP_QMSTAT_SYM_NAME "_abi_nfdqm%u_stats%s" 25 #define NFP_QMSTAT_STRIDE 32 26 #define NFP_QMSTAT_NON_STO 0 27 #define NFP_QMSTAT_STO 8 28 #define NFP_QMSTAT_DROP 16 29 #define NFP_QMSTAT_ECN 24 30 31 #define NFP_Q_STAT_SYM_NAME "_abi_nfd_rxq_stats%u%s" 32 #define NFP_Q_STAT_STRIDE 16 33 #define NFP_Q_STAT_PKTS 0 34 #define NFP_Q_STAT_BYTES 8 35 36 #define NFP_NET_ABM_MBOX_CMD NFP_NET_CFG_MBOX_SIMPLE_CMD 37 #define NFP_NET_ABM_MBOX_RET NFP_NET_CFG_MBOX_SIMPLE_RET 38 #define NFP_NET_ABM_MBOX_DATALEN NFP_NET_CFG_MBOX_SIMPLE_VAL 39 #define NFP_NET_ABM_MBOX_RESERVED (NFP_NET_CFG_MBOX_SIMPLE_VAL + 4) 40 #define NFP_NET_ABM_MBOX_DATA (NFP_NET_CFG_MBOX_SIMPLE_VAL + 8) 41 42 static int 43 nfp_abm_ctrl_stat(struct nfp_abm_link *alink, const struct nfp_rtsym *sym, 44 unsigned int stride, unsigned int offset, unsigned int band, 45 unsigned int queue, bool is_u64, u64 *res) 46 { 47 struct nfp_cpp *cpp = alink->abm->app->cpp; 48 u64 val, sym_offset; 49 unsigned int qid; 50 u32 val32; 51 int err; 52 53 qid = band * NFP_NET_MAX_RX_RINGS + alink->queue_base + queue; 54 55 sym_offset = qid * stride + offset; 56 if (is_u64) 57 err = __nfp_rtsym_readq(cpp, sym, 3, 0, sym_offset, &val); 58 else 59 err = __nfp_rtsym_readl(cpp, sym, 3, 0, sym_offset, &val32); 60 if (err) { 61 nfp_err(cpp, "RED offload reading stat failed on vNIC %d band %d queue %d (+ %d)\n", 62 alink->id, band, queue, alink->queue_base); 63 return err; 64 } 65 66 *res = is_u64 ? val : val32; 67 return 0; 68 } 69 70 int __nfp_abm_ctrl_set_q_lvl(struct nfp_abm *abm, unsigned int id, u32 val) 71 { 72 struct nfp_cpp *cpp = abm->app->cpp; 73 u64 sym_offset; 74 int err; 75 76 __clear_bit(id, abm->threshold_undef); 77 if (abm->thresholds[id] == val) 78 return 0; 79 80 sym_offset = id * NFP_QLVL_STRIDE + NFP_QLVL_THRS; 81 err = __nfp_rtsym_writel(cpp, abm->q_lvls, 4, 0, sym_offset, val); 82 if (err) { 83 nfp_err(cpp, 84 "RED offload setting level failed on subqueue %d\n", 85 id); 86 return err; 87 } 88 89 abm->thresholds[id] = val; 90 return 0; 91 } 92 93 int nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int band, 94 unsigned int queue, u32 val) 95 { 96 unsigned int threshold; 97 98 threshold = band * NFP_NET_MAX_RX_RINGS + alink->queue_base + queue; 99 100 return __nfp_abm_ctrl_set_q_lvl(alink->abm, threshold, val); 101 } 102 103 u64 nfp_abm_ctrl_stat_non_sto(struct nfp_abm_link *alink, unsigned int queue) 104 { 105 unsigned int band; 106 u64 val, sum = 0; 107 108 for (band = 0; band < alink->abm->num_bands; band++) { 109 if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 110 NFP_QMSTAT_STRIDE, NFP_QMSTAT_NON_STO, 111 band, queue, true, &val)) 112 return 0; 113 sum += val; 114 } 115 116 return sum; 117 } 118 119 u64 nfp_abm_ctrl_stat_sto(struct nfp_abm_link *alink, unsigned int queue) 120 { 121 unsigned int band; 122 u64 val, sum = 0; 123 124 for (band = 0; band < alink->abm->num_bands; band++) { 125 if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 126 NFP_QMSTAT_STRIDE, NFP_QMSTAT_STO, 127 band, queue, true, &val)) 128 return 0; 129 sum += val; 130 } 131 132 return sum; 133 } 134 135 static int 136 nfp_abm_ctrl_stat_basic(struct nfp_abm_link *alink, unsigned int band, 137 unsigned int queue, unsigned int off, u64 *val) 138 { 139 if (!nfp_abm_has_prio(alink->abm)) { 140 if (!band) { 141 unsigned int id = alink->queue_base + queue; 142 143 *val = nn_readq(alink->vnic, 144 NFP_NET_CFG_RXR_STATS(id) + off); 145 } else { 146 *val = 0; 147 } 148 149 return 0; 150 } else { 151 return nfp_abm_ctrl_stat(alink, alink->abm->q_stats, 152 NFP_Q_STAT_STRIDE, off, band, queue, 153 true, val); 154 } 155 } 156 157 int nfp_abm_ctrl_read_q_stats(struct nfp_abm_link *alink, unsigned int band, 158 unsigned int queue, struct nfp_alink_stats *stats) 159 { 160 int err; 161 162 err = nfp_abm_ctrl_stat_basic(alink, band, queue, NFP_Q_STAT_PKTS, 163 &stats->tx_pkts); 164 if (err) 165 return err; 166 167 err = nfp_abm_ctrl_stat_basic(alink, band, queue, NFP_Q_STAT_BYTES, 168 &stats->tx_bytes); 169 if (err) 170 return err; 171 172 err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls, NFP_QLVL_STRIDE, 173 NFP_QLVL_BLOG_BYTES, band, queue, false, 174 &stats->backlog_bytes); 175 if (err) 176 return err; 177 178 err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls, 179 NFP_QLVL_STRIDE, NFP_QLVL_BLOG_PKTS, 180 band, queue, false, &stats->backlog_pkts); 181 if (err) 182 return err; 183 184 err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 185 NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP, 186 band, queue, true, &stats->drops); 187 if (err) 188 return err; 189 190 return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 191 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN, 192 band, queue, true, &stats->overlimits); 193 } 194 195 int nfp_abm_ctrl_read_q_xstats(struct nfp_abm_link *alink, 196 unsigned int band, unsigned int queue, 197 struct nfp_alink_xstats *xstats) 198 { 199 int err; 200 201 err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 202 NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP, 203 band, queue, true, &xstats->pdrop); 204 if (err) 205 return err; 206 207 return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 208 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN, 209 band, queue, true, &xstats->ecn_marked); 210 } 211 212 int nfp_abm_ctrl_qm_enable(struct nfp_abm *abm) 213 { 214 return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_ENABLE, 215 NULL, 0, NULL, 0); 216 } 217 218 int nfp_abm_ctrl_qm_disable(struct nfp_abm *abm) 219 { 220 return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_DISABLE, 221 NULL, 0, NULL, 0); 222 } 223 224 static int nfp_abm_ctrl_prio_check_params(struct nfp_abm_link *alink) 225 { 226 struct nfp_abm *abm = alink->abm; 227 struct nfp_net *nn = alink->vnic; 228 unsigned int min_mbox_sz; 229 230 if (!nfp_abm_has_prio(alink->abm)) 231 return 0; 232 233 min_mbox_sz = NFP_NET_ABM_MBOX_DATA + alink->abm->prio_map_len; 234 if (nn->tlv_caps.mbox_len < min_mbox_sz) { 235 nfp_err(abm->app->pf->cpp, "vNIC mailbox too small for prio offload: %u, need: %u\n", 236 nn->tlv_caps.mbox_len, min_mbox_sz); 237 return -EINVAL; 238 } 239 240 return 0; 241 } 242 243 int nfp_abm_ctrl_read_params(struct nfp_abm_link *alink) 244 { 245 alink->queue_base = nn_readl(alink->vnic, NFP_NET_CFG_START_RXQ); 246 alink->queue_base /= alink->vnic->stride_rx; 247 248 return nfp_abm_ctrl_prio_check_params(alink); 249 } 250 251 static unsigned int nfp_abm_ctrl_prio_map_size(struct nfp_abm *abm) 252 { 253 unsigned int size; 254 255 size = roundup_pow_of_two(order_base_2(abm->num_bands)); 256 size = DIV_ROUND_UP(size * abm->num_prios, BITS_PER_BYTE); 257 size = round_up(size, sizeof(u32)); 258 259 return size; 260 } 261 262 static const struct nfp_rtsym * 263 nfp_abm_ctrl_find_rtsym(struct nfp_pf *pf, const char *name, unsigned int size) 264 { 265 const struct nfp_rtsym *sym; 266 267 sym = nfp_rtsym_lookup(pf->rtbl, name); 268 if (!sym) { 269 nfp_err(pf->cpp, "Symbol '%s' not found\n", name); 270 return ERR_PTR(-ENOENT); 271 } 272 if (nfp_rtsym_size(sym) != size) { 273 nfp_err(pf->cpp, 274 "Symbol '%s' wrong size: expected %u got %llu\n", 275 name, size, nfp_rtsym_size(sym)); 276 return ERR_PTR(-EINVAL); 277 } 278 279 return sym; 280 } 281 282 static const struct nfp_rtsym * 283 nfp_abm_ctrl_find_q_rtsym(struct nfp_abm *abm, const char *name_fmt, 284 size_t size) 285 { 286 char pf_symbol[64]; 287 288 size = array3_size(size, abm->num_bands, NFP_NET_MAX_RX_RINGS); 289 snprintf(pf_symbol, sizeof(pf_symbol), name_fmt, 290 abm->pf_id, nfp_abm_has_prio(abm) ? "_per_band" : ""); 291 292 return nfp_abm_ctrl_find_rtsym(abm->app->pf, pf_symbol, size); 293 } 294 295 int nfp_abm_ctrl_find_addrs(struct nfp_abm *abm) 296 { 297 struct nfp_pf *pf = abm->app->pf; 298 const struct nfp_rtsym *sym; 299 int res; 300 301 abm->pf_id = nfp_cppcore_pcie_unit(pf->cpp); 302 303 /* Read count of prios and prio bands */ 304 res = nfp_pf_rtsym_read_optional(pf, NFP_NUM_BANDS_SYM_NAME, 1); 305 if (res < 0) 306 return res; 307 abm->num_bands = res; 308 309 res = nfp_pf_rtsym_read_optional(pf, NFP_NUM_PRIOS_SYM_NAME, 1); 310 if (res < 0) 311 return res; 312 abm->num_prios = res; 313 314 abm->prio_map_len = nfp_abm_ctrl_prio_map_size(abm); 315 316 /* Check values are sane, U16_MAX is arbitrarily chosen as max */ 317 if (!is_power_of_2(abm->num_bands) || !is_power_of_2(abm->num_prios) || 318 abm->num_bands > U16_MAX || abm->num_prios > U16_MAX || 319 (abm->num_bands == 1) != (abm->num_prios == 1)) { 320 nfp_err(pf->cpp, 321 "invalid priomap description num bands: %u and num prios: %u\n", 322 abm->num_bands, abm->num_prios); 323 return -EINVAL; 324 } 325 326 /* Find level and stat symbols */ 327 sym = nfp_abm_ctrl_find_q_rtsym(abm, NFP_QLVL_SYM_NAME, 328 NFP_QLVL_STRIDE); 329 if (IS_ERR(sym)) 330 return PTR_ERR(sym); 331 abm->q_lvls = sym; 332 333 sym = nfp_abm_ctrl_find_q_rtsym(abm, NFP_QMSTAT_SYM_NAME, 334 NFP_QMSTAT_STRIDE); 335 if (IS_ERR(sym)) 336 return PTR_ERR(sym); 337 abm->qm_stats = sym; 338 339 if (nfp_abm_has_prio(abm)) { 340 sym = nfp_abm_ctrl_find_q_rtsym(abm, NFP_Q_STAT_SYM_NAME, 341 NFP_Q_STAT_STRIDE); 342 if (IS_ERR(sym)) 343 return PTR_ERR(sym); 344 abm->q_stats = sym; 345 } 346 347 return 0; 348 } 349