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 #define NFP_Q_STAT_SYM_NAME	"_abi_nfd_rxq_stats%u%s"
32 #define NFP_Q_STAT_STRIDE	16
33 #define NFP_Q_STAT_PKTS		0
34 #define NFP_Q_STAT_BYTES	8
35 
36 #define NFP_NET_ABM_MBOX_CMD		NFP_NET_CFG_MBOX_SIMPLE_CMD
37 #define NFP_NET_ABM_MBOX_RET		NFP_NET_CFG_MBOX_SIMPLE_RET
38 #define NFP_NET_ABM_MBOX_DATALEN	NFP_NET_CFG_MBOX_SIMPLE_VAL
39 #define NFP_NET_ABM_MBOX_RESERVED	(NFP_NET_CFG_MBOX_SIMPLE_VAL + 4)
40 #define NFP_NET_ABM_MBOX_DATA		(NFP_NET_CFG_MBOX_SIMPLE_VAL + 8)
41 
42 static int
43 nfp_abm_ctrl_stat(struct nfp_abm_link *alink, const struct nfp_rtsym *sym,
44 		  unsigned int stride, unsigned int offset, unsigned int band,
45 		  unsigned int queue, bool is_u64, u64 *res)
46 {
47 	struct nfp_cpp *cpp = alink->abm->app->cpp;
48 	u64 val, sym_offset;
49 	unsigned int qid;
50 	u32 val32;
51 	int err;
52 
53 	qid = band * NFP_NET_MAX_RX_RINGS + alink->queue_base + queue;
54 
55 	sym_offset = qid * stride + offset;
56 	if (is_u64)
57 		err = __nfp_rtsym_readq(cpp, sym, 3, 0, sym_offset, &val);
58 	else
59 		err = __nfp_rtsym_readl(cpp, sym, 3, 0, sym_offset, &val32);
60 	if (err) {
61 		nfp_err(cpp, "RED offload reading stat failed on vNIC %d band %d queue %d (+ %d)\n",
62 			alink->id, band, queue, alink->queue_base);
63 		return err;
64 	}
65 
66 	*res = is_u64 ? val : val32;
67 	return 0;
68 }
69 
70 int __nfp_abm_ctrl_set_q_lvl(struct nfp_abm *abm, unsigned int id, u32 val)
71 {
72 	struct nfp_cpp *cpp = abm->app->cpp;
73 	u64 sym_offset;
74 	int err;
75 
76 	__clear_bit(id, abm->threshold_undef);
77 	if (abm->thresholds[id] == val)
78 		return 0;
79 
80 	sym_offset = id * NFP_QLVL_STRIDE + NFP_QLVL_THRS;
81 	err = __nfp_rtsym_writel(cpp, abm->q_lvls, 4, 0, sym_offset, val);
82 	if (err) {
83 		nfp_err(cpp,
84 			"RED offload setting level failed on subqueue %d\n",
85 			id);
86 		return err;
87 	}
88 
89 	abm->thresholds[id] = val;
90 	return 0;
91 }
92 
93 int nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int band,
94 			   unsigned int queue, u32 val)
95 {
96 	unsigned int threshold;
97 
98 	threshold = band * NFP_NET_MAX_RX_RINGS + alink->queue_base + queue;
99 
100 	return __nfp_abm_ctrl_set_q_lvl(alink->abm, threshold, val);
101 }
102 
103 u64 nfp_abm_ctrl_stat_non_sto(struct nfp_abm_link *alink, unsigned int queue)
104 {
105 	unsigned int band;
106 	u64 val, sum = 0;
107 
108 	for (band = 0; band < alink->abm->num_bands; band++) {
109 		if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
110 				      NFP_QMSTAT_STRIDE, NFP_QMSTAT_NON_STO,
111 				      band, queue, true, &val))
112 			return 0;
113 		sum += val;
114 	}
115 
116 	return sum;
117 }
118 
119 u64 nfp_abm_ctrl_stat_sto(struct nfp_abm_link *alink, unsigned int queue)
120 {
121 	unsigned int band;
122 	u64 val, sum = 0;
123 
124 	for (band = 0; band < alink->abm->num_bands; band++) {
125 		if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
126 				      NFP_QMSTAT_STRIDE, NFP_QMSTAT_STO,
127 				      band, queue, true, &val))
128 			return 0;
129 		sum += val;
130 	}
131 
132 	return sum;
133 }
134 
135 static int
136 nfp_abm_ctrl_stat_basic(struct nfp_abm_link *alink, unsigned int band,
137 			unsigned int queue, unsigned int off, u64 *val)
138 {
139 	if (!nfp_abm_has_prio(alink->abm)) {
140 		if (!band) {
141 			unsigned int id = alink->queue_base + queue;
142 
143 			*val = nn_readq(alink->vnic,
144 					NFP_NET_CFG_RXR_STATS(id) + off);
145 		} else {
146 			*val = 0;
147 		}
148 
149 		return 0;
150 	} else {
151 		return nfp_abm_ctrl_stat(alink, alink->abm->q_stats,
152 					 NFP_Q_STAT_STRIDE, off, band, queue,
153 					 true, val);
154 	}
155 }
156 
157 int nfp_abm_ctrl_read_q_stats(struct nfp_abm_link *alink, unsigned int band,
158 			      unsigned int queue, struct nfp_alink_stats *stats)
159 {
160 	int err;
161 
162 	err = nfp_abm_ctrl_stat_basic(alink, band, queue, NFP_Q_STAT_PKTS,
163 				      &stats->tx_pkts);
164 	if (err)
165 		return err;
166 
167 	err = nfp_abm_ctrl_stat_basic(alink, band, queue, NFP_Q_STAT_BYTES,
168 				      &stats->tx_bytes);
169 	if (err)
170 		return err;
171 
172 	err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls, NFP_QLVL_STRIDE,
173 				NFP_QLVL_BLOG_BYTES, band, queue, false,
174 				&stats->backlog_bytes);
175 	if (err)
176 		return err;
177 
178 	err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls,
179 				NFP_QLVL_STRIDE, NFP_QLVL_BLOG_PKTS,
180 				band, queue, false, &stats->backlog_pkts);
181 	if (err)
182 		return err;
183 
184 	err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
185 				NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP,
186 				band, queue, true, &stats->drops);
187 	if (err)
188 		return err;
189 
190 	return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
191 				 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN,
192 				 band, queue, true, &stats->overlimits);
193 }
194 
195 int nfp_abm_ctrl_read_q_xstats(struct nfp_abm_link *alink,
196 			       unsigned int band, unsigned int queue,
197 			       struct nfp_alink_xstats *xstats)
198 {
199 	int err;
200 
201 	err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
202 				NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP,
203 				band, queue, true, &xstats->pdrop);
204 	if (err)
205 		return err;
206 
207 	return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
208 				 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN,
209 				 band, queue, true, &xstats->ecn_marked);
210 }
211 
212 int nfp_abm_ctrl_qm_enable(struct nfp_abm *abm)
213 {
214 	return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_ENABLE,
215 			    NULL, 0, NULL, 0);
216 }
217 
218 int nfp_abm_ctrl_qm_disable(struct nfp_abm *abm)
219 {
220 	return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_DISABLE,
221 			    NULL, 0, NULL, 0);
222 }
223 
224 static int nfp_abm_ctrl_prio_check_params(struct nfp_abm_link *alink)
225 {
226 	struct nfp_abm *abm = alink->abm;
227 	struct nfp_net *nn = alink->vnic;
228 	unsigned int min_mbox_sz;
229 
230 	if (!nfp_abm_has_prio(alink->abm))
231 		return 0;
232 
233 	min_mbox_sz = NFP_NET_ABM_MBOX_DATA + alink->abm->prio_map_len;
234 	if (nn->tlv_caps.mbox_len < min_mbox_sz) {
235 		nfp_err(abm->app->pf->cpp, "vNIC mailbox too small for prio offload: %u, need: %u\n",
236 			nn->tlv_caps.mbox_len,  min_mbox_sz);
237 		return -EINVAL;
238 	}
239 
240 	return 0;
241 }
242 
243 int nfp_abm_ctrl_read_params(struct nfp_abm_link *alink)
244 {
245 	alink->queue_base = nn_readl(alink->vnic, NFP_NET_CFG_START_RXQ);
246 	alink->queue_base /= alink->vnic->stride_rx;
247 
248 	return nfp_abm_ctrl_prio_check_params(alink);
249 }
250 
251 static unsigned int nfp_abm_ctrl_prio_map_size(struct nfp_abm *abm)
252 {
253 	unsigned int size;
254 
255 	size = roundup_pow_of_two(order_base_2(abm->num_bands));
256 	size = DIV_ROUND_UP(size * abm->num_prios, BITS_PER_BYTE);
257 	size = round_up(size, sizeof(u32));
258 
259 	return size;
260 }
261 
262 static const struct nfp_rtsym *
263 nfp_abm_ctrl_find_rtsym(struct nfp_pf *pf, const char *name, unsigned int size)
264 {
265 	const struct nfp_rtsym *sym;
266 
267 	sym = nfp_rtsym_lookup(pf->rtbl, name);
268 	if (!sym) {
269 		nfp_err(pf->cpp, "Symbol '%s' not found\n", name);
270 		return ERR_PTR(-ENOENT);
271 	}
272 	if (nfp_rtsym_size(sym) != size) {
273 		nfp_err(pf->cpp,
274 			"Symbol '%s' wrong size: expected %u got %llu\n",
275 			name, size, nfp_rtsym_size(sym));
276 		return ERR_PTR(-EINVAL);
277 	}
278 
279 	return sym;
280 }
281 
282 static const struct nfp_rtsym *
283 nfp_abm_ctrl_find_q_rtsym(struct nfp_abm *abm, const char *name_fmt,
284 			  size_t size)
285 {
286 	char pf_symbol[64];
287 
288 	size = array3_size(size, abm->num_bands, NFP_NET_MAX_RX_RINGS);
289 	snprintf(pf_symbol, sizeof(pf_symbol), name_fmt,
290 		 abm->pf_id, nfp_abm_has_prio(abm) ? "_per_band" : "");
291 
292 	return nfp_abm_ctrl_find_rtsym(abm->app->pf, pf_symbol, size);
293 }
294 
295 int nfp_abm_ctrl_find_addrs(struct nfp_abm *abm)
296 {
297 	struct nfp_pf *pf = abm->app->pf;
298 	const struct nfp_rtsym *sym;
299 	int res;
300 
301 	abm->pf_id = nfp_cppcore_pcie_unit(pf->cpp);
302 
303 	/* Read count of prios and prio bands */
304 	res = nfp_pf_rtsym_read_optional(pf, NFP_NUM_BANDS_SYM_NAME, 1);
305 	if (res < 0)
306 		return res;
307 	abm->num_bands = res;
308 
309 	res = nfp_pf_rtsym_read_optional(pf, NFP_NUM_PRIOS_SYM_NAME, 1);
310 	if (res < 0)
311 		return res;
312 	abm->num_prios = res;
313 
314 	abm->prio_map_len = nfp_abm_ctrl_prio_map_size(abm);
315 
316 	/* Check values are sane, U16_MAX is arbitrarily chosen as max */
317 	if (!is_power_of_2(abm->num_bands) || !is_power_of_2(abm->num_prios) ||
318 	    abm->num_bands > U16_MAX || abm->num_prios > U16_MAX ||
319 	    (abm->num_bands == 1) != (abm->num_prios == 1)) {
320 		nfp_err(pf->cpp,
321 			"invalid priomap description num bands: %u and num prios: %u\n",
322 			abm->num_bands, abm->num_prios);
323 		return -EINVAL;
324 	}
325 
326 	/* Find level and stat symbols */
327 	sym = nfp_abm_ctrl_find_q_rtsym(abm, NFP_QLVL_SYM_NAME,
328 					NFP_QLVL_STRIDE);
329 	if (IS_ERR(sym))
330 		return PTR_ERR(sym);
331 	abm->q_lvls = sym;
332 
333 	sym = nfp_abm_ctrl_find_q_rtsym(abm, NFP_QMSTAT_SYM_NAME,
334 					NFP_QMSTAT_STRIDE);
335 	if (IS_ERR(sym))
336 		return PTR_ERR(sym);
337 	abm->qm_stats = sym;
338 
339 	if (nfp_abm_has_prio(abm)) {
340 		sym = nfp_abm_ctrl_find_q_rtsym(abm, NFP_Q_STAT_SYM_NAME,
341 						NFP_Q_STAT_STRIDE);
342 		if (IS_ERR(sym))
343 			return PTR_ERR(sym);
344 		abm->q_stats = sym;
345 	}
346 
347 	return 0;
348 }
349