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