• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2020 Mellanox Technologies. All rights reserved */
3 
4 #include <linux/idr.h>
5 #include <linux/log2.h>
6 #include <linux/mutex.h>
7 #include <linux/netlink.h>
8 #include <net/devlink.h>
9 
10 #include "spectrum.h"
11 
12 struct mlxsw_sp_policer_family {
13 	enum mlxsw_sp_policer_type type;
14 	enum mlxsw_reg_qpcr_g qpcr_type;
15 	struct mlxsw_sp *mlxsw_sp;
16 	u16 start_index; /* Inclusive */
17 	u16 end_index; /* Exclusive */
18 	struct idr policer_idr;
19 	struct mutex lock; /* Protects policer_idr */
20 	atomic_t policers_count;
21 	const struct mlxsw_sp_policer_family_ops *ops;
22 };
23 
24 struct mlxsw_sp_policer {
25 	struct mlxsw_sp_policer_params params;
26 	u16 index;
27 };
28 
29 struct mlxsw_sp_policer_family_ops {
30 	int (*init)(struct mlxsw_sp_policer_family *family);
31 	void (*fini)(struct mlxsw_sp_policer_family *family);
32 	int (*policer_index_alloc)(struct mlxsw_sp_policer_family *family,
33 				   struct mlxsw_sp_policer *policer);
34 	struct mlxsw_sp_policer * (*policer_index_free)(struct mlxsw_sp_policer_family *family,
35 							u16 policer_index);
36 	int (*policer_init)(struct mlxsw_sp_policer_family *family,
37 			    const struct mlxsw_sp_policer *policer);
38 	int (*policer_params_check)(const struct mlxsw_sp_policer_family *family,
39 				    const struct mlxsw_sp_policer_params *params,
40 				    struct netlink_ext_ack *extack);
41 };
42 
43 struct mlxsw_sp_policer_core {
44 	struct mlxsw_sp_policer_family *family_arr[MLXSW_SP_POLICER_TYPE_MAX + 1];
45 	const struct mlxsw_sp_policer_core_ops *ops;
46 	u8 lowest_bs_bits;
47 	u8 highest_bs_bits;
48 };
49 
50 struct mlxsw_sp_policer_core_ops {
51 	int (*init)(struct mlxsw_sp_policer_core *policer_core);
52 };
53 
mlxsw_sp_policer_rate_bytes_ps_kbps(u64 rate_bytes_ps)54 static u64 mlxsw_sp_policer_rate_bytes_ps_kbps(u64 rate_bytes_ps)
55 {
56 	return div_u64(rate_bytes_ps, 1000) * BITS_PER_BYTE;
57 }
58 
mlxsw_sp_policer_burst_bytes_hw_units(u64 burst_bytes)59 static u8 mlxsw_sp_policer_burst_bytes_hw_units(u64 burst_bytes)
60 {
61 	/* Provided burst size is in bytes. The ASIC burst size value is
62 	 * (2 ^ bs) * 512 bits. Convert the provided size to 512-bit units.
63 	 */
64 	u64 bs512 = div_u64(burst_bytes, 64);
65 
66 	if (!bs512)
67 		return 0;
68 
69 	return fls64(bs512) - 1;
70 }
71 
mlxsw_sp_policer_single_rate_occ_get(void * priv)72 static u64 mlxsw_sp_policer_single_rate_occ_get(void *priv)
73 {
74 	struct mlxsw_sp_policer_family *family = priv;
75 
76 	return atomic_read(&family->policers_count);
77 }
78 
79 static int
mlxsw_sp_policer_single_rate_family_init(struct mlxsw_sp_policer_family * family)80 mlxsw_sp_policer_single_rate_family_init(struct mlxsw_sp_policer_family *family)
81 {
82 	struct mlxsw_core *core = family->mlxsw_sp->core;
83 	struct devlink *devlink;
84 
85 	/* CPU policers are allocated from the first N policers in the global
86 	 * range, so skip them.
87 	 */
88 	if (!MLXSW_CORE_RES_VALID(core, MAX_GLOBAL_POLICERS) ||
89 	    !MLXSW_CORE_RES_VALID(core, MAX_CPU_POLICERS))
90 		return -EIO;
91 
92 	family->start_index = MLXSW_CORE_RES_GET(core, MAX_CPU_POLICERS);
93 	family->end_index = MLXSW_CORE_RES_GET(core, MAX_GLOBAL_POLICERS);
94 
95 	atomic_set(&family->policers_count, 0);
96 	devlink = priv_to_devlink(core);
97 	devlink_resource_occ_get_register(devlink,
98 					  MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS,
99 					  mlxsw_sp_policer_single_rate_occ_get,
100 					  family);
101 
102 	return 0;
103 }
104 
105 static void
mlxsw_sp_policer_single_rate_family_fini(struct mlxsw_sp_policer_family * family)106 mlxsw_sp_policer_single_rate_family_fini(struct mlxsw_sp_policer_family *family)
107 {
108 	struct devlink *devlink = priv_to_devlink(family->mlxsw_sp->core);
109 
110 	devlink_resource_occ_get_unregister(devlink,
111 					    MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS);
112 	WARN_ON(atomic_read(&family->policers_count) != 0);
113 }
114 
115 static int
mlxsw_sp_policer_single_rate_index_alloc(struct mlxsw_sp_policer_family * family,struct mlxsw_sp_policer * policer)116 mlxsw_sp_policer_single_rate_index_alloc(struct mlxsw_sp_policer_family *family,
117 					 struct mlxsw_sp_policer *policer)
118 {
119 	int id;
120 
121 	mutex_lock(&family->lock);
122 	id = idr_alloc(&family->policer_idr, policer, family->start_index,
123 		       family->end_index, GFP_KERNEL);
124 	mutex_unlock(&family->lock);
125 
126 	if (id < 0)
127 		return id;
128 
129 	atomic_inc(&family->policers_count);
130 	policer->index = id;
131 
132 	return 0;
133 }
134 
135 static struct mlxsw_sp_policer *
mlxsw_sp_policer_single_rate_index_free(struct mlxsw_sp_policer_family * family,u16 policer_index)136 mlxsw_sp_policer_single_rate_index_free(struct mlxsw_sp_policer_family *family,
137 					u16 policer_index)
138 {
139 	struct mlxsw_sp_policer *policer;
140 
141 	atomic_dec(&family->policers_count);
142 
143 	mutex_lock(&family->lock);
144 	policer = idr_remove(&family->policer_idr, policer_index);
145 	mutex_unlock(&family->lock);
146 
147 	WARN_ON(!policer);
148 
149 	return policer;
150 }
151 
152 static int
mlxsw_sp_policer_single_rate_init(struct mlxsw_sp_policer_family * family,const struct mlxsw_sp_policer * policer)153 mlxsw_sp_policer_single_rate_init(struct mlxsw_sp_policer_family *family,
154 				  const struct mlxsw_sp_policer *policer)
155 {
156 	u64 rate_kbps = mlxsw_sp_policer_rate_bytes_ps_kbps(policer->params.rate);
157 	u8 bs = mlxsw_sp_policer_burst_bytes_hw_units(policer->params.burst);
158 	struct mlxsw_sp *mlxsw_sp = family->mlxsw_sp;
159 	char qpcr_pl[MLXSW_REG_QPCR_LEN];
160 
161 	mlxsw_reg_qpcr_pack(qpcr_pl, policer->index, MLXSW_REG_QPCR_IR_UNITS_K,
162 			    true, rate_kbps, bs);
163 	mlxsw_reg_qpcr_clear_counter_set(qpcr_pl, true);
164 
165 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
166 }
167 
168 static int
mlxsw_sp_policer_single_rate_params_check(const struct mlxsw_sp_policer_family * family,const struct mlxsw_sp_policer_params * params,struct netlink_ext_ack * extack)169 mlxsw_sp_policer_single_rate_params_check(const struct mlxsw_sp_policer_family *family,
170 					  const struct mlxsw_sp_policer_params *params,
171 					  struct netlink_ext_ack *extack)
172 {
173 	struct mlxsw_sp_policer_core *policer_core = family->mlxsw_sp->policer_core;
174 	u64 rate_bps = params->rate * BITS_PER_BYTE;
175 	u8 bs;
176 
177 	if (!params->bytes) {
178 		NL_SET_ERR_MSG_MOD(extack, "Only bandwidth policing is currently supported by single rate policers");
179 		return -EINVAL;
180 	}
181 
182 	if (!is_power_of_2(params->burst)) {
183 		NL_SET_ERR_MSG_MOD(extack, "Policer burst size is not power of two");
184 		return -EINVAL;
185 	}
186 
187 	bs = mlxsw_sp_policer_burst_bytes_hw_units(params->burst);
188 
189 	if (bs < policer_core->lowest_bs_bits) {
190 		NL_SET_ERR_MSG_MOD(extack, "Policer burst size lower than limit");
191 		return -EINVAL;
192 	}
193 
194 	if (bs > policer_core->highest_bs_bits) {
195 		NL_SET_ERR_MSG_MOD(extack, "Policer burst size higher than limit");
196 		return -EINVAL;
197 	}
198 
199 	if (rate_bps < MLXSW_REG_QPCR_LOWEST_CIR_BITS) {
200 		NL_SET_ERR_MSG_MOD(extack, "Policer rate lower than limit");
201 		return -EINVAL;
202 	}
203 
204 	if (rate_bps > MLXSW_REG_QPCR_HIGHEST_CIR_BITS) {
205 		NL_SET_ERR_MSG_MOD(extack, "Policer rate higher than limit");
206 		return -EINVAL;
207 	}
208 
209 	return 0;
210 }
211 
212 static const struct mlxsw_sp_policer_family_ops mlxsw_sp_policer_single_rate_ops = {
213 	.init			= mlxsw_sp_policer_single_rate_family_init,
214 	.fini			= mlxsw_sp_policer_single_rate_family_fini,
215 	.policer_index_alloc	= mlxsw_sp_policer_single_rate_index_alloc,
216 	.policer_index_free	= mlxsw_sp_policer_single_rate_index_free,
217 	.policer_init		= mlxsw_sp_policer_single_rate_init,
218 	.policer_params_check	= mlxsw_sp_policer_single_rate_params_check,
219 };
220 
221 static const struct mlxsw_sp_policer_family mlxsw_sp_policer_single_rate_family = {
222 	.type		= MLXSW_SP_POLICER_TYPE_SINGLE_RATE,
223 	.qpcr_type	= MLXSW_REG_QPCR_G_GLOBAL,
224 	.ops		= &mlxsw_sp_policer_single_rate_ops,
225 };
226 
227 static const struct mlxsw_sp_policer_family *mlxsw_sp_policer_family_arr[] = {
228 	[MLXSW_SP_POLICER_TYPE_SINGLE_RATE]	= &mlxsw_sp_policer_single_rate_family,
229 };
230 
mlxsw_sp_policer_add(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_policer_type type,const struct mlxsw_sp_policer_params * params,struct netlink_ext_ack * extack,u16 * p_policer_index)231 int mlxsw_sp_policer_add(struct mlxsw_sp *mlxsw_sp,
232 			 enum mlxsw_sp_policer_type type,
233 			 const struct mlxsw_sp_policer_params *params,
234 			 struct netlink_ext_ack *extack, u16 *p_policer_index)
235 {
236 	struct mlxsw_sp_policer_family *family;
237 	struct mlxsw_sp_policer *policer;
238 	int err;
239 
240 	family = mlxsw_sp->policer_core->family_arr[type];
241 
242 	err = family->ops->policer_params_check(family, params, extack);
243 	if (err)
244 		return err;
245 
246 	policer = kmalloc(sizeof(*policer), GFP_KERNEL);
247 	if (!policer)
248 		return -ENOMEM;
249 	policer->params = *params;
250 
251 	err = family->ops->policer_index_alloc(family, policer);
252 	if (err) {
253 		NL_SET_ERR_MSG_MOD(extack, "Failed to allocate policer index");
254 		goto err_policer_index_alloc;
255 	}
256 
257 	err = family->ops->policer_init(family, policer);
258 	if (err) {
259 		NL_SET_ERR_MSG_MOD(extack, "Failed to initialize policer");
260 		goto err_policer_init;
261 	}
262 
263 	*p_policer_index = policer->index;
264 
265 	return 0;
266 
267 err_policer_init:
268 	family->ops->policer_index_free(family, policer->index);
269 err_policer_index_alloc:
270 	kfree(policer);
271 	return err;
272 }
273 
mlxsw_sp_policer_del(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_policer_type type,u16 policer_index)274 void mlxsw_sp_policer_del(struct mlxsw_sp *mlxsw_sp,
275 			  enum mlxsw_sp_policer_type type, u16 policer_index)
276 {
277 	struct mlxsw_sp_policer_family *family;
278 	struct mlxsw_sp_policer *policer;
279 
280 	family = mlxsw_sp->policer_core->family_arr[type];
281 	policer = family->ops->policer_index_free(family, policer_index);
282 	kfree(policer);
283 }
284 
mlxsw_sp_policer_drops_counter_get(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_policer_type type,u16 policer_index,u64 * p_drops)285 int mlxsw_sp_policer_drops_counter_get(struct mlxsw_sp *mlxsw_sp,
286 				       enum mlxsw_sp_policer_type type,
287 				       u16 policer_index, u64 *p_drops)
288 {
289 	struct mlxsw_sp_policer_family *family;
290 	char qpcr_pl[MLXSW_REG_QPCR_LEN];
291 	int err;
292 
293 	family = mlxsw_sp->policer_core->family_arr[type];
294 
295 	MLXSW_REG_ZERO(qpcr, qpcr_pl);
296 	mlxsw_reg_qpcr_pid_set(qpcr_pl, policer_index);
297 	mlxsw_reg_qpcr_g_set(qpcr_pl, family->qpcr_type);
298 	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl);
299 	if (err)
300 		return err;
301 
302 	*p_drops = mlxsw_reg_qpcr_violate_count_get(qpcr_pl);
303 
304 	return 0;
305 }
306 
307 static int
mlxsw_sp_policer_family_register(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_policer_family * tmpl)308 mlxsw_sp_policer_family_register(struct mlxsw_sp *mlxsw_sp,
309 				 const struct mlxsw_sp_policer_family *tmpl)
310 {
311 	struct mlxsw_sp_policer_family *family;
312 	int err;
313 
314 	family = kmemdup(tmpl, sizeof(*family), GFP_KERNEL);
315 	if (!family)
316 		return -ENOMEM;
317 
318 	family->mlxsw_sp = mlxsw_sp;
319 	idr_init(&family->policer_idr);
320 	mutex_init(&family->lock);
321 
322 	err = family->ops->init(family);
323 	if (err)
324 		goto err_family_init;
325 
326 	if (WARN_ON(family->start_index >= family->end_index)) {
327 		err = -EINVAL;
328 		goto err_index_check;
329 	}
330 
331 	mlxsw_sp->policer_core->family_arr[tmpl->type] = family;
332 
333 	return 0;
334 
335 err_index_check:
336 	family->ops->fini(family);
337 err_family_init:
338 	mutex_destroy(&family->lock);
339 	idr_destroy(&family->policer_idr);
340 	kfree(family);
341 	return err;
342 }
343 
344 static void
mlxsw_sp_policer_family_unregister(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_policer_family * family)345 mlxsw_sp_policer_family_unregister(struct mlxsw_sp *mlxsw_sp,
346 				   struct mlxsw_sp_policer_family *family)
347 {
348 	family->ops->fini(family);
349 	mutex_destroy(&family->lock);
350 	WARN_ON(!idr_is_empty(&family->policer_idr));
351 	idr_destroy(&family->policer_idr);
352 	kfree(family);
353 }
354 
mlxsw_sp_policers_init(struct mlxsw_sp * mlxsw_sp)355 int mlxsw_sp_policers_init(struct mlxsw_sp *mlxsw_sp)
356 {
357 	struct mlxsw_sp_policer_core *policer_core;
358 	int i, err;
359 
360 	policer_core = kzalloc(sizeof(*policer_core), GFP_KERNEL);
361 	if (!policer_core)
362 		return -ENOMEM;
363 	mlxsw_sp->policer_core = policer_core;
364 	policer_core->ops = mlxsw_sp->policer_core_ops;
365 
366 	err = policer_core->ops->init(policer_core);
367 	if (err)
368 		goto err_init;
369 
370 	for (i = 0; i < MLXSW_SP_POLICER_TYPE_MAX + 1; i++) {
371 		err = mlxsw_sp_policer_family_register(mlxsw_sp, mlxsw_sp_policer_family_arr[i]);
372 		if (err)
373 			goto err_family_register;
374 	}
375 
376 	return 0;
377 
378 err_family_register:
379 	for (i--; i >= 0; i--) {
380 		struct mlxsw_sp_policer_family *family;
381 
382 		family = mlxsw_sp->policer_core->family_arr[i];
383 		mlxsw_sp_policer_family_unregister(mlxsw_sp, family);
384 	}
385 err_init:
386 	kfree(mlxsw_sp->policer_core);
387 	return err;
388 }
389 
mlxsw_sp_policers_fini(struct mlxsw_sp * mlxsw_sp)390 void mlxsw_sp_policers_fini(struct mlxsw_sp *mlxsw_sp)
391 {
392 	int i;
393 
394 	for (i = MLXSW_SP_POLICER_TYPE_MAX; i >= 0; i--) {
395 		struct mlxsw_sp_policer_family *family;
396 
397 		family = mlxsw_sp->policer_core->family_arr[i];
398 		mlxsw_sp_policer_family_unregister(mlxsw_sp, family);
399 	}
400 
401 	kfree(mlxsw_sp->policer_core);
402 }
403 
mlxsw_sp_policer_resources_register(struct mlxsw_core * mlxsw_core)404 int mlxsw_sp_policer_resources_register(struct mlxsw_core *mlxsw_core)
405 {
406 	u64 global_policers, cpu_policers, single_rate_policers;
407 	struct devlink *devlink = priv_to_devlink(mlxsw_core);
408 	struct devlink_resource_size_params size_params;
409 	int err;
410 
411 	if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_GLOBAL_POLICERS) ||
412 	    !MLXSW_CORE_RES_VALID(mlxsw_core, MAX_CPU_POLICERS))
413 		return -EIO;
414 
415 	global_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_GLOBAL_POLICERS);
416 	cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS);
417 	single_rate_policers = global_policers - cpu_policers;
418 
419 	devlink_resource_size_params_init(&size_params, global_policers,
420 					  global_policers, 1,
421 					  DEVLINK_RESOURCE_UNIT_ENTRY);
422 	err = devlink_resource_register(devlink, "global_policers",
423 					global_policers,
424 					MLXSW_SP_RESOURCE_GLOBAL_POLICERS,
425 					DEVLINK_RESOURCE_ID_PARENT_TOP,
426 					&size_params);
427 	if (err)
428 		return err;
429 
430 	devlink_resource_size_params_init(&size_params, single_rate_policers,
431 					  single_rate_policers, 1,
432 					  DEVLINK_RESOURCE_UNIT_ENTRY);
433 	err = devlink_resource_register(devlink, "single_rate_policers",
434 					single_rate_policers,
435 					MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS,
436 					MLXSW_SP_RESOURCE_GLOBAL_POLICERS,
437 					&size_params);
438 	if (err)
439 		return err;
440 
441 	return 0;
442 }
443 
444 static int
mlxsw_sp1_policer_core_init(struct mlxsw_sp_policer_core * policer_core)445 mlxsw_sp1_policer_core_init(struct mlxsw_sp_policer_core *policer_core)
446 {
447 	policer_core->lowest_bs_bits = MLXSW_REG_QPCR_LOWEST_CBS_BITS_SP1;
448 	policer_core->highest_bs_bits = MLXSW_REG_QPCR_HIGHEST_CBS_BITS_SP1;
449 
450 	return 0;
451 }
452 
453 const struct mlxsw_sp_policer_core_ops mlxsw_sp1_policer_core_ops = {
454 	.init = mlxsw_sp1_policer_core_init,
455 };
456 
457 static int
mlxsw_sp2_policer_core_init(struct mlxsw_sp_policer_core * policer_core)458 mlxsw_sp2_policer_core_init(struct mlxsw_sp_policer_core *policer_core)
459 {
460 	policer_core->lowest_bs_bits = MLXSW_REG_QPCR_LOWEST_CBS_BITS_SP2;
461 	policer_core->highest_bs_bits = MLXSW_REG_QPCR_HIGHEST_CBS_BITS_SP2;
462 
463 	return 0;
464 }
465 
466 const struct mlxsw_sp_policer_core_ops mlxsw_sp2_policer_core_ops = {
467 	.init = mlxsw_sp2_policer_core_init,
468 };
469