GNU Linux-libre 4.19.286-gnu1
[releases.git] / drivers / net / ethernet / netronome / nfp / abm / ctrl.c
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 }