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 int 59 nfp_abm_ctrl_stat(struct nfp_abm_link *alink, const struct nfp_rtsym *sym, 60 unsigned int stride, unsigned int offset, unsigned int i, 61 bool is_u64, u64 *res) 62 { 63 struct nfp_cpp *cpp = alink->abm->app->cpp; 64 u64 val, sym_offset; 65 u32 val32; 66 int err; 67 68 sym_offset = (alink->queue_base + i) * stride + offset; 69 if (is_u64) 70 err = __nfp_rtsym_readq(cpp, sym, 3, 0, sym_offset, &val); 71 else 72 err = __nfp_rtsym_readl(cpp, sym, 3, 0, sym_offset, &val32); 73 if (err) { 74 nfp_err(cpp, 75 "RED offload reading stat failed on vNIC %d queue %d\n", 76 alink->id, i); 77 return err; 78 } 79 80 *res = is_u64 ? val : val32; 81 return 0; 82 } 83 84 static int 85 nfp_abm_ctrl_stat_all(struct nfp_abm_link *alink, const struct nfp_rtsym *sym, 86 unsigned int stride, unsigned int offset, bool is_u64, 87 u64 *res) 88 { 89 u64 val, sum = 0; 90 unsigned int i; 91 int err; 92 93 for (i = 0; i < alink->vnic->max_rx_rings; i++) { 94 err = nfp_abm_ctrl_stat(alink, sym, stride, offset, i, 95 is_u64, &val); 96 if (err) 97 return err; 98 sum += val; 99 } 100 101 *res = sum; 102 return 0; 103 } 104 105 int nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int i, u32 val) 106 { 107 struct nfp_cpp *cpp = alink->abm->app->cpp; 108 u64 sym_offset; 109 int err; 110 111 sym_offset = (alink->queue_base + i) * NFP_QLVL_STRIDE + NFP_QLVL_THRS; 112 err = __nfp_rtsym_writel(cpp, alink->abm->q_lvls, 4, 0, 113 sym_offset, val); 114 if (err) { 115 nfp_err(cpp, "RED offload setting level failed on vNIC %d queue %d\n", 116 alink->id, i); 117 return err; 118 } 119 120 return 0; 121 } 122 123 int nfp_abm_ctrl_set_all_q_lvls(struct nfp_abm_link *alink, u32 val) 124 { 125 int i, err; 126 127 for (i = 0; i < alink->vnic->max_rx_rings; i++) { 128 err = nfp_abm_ctrl_set_q_lvl(alink, i, val); 129 if (err) 130 return err; 131 } 132 133 return 0; 134 } 135 136 u64 nfp_abm_ctrl_stat_non_sto(struct nfp_abm_link *alink, unsigned int i) 137 { 138 u64 val; 139 140 if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, NFP_QMSTAT_STRIDE, 141 NFP_QMSTAT_NON_STO, i, true, &val)) 142 return 0; 143 return val; 144 } 145 146 u64 nfp_abm_ctrl_stat_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_STO, i, true, &val)) 152 return 0; 153 return val; 154 } 155 156 int nfp_abm_ctrl_read_q_stats(struct nfp_abm_link *alink, unsigned int i, 157 struct nfp_alink_stats *stats) 158 { 159 int err; 160 161 stats->tx_pkts = nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i)); 162 stats->tx_bytes = nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i) + 8); 163 164 err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls, 165 NFP_QLVL_STRIDE, NFP_QLVL_BLOG_BYTES, 166 i, false, &stats->backlog_bytes); 167 if (err) 168 return err; 169 170 err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls, 171 NFP_QLVL_STRIDE, NFP_QLVL_BLOG_PKTS, 172 i, false, &stats->backlog_pkts); 173 if (err) 174 return err; 175 176 err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 177 NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP, 178 i, true, &stats->drops); 179 if (err) 180 return err; 181 182 return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 183 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN, 184 i, true, &stats->overlimits); 185 } 186 187 int nfp_abm_ctrl_read_stats(struct nfp_abm_link *alink, 188 struct nfp_alink_stats *stats) 189 { 190 u64 pkts = 0, bytes = 0; 191 int i, err; 192 193 for (i = 0; i < alink->vnic->max_rx_rings; i++) { 194 pkts += nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i)); 195 bytes += nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i) + 8); 196 } 197 stats->tx_pkts = pkts; 198 stats->tx_bytes = bytes; 199 200 err = nfp_abm_ctrl_stat_all(alink, alink->abm->q_lvls, 201 NFP_QLVL_STRIDE, NFP_QLVL_BLOG_BYTES, 202 false, &stats->backlog_bytes); 203 if (err) 204 return err; 205 206 err = nfp_abm_ctrl_stat_all(alink, alink->abm->q_lvls, 207 NFP_QLVL_STRIDE, NFP_QLVL_BLOG_PKTS, 208 false, &stats->backlog_pkts); 209 if (err) 210 return err; 211 212 err = nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats, 213 NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP, 214 true, &stats->drops); 215 if (err) 216 return err; 217 218 return nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats, 219 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN, 220 true, &stats->overlimits); 221 } 222 223 int nfp_abm_ctrl_read_q_xstats(struct nfp_abm_link *alink, unsigned int i, 224 struct nfp_alink_xstats *xstats) 225 { 226 int err; 227 228 err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 229 NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP, 230 i, true, &xstats->pdrop); 231 if (err) 232 return err; 233 234 return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, 235 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN, 236 i, true, &xstats->ecn_marked); 237 } 238 239 int nfp_abm_ctrl_read_xstats(struct nfp_abm_link *alink, 240 struct nfp_alink_xstats *xstats) 241 { 242 int err; 243 244 err = nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats, 245 NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP, 246 true, &xstats->pdrop); 247 if (err) 248 return err; 249 250 return nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats, 251 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN, 252 true, &xstats->ecn_marked); 253 } 254 255 int nfp_abm_ctrl_qm_enable(struct nfp_abm *abm) 256 { 257 return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_ENABLE, 258 NULL, 0, NULL, 0); 259 } 260 261 int nfp_abm_ctrl_qm_disable(struct nfp_abm *abm) 262 { 263 return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_DISABLE, 264 NULL, 0, NULL, 0); 265 } 266 267 void nfp_abm_ctrl_read_params(struct nfp_abm_link *alink) 268 { 269 alink->queue_base = nn_readl(alink->vnic, NFP_NET_CFG_START_RXQ); 270 alink->queue_base /= alink->vnic->stride_rx; 271 } 272 273 static const struct nfp_rtsym * 274 nfp_abm_ctrl_find_rtsym(struct nfp_pf *pf, const char *name, unsigned int size) 275 { 276 const struct nfp_rtsym *sym; 277 278 sym = nfp_rtsym_lookup(pf->rtbl, name); 279 if (!sym) { 280 nfp_err(pf->cpp, "Symbol '%s' not found\n", name); 281 return ERR_PTR(-ENOENT); 282 } 283 if (nfp_rtsym_size(sym) != size) { 284 nfp_err(pf->cpp, 285 "Symbol '%s' wrong size: expected %u got %llu\n", 286 name, size, nfp_rtsym_size(sym)); 287 return ERR_PTR(-EINVAL); 288 } 289 290 return sym; 291 } 292 293 static const struct nfp_rtsym * 294 nfp_abm_ctrl_find_q_rtsym(struct nfp_pf *pf, const char *name, 295 unsigned int size) 296 { 297 return nfp_abm_ctrl_find_rtsym(pf, name, size * NFP_NET_MAX_RX_RINGS); 298 } 299 300 int nfp_abm_ctrl_find_addrs(struct nfp_abm *abm) 301 { 302 struct nfp_pf *pf = abm->app->pf; 303 const struct nfp_rtsym *sym; 304 unsigned int pf_id; 305 char pf_symbol[64]; 306 307 pf_id = nfp_cppcore_pcie_unit(pf->cpp); 308 abm->pf_id = pf_id; 309 310 snprintf(pf_symbol, sizeof(pf_symbol), NFP_QLVL_SYM_NAME, pf_id); 311 sym = nfp_abm_ctrl_find_q_rtsym(pf, pf_symbol, NFP_QLVL_STRIDE); 312 if (IS_ERR(sym)) 313 return PTR_ERR(sym); 314 abm->q_lvls = sym; 315 316 snprintf(pf_symbol, sizeof(pf_symbol), NFP_QMSTAT_SYM_NAME, pf_id); 317 sym = nfp_abm_ctrl_find_q_rtsym(pf, pf_symbol, NFP_QMSTAT_STRIDE); 318 if (IS_ERR(sym)) 319 return PTR_ERR(sym); 320 abm->qm_stats = sym; 321 322 return 0; 323 } 324