1 // SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 /* 3 * Copyright (C) 2018 Netronome Systems, Inc. 4 * 5 * This software is dual licensed under the GNU General License Version 2, 6 * June 1991 as shown in the file COPYING in the top-level directory of this 7 * source tree or the BSD 2-Clause License provided below. You have the 8 * option to license this software under the complete terms of either license. 9 * 10 * The BSD 2-Clause License: 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * 1. Redistributions of source code must retain the above 17 * copyright notice, this list of conditions and the following 18 * disclaimer. 19 * 20 * 2. Redistributions in binary form must reproduce the above 21 * copyright notice, this list of conditions and the following 22 * disclaimer in the documentation and/or other materials 23 * provided with the distribution. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 * SOFTWARE. 33 */ 34 35 #include <linux/kernel.h> 36 37 #include "../nfpcore/nfp_cpp.h" 38 #include "../nfpcore/nfp_nffw.h" 39 #include "../nfp_app.h" 40 #include "../nfp_abi.h" 41 #include "../nfp_main.h" 42 #include "../nfp_net.h" 43 #include "main.h" 44 45 #define NFP_QLVL_SYM_NAME "_abi_nfd_out_q_lvls_%u" 46 #define NFP_QLVL_STRIDE 16 47 #define NFP_QLVL_BLOG_BYTES 0 48 #define NFP_QLVL_BLOG_PKTS 4 49 #define NFP_QLVL_THRS 8 50 51 #define NFP_QMSTAT_SYM_NAME "_abi_nfdqm%u_stats" 52 #define NFP_QMSTAT_STRIDE 32 53 #define NFP_QMSTAT_NON_STO 0 54 #define NFP_QMSTAT_STO 8 55 #define NFP_QMSTAT_DROP 16 56 #define NFP_QMSTAT_ECN 24 57 58 static unsigned long long 59 nfp_abm_q_lvl_thrs(struct nfp_abm_link *alink, unsigned int queue) 60 { 61 return alink->abm->q_lvls->addr + 62 (alink->queue_base + queue) * NFP_QLVL_STRIDE + NFP_QLVL_THRS; 63 } 64 65 static int 66 nfp_abm_ctrl_stat(struct nfp_abm_link *alink, const struct nfp_rtsym *sym, 67 unsigned int stride, unsigned int offset, unsigned int i, 68 bool is_u64, u64 *res) 69 { 70 struct nfp_cpp *cpp = alink->abm->app->cpp; 71 u32 val32, mur; 72 u64 val, addr; 73 int err; 74 75 mur = NFP_CPP_ATOMIC_RD(sym->target, sym->domain); 76 77 addr = sym->addr + (alink->queue_base + i) * stride + offset; 78 if (is_u64) 79 err = nfp_cpp_readq(cpp, mur, addr, &val); 80 else 81 err = nfp_cpp_readl(cpp, mur, addr, &val32); 82 if (err) { 83 nfp_err(cpp, 84 "RED offload reading stat failed on vNIC %d queue %d\n", 85 alink->id, i); 86 return err; 87 } 88 89 *res = is_u64 ? val : val32; 90 return 0; 91 } 92 93 static int 94 nfp_abm_ctrl_stat_all(struct nfp_abm_link *alink, const struct nfp_rtsym *sym, 95 unsigned int stride, unsigned int offset, bool is_u64, 96 u64 *res) 97 { 98 u64 val, sum = 0; 99 unsigned int i; 100 int err; 101 102 for (i = 0; i < alink->vnic->max_rx_rings; i++) { 103 err = nfp_abm_ctrl_stat(alink, sym, stride, offset, i, 104 is_u64, &val); 105 if (err) 106 return err; 107 sum += val; 108 } 109 110 *res = sum; 111 return 0; 112 } 113 114 int nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int i, u32 val) 115 { 116 struct nfp_cpp *cpp = alink->abm->app->cpp; 117 u32 muw; 118 int err; 119 120 muw = NFP_CPP_ATOMIC_WR(alink->abm->q_lvls->target, 121 alink->abm->q_lvls->domain); 122 123 err = nfp_cpp_writel(cpp, muw, nfp_abm_q_lvl_thrs(alink, i), val); 124 if (err) { 125 nfp_err(cpp, "RED offload setting level failed on vNIC %d queue %d\n", 126 alink->id, i); 127 return err; 128 } 129 130 return 0; 131 } 132 133 int nfp_abm_ctrl_set_all_q_lvls(struct nfp_abm_link *alink, u32 val) 134 { 135 int i, err; 136 137 for (i = 0; i < alink->vnic->max_rx_rings; i++) { 138 err = nfp_abm_ctrl_set_q_lvl(alink, i, val); 139 if (err) 140 return err; 141 } 142 143 return 0; 144 } 145 146 u64 nfp_abm_ctrl_stat_non_sto(struct nfp_abm_link *alink, unsigned int i) 147 { 148 u64 val; 149 150 if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, NFP_QMSTAT_STRIDE, 151 NFP_QMSTAT_NON_STO, i, true, &val)) 152 return 0; 153 return val; 154 } 155 156 u64 nfp_abm_ctrl_stat_sto(struct nfp_abm_link *alink, unsigned int i) 157 { 158 u64 val; 159 160 if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, NFP_QMSTAT_STRIDE, 161 NFP_QMSTAT_STO, i, true, &val)) 162 return 0; 163 return val; 164 } 165 166 int nfp_abm_ctrl_read_q_stats(struct nfp_abm_link *alink, unsigned int i, 167 struct nfp_alink_stats *stats) 168 { 169 int err; 170 171 stats->tx_pkts = nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i)); 172 stats->tx_bytes = nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i) + 8); 173 174 err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls, 175 NFP_QLVL_STRIDE, NFP_QLVL_BLOG_BYTES, 176 i, false, &stats->backlog_bytes); 177 if (err) 178 return err; 179 180 err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls, 181 NFP_QLVL_STRIDE, NFP_QLVL_BLOG_PKTS, 182 i, false, &stats->backlog_pkts); 183 if (err) 184 return err; 185 186 err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 187 NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP, 188 i, true, &stats->drops); 189 if (err) 190 return err; 191 192 return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 193 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN, 194 i, true, &stats->overlimits); 195 } 196 197 int nfp_abm_ctrl_read_stats(struct nfp_abm_link *alink, 198 struct nfp_alink_stats *stats) 199 { 200 u64 pkts = 0, bytes = 0; 201 int i, err; 202 203 for (i = 0; i < alink->vnic->max_rx_rings; i++) { 204 pkts += nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i)); 205 bytes += nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i) + 8); 206 } 207 stats->tx_pkts = pkts; 208 stats->tx_bytes = bytes; 209 210 err = nfp_abm_ctrl_stat_all(alink, alink->abm->q_lvls, 211 NFP_QLVL_STRIDE, NFP_QLVL_BLOG_BYTES, 212 false, &stats->backlog_bytes); 213 if (err) 214 return err; 215 216 err = nfp_abm_ctrl_stat_all(alink, alink->abm->q_lvls, 217 NFP_QLVL_STRIDE, NFP_QLVL_BLOG_PKTS, 218 false, &stats->backlog_pkts); 219 if (err) 220 return err; 221 222 err = nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats, 223 NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP, 224 true, &stats->drops); 225 if (err) 226 return err; 227 228 return nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats, 229 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN, 230 true, &stats->overlimits); 231 } 232 233 int nfp_abm_ctrl_read_q_xstats(struct nfp_abm_link *alink, unsigned int i, 234 struct nfp_alink_xstats *xstats) 235 { 236 int err; 237 238 err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 239 NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP, 240 i, true, &xstats->pdrop); 241 if (err) 242 return err; 243 244 return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 245 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN, 246 i, true, &xstats->ecn_marked); 247 } 248 249 int nfp_abm_ctrl_read_xstats(struct nfp_abm_link *alink, 250 struct nfp_alink_xstats *xstats) 251 { 252 int err; 253 254 err = nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats, 255 NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP, 256 true, &xstats->pdrop); 257 if (err) 258 return err; 259 260 return nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats, 261 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN, 262 true, &xstats->ecn_marked); 263 } 264 265 int nfp_abm_ctrl_qm_enable(struct nfp_abm *abm) 266 { 267 return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_ENABLE, 268 NULL, 0, NULL, 0); 269 } 270 271 int nfp_abm_ctrl_qm_disable(struct nfp_abm *abm) 272 { 273 return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_DISABLE, 274 NULL, 0, NULL, 0); 275 } 276 277 void nfp_abm_ctrl_read_params(struct nfp_abm_link *alink) 278 { 279 alink->queue_base = nn_readl(alink->vnic, NFP_NET_CFG_START_RXQ); 280 alink->queue_base /= alink->vnic->stride_rx; 281 } 282 283 static const struct nfp_rtsym * 284 nfp_abm_ctrl_find_rtsym(struct nfp_pf *pf, const char *name, unsigned int size) 285 { 286 const struct nfp_rtsym *sym; 287 288 sym = nfp_rtsym_lookup(pf->rtbl, name); 289 if (!sym) { 290 nfp_err(pf->cpp, "Symbol '%s' not found\n", name); 291 return ERR_PTR(-ENOENT); 292 } 293 if (sym->size != size) { 294 nfp_err(pf->cpp, 295 "Symbol '%s' wrong size: expected %u got %llu\n", 296 name, size, sym->size); 297 return ERR_PTR(-EINVAL); 298 } 299 300 return sym; 301 } 302 303 static const struct nfp_rtsym * 304 nfp_abm_ctrl_find_q_rtsym(struct nfp_pf *pf, const char *name, 305 unsigned int size) 306 { 307 return nfp_abm_ctrl_find_rtsym(pf, name, size * NFP_NET_MAX_RX_RINGS); 308 } 309 310 int nfp_abm_ctrl_find_addrs(struct nfp_abm *abm) 311 { 312 struct nfp_pf *pf = abm->app->pf; 313 const struct nfp_rtsym *sym; 314 unsigned int pf_id; 315 char pf_symbol[64]; 316 317 pf_id = nfp_cppcore_pcie_unit(pf->cpp); 318 abm->pf_id = pf_id; 319 320 snprintf(pf_symbol, sizeof(pf_symbol), NFP_QLVL_SYM_NAME, pf_id); 321 sym = nfp_abm_ctrl_find_q_rtsym(pf, pf_symbol, NFP_QLVL_STRIDE); 322 if (IS_ERR(sym)) 323 return PTR_ERR(sym); 324 abm->q_lvls = sym; 325 326 snprintf(pf_symbol, sizeof(pf_symbol), NFP_QMSTAT_SYM_NAME, pf_id); 327 sym = nfp_abm_ctrl_find_q_rtsym(pf, pf_symbol, NFP_QMSTAT_STRIDE); 328 if (IS_ERR(sym)) 329 return PTR_ERR(sym); 330 abm->qm_stats = sym; 331 332 return 0; 333 } 334