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 
6 #include "../nfpcore/nfp_cpp.h"
7 #include "../nfpcore/nfp_nffw.h"
8 #include "../nfp_app.h"
9 #include "../nfp_abi.h"
10 #include "../nfp_main.h"
11 #include "../nfp_net.h"
12 #include "main.h"
13 
14 #define NFP_QLVL_SYM_NAME	"_abi_nfd_out_q_lvls_%u"
15 #define NFP_QLVL_STRIDE		16
16 #define NFP_QLVL_BLOG_BYTES	0
17 #define NFP_QLVL_BLOG_PKTS	4
18 #define NFP_QLVL_THRS		8
19 
20 #define NFP_QMSTAT_SYM_NAME	"_abi_nfdqm%u_stats"
21 #define NFP_QMSTAT_STRIDE	32
22 #define NFP_QMSTAT_NON_STO	0
23 #define NFP_QMSTAT_STO		8
24 #define NFP_QMSTAT_DROP		16
25 #define NFP_QMSTAT_ECN		24
26 
27 static int
28 nfp_abm_ctrl_stat(struct nfp_abm_link *alink, const struct nfp_rtsym *sym,
29 		  unsigned int stride, unsigned int offset, unsigned int i,
30 		  bool is_u64, u64 *res)
31 {
32 	struct nfp_cpp *cpp = alink->abm->app->cpp;
33 	u64 val, sym_offset;
34 	u32 val32;
35 	int err;
36 
37 	sym_offset = (alink->queue_base + i) * stride + offset;
38 	if (is_u64)
39 		err = __nfp_rtsym_readq(cpp, sym, 3, 0, sym_offset, &val);
40 	else
41 		err = __nfp_rtsym_readl(cpp, sym, 3, 0, sym_offset, &val32);
42 	if (err) {
43 		nfp_err(cpp,
44 			"RED offload reading stat failed on vNIC %d queue %d\n",
45 			alink->id, i);
46 		return err;
47 	}
48 
49 	*res = is_u64 ? val : val32;
50 	return 0;
51 }
52 
53 static int
54 nfp_abm_ctrl_stat_all(struct nfp_abm_link *alink, const struct nfp_rtsym *sym,
55 		      unsigned int stride, unsigned int offset, bool is_u64,
56 		      u64 *res)
57 {
58 	u64 val, sum = 0;
59 	unsigned int i;
60 	int err;
61 
62 	for (i = 0; i < alink->vnic->max_rx_rings; i++) {
63 		err = nfp_abm_ctrl_stat(alink, sym, stride, offset, i,
64 					is_u64, &val);
65 		if (err)
66 			return err;
67 		sum += val;
68 	}
69 
70 	*res = sum;
71 	return 0;
72 }
73 
74 int nfp_abm_ctrl_set_q_lvl(struct nfp_abm_link *alink, unsigned int i, u32 val)
75 {
76 	struct nfp_cpp *cpp = alink->abm->app->cpp;
77 	u64 sym_offset;
78 	int err;
79 
80 	sym_offset = (alink->queue_base + i) * NFP_QLVL_STRIDE + NFP_QLVL_THRS;
81 	err = __nfp_rtsym_writel(cpp, alink->abm->q_lvls, 4, 0,
82 				 sym_offset, val);
83 	if (err) {
84 		nfp_err(cpp, "RED offload setting level failed on vNIC %d queue %d\n",
85 			alink->id, i);
86 		return err;
87 	}
88 
89 	return 0;
90 }
91 
92 int nfp_abm_ctrl_set_all_q_lvls(struct nfp_abm_link *alink, u32 val)
93 {
94 	int i, err;
95 
96 	for (i = 0; i < alink->vnic->max_rx_rings; i++) {
97 		err = nfp_abm_ctrl_set_q_lvl(alink, i, val);
98 		if (err)
99 			return err;
100 	}
101 
102 	return 0;
103 }
104 
105 u64 nfp_abm_ctrl_stat_non_sto(struct nfp_abm_link *alink, unsigned int i)
106 {
107 	u64 val;
108 
109 	if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, NFP_QMSTAT_STRIDE,
110 			      NFP_QMSTAT_NON_STO, i, true, &val))
111 		return 0;
112 	return val;
113 }
114 
115 u64 nfp_abm_ctrl_stat_sto(struct nfp_abm_link *alink, unsigned int i)
116 {
117 	u64 val;
118 
119 	if (nfp_abm_ctrl_stat(alink, alink->abm->qm_stats, NFP_QMSTAT_STRIDE,
120 			      NFP_QMSTAT_STO, i, true, &val))
121 		return 0;
122 	return val;
123 }
124 
125 int nfp_abm_ctrl_read_q_stats(struct nfp_abm_link *alink, unsigned int i,
126 			      struct nfp_alink_stats *stats)
127 {
128 	int err;
129 
130 	stats->tx_pkts = nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i));
131 	stats->tx_bytes = nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i) + 8);
132 
133 	err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls,
134 				NFP_QLVL_STRIDE, NFP_QLVL_BLOG_BYTES,
135 				i, false, &stats->backlog_bytes);
136 	if (err)
137 		return err;
138 
139 	err = nfp_abm_ctrl_stat(alink, alink->abm->q_lvls,
140 				NFP_QLVL_STRIDE, NFP_QLVL_BLOG_PKTS,
141 				i, false, &stats->backlog_pkts);
142 	if (err)
143 		return err;
144 
145 	err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
146 				NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP,
147 				i, true, &stats->drops);
148 	if (err)
149 		return err;
150 
151 	return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
152 				 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN,
153 				 i, true, &stats->overlimits);
154 }
155 
156 int nfp_abm_ctrl_read_stats(struct nfp_abm_link *alink,
157 			    struct nfp_alink_stats *stats)
158 {
159 	u64 pkts = 0, bytes = 0;
160 	int i, err;
161 
162 	for (i = 0; i < alink->vnic->max_rx_rings; i++) {
163 		pkts += nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i));
164 		bytes += nn_readq(alink->vnic, NFP_NET_CFG_RXR_STATS(i) + 8);
165 	}
166 	stats->tx_pkts = pkts;
167 	stats->tx_bytes = bytes;
168 
169 	err = nfp_abm_ctrl_stat_all(alink, alink->abm->q_lvls,
170 				    NFP_QLVL_STRIDE, NFP_QLVL_BLOG_BYTES,
171 				    false, &stats->backlog_bytes);
172 	if (err)
173 		return err;
174 
175 	err = nfp_abm_ctrl_stat_all(alink, alink->abm->q_lvls,
176 				    NFP_QLVL_STRIDE, NFP_QLVL_BLOG_PKTS,
177 				    false, &stats->backlog_pkts);
178 	if (err)
179 		return err;
180 
181 	err = nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats,
182 				    NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP,
183 				    true, &stats->drops);
184 	if (err)
185 		return err;
186 
187 	return nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats,
188 				     NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN,
189 				     true, &stats->overlimits);
190 }
191 
192 int nfp_abm_ctrl_read_q_xstats(struct nfp_abm_link *alink, unsigned int i,
193 			       struct nfp_alink_xstats *xstats)
194 {
195 	int err;
196 
197 	err = nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
198 				NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP,
199 				i, true, &xstats->pdrop);
200 	if (err)
201 		return err;
202 
203 	return nfp_abm_ctrl_stat(alink, alink->abm->qm_stats,
204 				 NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN,
205 				 i, true, &xstats->ecn_marked);
206 }
207 
208 int nfp_abm_ctrl_read_xstats(struct nfp_abm_link *alink,
209 			     struct nfp_alink_xstats *xstats)
210 {
211 	int err;
212 
213 	err = nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats,
214 				    NFP_QMSTAT_STRIDE, NFP_QMSTAT_DROP,
215 				    true, &xstats->pdrop);
216 	if (err)
217 		return err;
218 
219 	return nfp_abm_ctrl_stat_all(alink, alink->abm->qm_stats,
220 				     NFP_QMSTAT_STRIDE, NFP_QMSTAT_ECN,
221 				     true, &xstats->ecn_marked);
222 }
223 
224 int nfp_abm_ctrl_qm_enable(struct nfp_abm *abm)
225 {
226 	return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_ENABLE,
227 			    NULL, 0, NULL, 0);
228 }
229 
230 int nfp_abm_ctrl_qm_disable(struct nfp_abm *abm)
231 {
232 	return nfp_mbox_cmd(abm->app->pf, NFP_MBOX_PCIE_ABM_DISABLE,
233 			    NULL, 0, NULL, 0);
234 }
235 
236 void nfp_abm_ctrl_read_params(struct nfp_abm_link *alink)
237 {
238 	alink->queue_base = nn_readl(alink->vnic, NFP_NET_CFG_START_RXQ);
239 	alink->queue_base /= alink->vnic->stride_rx;
240 }
241 
242 static const struct nfp_rtsym *
243 nfp_abm_ctrl_find_rtsym(struct nfp_pf *pf, const char *name, unsigned int size)
244 {
245 	const struct nfp_rtsym *sym;
246 
247 	sym = nfp_rtsym_lookup(pf->rtbl, name);
248 	if (!sym) {
249 		nfp_err(pf->cpp, "Symbol '%s' not found\n", name);
250 		return ERR_PTR(-ENOENT);
251 	}
252 	if (nfp_rtsym_size(sym) != size) {
253 		nfp_err(pf->cpp,
254 			"Symbol '%s' wrong size: expected %u got %llu\n",
255 			name, size, nfp_rtsym_size(sym));
256 		return ERR_PTR(-EINVAL);
257 	}
258 
259 	return sym;
260 }
261 
262 static const struct nfp_rtsym *
263 nfp_abm_ctrl_find_q_rtsym(struct nfp_pf *pf, const char *name,
264 			  unsigned int size)
265 {
266 	return nfp_abm_ctrl_find_rtsym(pf, name, size * NFP_NET_MAX_RX_RINGS);
267 }
268 
269 int nfp_abm_ctrl_find_addrs(struct nfp_abm *abm)
270 {
271 	struct nfp_pf *pf = abm->app->pf;
272 	const struct nfp_rtsym *sym;
273 	unsigned int pf_id;
274 	char pf_symbol[64];
275 
276 	pf_id =	nfp_cppcore_pcie_unit(pf->cpp);
277 	abm->pf_id = pf_id;
278 
279 	snprintf(pf_symbol, sizeof(pf_symbol), NFP_QLVL_SYM_NAME, pf_id);
280 	sym = nfp_abm_ctrl_find_q_rtsym(pf, pf_symbol, NFP_QLVL_STRIDE);
281 	if (IS_ERR(sym))
282 		return PTR_ERR(sym);
283 	abm->q_lvls = sym;
284 
285 	snprintf(pf_symbol, sizeof(pf_symbol), NFP_QMSTAT_SYM_NAME, pf_id);
286 	sym = nfp_abm_ctrl_find_q_rtsym(pf, pf_symbol, NFP_QMSTAT_STRIDE);
287 	if (IS_ERR(sym))
288 		return PTR_ERR(sym);
289 	abm->qm_stats = sym;
290 
291 	return 0;
292 }
293