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