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