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