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