xref: /linux/drivers/net/ethernet/netronome/nfp/abm/ctrl.c (revision cb89cac8e705b0405872a870842c6c2a0a0e5ec2)
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_DROP		16
54 #define NFP_QMSTAT_ECN		24
55 
56 static unsigned long long
57 nfp_abm_q_lvl_thrs(struct nfp_abm_link *alink, unsigned int queue)
58 {
59 	return alink->abm->q_lvls->addr +
60 		(alink->queue_base + queue) * NFP_QLVL_STRIDE + NFP_QLVL_THRS;
61 }
62 
63 static int
64 nfp_abm_ctrl_stat(struct nfp_abm_link *alink, const struct nfp_rtsym *sym,
65 		  unsigned int stride, unsigned int offset, unsigned int i,
66 		  bool is_u64, u64 *res)
67 {
68 	struct nfp_cpp *cpp = alink->abm->app->cpp;
69 	u32 val32, mur;
70 	u64 val, addr;
71 	int err;
72 
73 	mur = NFP_CPP_ATOMIC_RD(sym->target, sym->domain);
74 
75 	addr = sym->addr + (alink->queue_base + i) * stride + offset;
76 	if (is_u64)
77 		err = nfp_cpp_readq(cpp, mur, addr, &val);
78 	else
79 		err = nfp_cpp_readl(cpp, mur, addr, &val32);
80 	if (err) {
81 		nfp_err(cpp,
82 			"RED offload reading stat failed on vNIC %d queue %d\n",
83 			alink->id, i);
84 		return err;
85 	}
86 
87 	*res = is_u64 ? val : val32;
88 	return 0;
89 }
90 
91 static int
92 nfp_abm_ctrl_stat_all(struct nfp_abm_link *alink, const struct nfp_rtsym *sym,
93 		      unsigned int stride, unsigned int offset, bool is_u64,
94 		      u64 *res)
95 {
96 	u64 val, sum = 0;
97 	unsigned int i;
98 	int err;
99 
100 	for (i = 0; i < alink->vnic->max_rx_rings; i++) {
101 		err = nfp_abm_ctrl_stat(alink, sym, stride, offset, i,
102 					is_u64, &val);
103 		if (err)
104 			return err;
105 		sum += val;
106 	}
107 
108 	*res = sum;
109 	return 0;
110 }
111 
112 static int
113 nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int i, u32 val)
114 {
115 	struct nfp_cpp *cpp = alink->abm->app->cpp;
116 	u32 muw;
117 	int err;
118 
119 	muw = NFP_CPP_ATOMIC_WR(alink->abm->q_lvls->target,
120 				alink->abm->q_lvls->domain);
121 
122 	err = nfp_cpp_writel(cpp, muw, nfp_abm_q_lvl_thrs(alink, i), val);
123 	if (err) {
124 		nfp_err(cpp, "RED offload setting level failed on vNIC %d queue %d\n",
125 			alink->id, i);
126 		return err;
127 	}
128 
129 	return 0;
130 }
131 
132 int nfp_abm_ctrl_set_all_q_lvls(struct nfp_abm_link *alink, u32 val)
133 {
134 	int i, err;
135 
136 	for (i = 0; i < alink->vnic->max_rx_rings; i++) {
137 		err = nfp_abm_ctrl_set_q_lvl(alink, i, val);
138 		if (err)
139 			return err;
140 	}
141 
142 	return 0;
143 }
144 
145 int nfp_abm_ctrl_read_stats(struct nfp_abm_link *alink,
146 			    struct nfp_alink_stats *stats)
147 {
148 	u64 pkts = 0, bytes = 0;
149 	int i, err;
150 
151 	for (i = 0; i < alink->vnic->max_rx_rings; i++) {
152 		pkts += nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i));
153 		bytes += nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i) + 8);
154 	}
155 	stats->tx_pkts = pkts;
156 	stats->tx_bytes = bytes;
157 
158 	err = nfp_abm_ctrl_stat_all(alink, alink->abm->q_lvls,
159 				    NFP_QLVL_STRIDE, NFP_QLVL_BLOG_BYTES,
160 				    false, &stats->backlog_bytes);
161 	if (err)
162 		return err;
163 
164 	err = nfp_abm_ctrl_stat_all(alink, alink->abm->q_lvls,
165 				    NFP_QLVL_STRIDE, NFP_QLVL_BLOG_PKTS,
166 				    false, &stats->backlog_pkts);
167 	if (err)
168 		return err;
169 
170 	err = nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats,
171 				    NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP,
172 				    true, &stats->drops);
173 	if (err)
174 		return err;
175 
176 	return nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats,
177 				     NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN,
178 				     true, &stats->overlimits);
179 }
180 
181 int nfp_abm_ctrl_read_xstats(struct nfp_abm_link *alink,
182 			     struct nfp_alink_xstats *xstats)
183 {
184 	int err;
185 
186 	err = nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats,
187 				    NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP,
188 				    true, &xstats->pdrop);
189 	if (err)
190 		return err;
191 
192 	return nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats,
193 				     NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN,
194 				     true, &xstats->ecn_marked);
195 }
196 
197 int nfp_abm_ctrl_qm_enable(struct nfp_abm *abm)
198 {
199 	return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_ENABLE,
200 			    NULL, 0, NULL, 0);
201 }
202 
203 int nfp_abm_ctrl_qm_disable(struct nfp_abm *abm)
204 {
205 	return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_DISABLE,
206 			    NULL, 0, NULL, 0);
207 }
208 
209 void nfp_abm_ctrl_read_params(struct nfp_abm_link *alink)
210 {
211 	alink->queue_base = nn_readl(alink->vnic, NFP_NET_CFG_START_RXQ);
212 	alink->queue_base /= alink->vnic->stride_rx;
213 }
214 
215 static const struct nfp_rtsym *
216 nfp_abm_ctrl_find_rtsym(struct nfp_pf *pf, const char *name, unsigned int size)
217 {
218 	const struct nfp_rtsym *sym;
219 
220 	sym = nfp_rtsym_lookup(pf->rtbl, name);
221 	if (!sym) {
222 		nfp_err(pf->cpp, "Symbol '%s' not found\n", name);
223 		return ERR_PTR(-ENOENT);
224 	}
225 	if (sym->size != size) {
226 		nfp_err(pf->cpp,
227 			"Symbol '%s' wrong size: expected %u got %llu\n",
228 			name, size, sym->size);
229 		return ERR_PTR(-EINVAL);
230 	}
231 
232 	return sym;
233 }
234 
235 static const struct nfp_rtsym *
236 nfp_abm_ctrl_find_q_rtsym(struct nfp_pf *pf, const char *name,
237 			  unsigned int size)
238 {
239 	return nfp_abm_ctrl_find_rtsym(pf, name, size * NFP_NET_MAX_RX_RINGS);
240 }
241 
242 int nfp_abm_ctrl_find_addrs(struct nfp_abm *abm)
243 {
244 	struct nfp_pf *pf = abm->app->pf;
245 	const struct nfp_rtsym *sym;
246 	unsigned int pf_id;
247 	char pf_symbol[64];
248 
249 	pf_id =	nfp_cppcore_pcie_unit(pf->cpp);
250 	abm->pf_id = pf_id;
251 
252 	snprintf(pf_symbol, sizeof(pf_symbol), NFP_QLVL_SYM_NAME, pf_id);
253 	sym = nfp_abm_ctrl_find_q_rtsym(pf, pf_symbol, NFP_QLVL_STRIDE);
254 	if (IS_ERR(sym))
255 		return PTR_ERR(sym);
256 	abm->q_lvls = sym;
257 
258 	snprintf(pf_symbol, sizeof(pf_symbol), NFP_QMSTAT_SYM_NAME, pf_id);
259 	sym = nfp_abm_ctrl_find_q_rtsym(pf, pf_symbol, NFP_QMSTAT_STRIDE);
260 	if (IS_ERR(sym))
261 		return PTR_ERR(sym);
262 	abm->qm_stats = sym;
263 
264 	return 0;
265 }
266