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