1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
5 */
6
7#include "devl_internal.h"
8
9struct devlink_sb {
10	struct list_head list;
11	unsigned int index;
12	u32 size;
13	u16 ingress_pools_count;
14	u16 egress_pools_count;
15	u16 ingress_tc_count;
16	u16 egress_tc_count;
17};
18
19static u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb)
20{
21	return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count;
22}
23
24static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink,
25						  unsigned int sb_index)
26{
27	struct devlink_sb *devlink_sb;
28
29	list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
30		if (devlink_sb->index == sb_index)
31			return devlink_sb;
32	}
33	return NULL;
34}
35
36static bool devlink_sb_index_exists(struct devlink *devlink,
37				    unsigned int sb_index)
38{
39	return devlink_sb_get_by_index(devlink, sb_index);
40}
41
42static struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink,
43						    struct nlattr **attrs)
44{
45	if (attrs[DEVLINK_ATTR_SB_INDEX]) {
46		u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]);
47		struct devlink_sb *devlink_sb;
48
49		devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
50		if (!devlink_sb)
51			return ERR_PTR(-ENODEV);
52		return devlink_sb;
53	}
54	return ERR_PTR(-EINVAL);
55}
56
57static struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink,
58						   struct genl_info *info)
59{
60	return devlink_sb_get_from_attrs(devlink, info->attrs);
61}
62
63static int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb,
64						struct nlattr **attrs,
65						u16 *p_pool_index)
66{
67	u16 val;
68
69	if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX])
70		return -EINVAL;
71
72	val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]);
73	if (val >= devlink_sb_pool_count(devlink_sb))
74		return -EINVAL;
75	*p_pool_index = val;
76	return 0;
77}
78
79static int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb,
80					       struct genl_info *info,
81					       u16 *p_pool_index)
82{
83	return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs,
84						    p_pool_index);
85}
86
87static int
88devlink_sb_pool_type_get_from_attrs(struct nlattr **attrs,
89				    enum devlink_sb_pool_type *p_pool_type)
90{
91	u8 val;
92
93	if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE])
94		return -EINVAL;
95
96	val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]);
97	if (val != DEVLINK_SB_POOL_TYPE_INGRESS &&
98	    val != DEVLINK_SB_POOL_TYPE_EGRESS)
99		return -EINVAL;
100	*p_pool_type = val;
101	return 0;
102}
103
104static int
105devlink_sb_pool_type_get_from_info(struct genl_info *info,
106				   enum devlink_sb_pool_type *p_pool_type)
107{
108	return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type);
109}
110
111static int
112devlink_sb_th_type_get_from_attrs(struct nlattr **attrs,
113				  enum devlink_sb_threshold_type *p_th_type)
114{
115	u8 val;
116
117	if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
118		return -EINVAL;
119
120	val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]);
121	if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC &&
122	    val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC)
123		return -EINVAL;
124	*p_th_type = val;
125	return 0;
126}
127
128static int
129devlink_sb_th_type_get_from_info(struct genl_info *info,
130				 enum devlink_sb_threshold_type *p_th_type)
131{
132	return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type);
133}
134
135static int
136devlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb,
137				   struct nlattr **attrs,
138				   enum devlink_sb_pool_type pool_type,
139				   u16 *p_tc_index)
140{
141	u16 val;
142
143	if (!attrs[DEVLINK_ATTR_SB_TC_INDEX])
144		return -EINVAL;
145
146	val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]);
147	if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS &&
148	    val >= devlink_sb->ingress_tc_count)
149		return -EINVAL;
150	if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS &&
151	    val >= devlink_sb->egress_tc_count)
152		return -EINVAL;
153	*p_tc_index = val;
154	return 0;
155}
156
157static int
158devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
159				  struct genl_info *info,
160				  enum devlink_sb_pool_type pool_type,
161				  u16 *p_tc_index)
162{
163	return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs,
164						  pool_type, p_tc_index);
165}
166
167static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
168			      struct devlink_sb *devlink_sb,
169			      enum devlink_command cmd, u32 portid,
170			      u32 seq, int flags)
171{
172	void *hdr;
173
174	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
175	if (!hdr)
176		return -EMSGSIZE;
177
178	if (devlink_nl_put_handle(msg, devlink))
179		goto nla_put_failure;
180	if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
181		goto nla_put_failure;
182	if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))
183		goto nla_put_failure;
184	if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,
185			devlink_sb->ingress_pools_count))
186		goto nla_put_failure;
187	if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,
188			devlink_sb->egress_pools_count))
189		goto nla_put_failure;
190	if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,
191			devlink_sb->ingress_tc_count))
192		goto nla_put_failure;
193	if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,
194			devlink_sb->egress_tc_count))
195		goto nla_put_failure;
196
197	genlmsg_end(msg, hdr);
198	return 0;
199
200nla_put_failure:
201	genlmsg_cancel(msg, hdr);
202	return -EMSGSIZE;
203}
204
205int devlink_nl_sb_get_doit(struct sk_buff *skb, struct genl_info *info)
206{
207	struct devlink *devlink = info->user_ptr[0];
208	struct devlink_sb *devlink_sb;
209	struct sk_buff *msg;
210	int err;
211
212	devlink_sb = devlink_sb_get_from_info(devlink, info);
213	if (IS_ERR(devlink_sb))
214		return PTR_ERR(devlink_sb);
215
216	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
217	if (!msg)
218		return -ENOMEM;
219
220	err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
221				 DEVLINK_CMD_SB_NEW,
222				 info->snd_portid, info->snd_seq, 0);
223	if (err) {
224		nlmsg_free(msg);
225		return err;
226	}
227
228	return genlmsg_reply(msg, info);
229}
230
231static int
232devlink_nl_sb_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
233			   struct netlink_callback *cb, int flags)
234{
235	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
236	struct devlink_sb *devlink_sb;
237	int idx = 0;
238	int err = 0;
239
240	list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
241		if (idx < state->idx) {
242			idx++;
243			continue;
244		}
245		err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
246					 DEVLINK_CMD_SB_NEW,
247					 NETLINK_CB(cb->skb).portid,
248					 cb->nlh->nlmsg_seq, flags);
249		if (err) {
250			state->idx = idx;
251			break;
252		}
253		idx++;
254	}
255
256	return err;
257}
258
259int devlink_nl_sb_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
260{
261	return devlink_nl_dumpit(skb, cb, devlink_nl_sb_get_dump_one);
262}
263
264static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,
265				   struct devlink_sb *devlink_sb,
266				   u16 pool_index, enum devlink_command cmd,
267				   u32 portid, u32 seq, int flags)
268{
269	struct devlink_sb_pool_info pool_info;
270	void *hdr;
271	int err;
272
273	err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,
274					pool_index, &pool_info);
275	if (err)
276		return err;
277
278	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
279	if (!hdr)
280		return -EMSGSIZE;
281
282	if (devlink_nl_put_handle(msg, devlink))
283		goto nla_put_failure;
284	if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
285		goto nla_put_failure;
286	if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
287		goto nla_put_failure;
288	if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))
289		goto nla_put_failure;
290	if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))
291		goto nla_put_failure;
292	if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
293		       pool_info.threshold_type))
294		goto nla_put_failure;
295	if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
296			pool_info.cell_size))
297		goto nla_put_failure;
298
299	genlmsg_end(msg, hdr);
300	return 0;
301
302nla_put_failure:
303	genlmsg_cancel(msg, hdr);
304	return -EMSGSIZE;
305}
306
307int devlink_nl_sb_pool_get_doit(struct sk_buff *skb, struct genl_info *info)
308{
309	struct devlink *devlink = info->user_ptr[0];
310	struct devlink_sb *devlink_sb;
311	struct sk_buff *msg;
312	u16 pool_index;
313	int err;
314
315	devlink_sb = devlink_sb_get_from_info(devlink, info);
316	if (IS_ERR(devlink_sb))
317		return PTR_ERR(devlink_sb);
318
319	err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
320						  &pool_index);
321	if (err)
322		return err;
323
324	if (!devlink->ops->sb_pool_get)
325		return -EOPNOTSUPP;
326
327	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
328	if (!msg)
329		return -ENOMEM;
330
331	err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,
332				      DEVLINK_CMD_SB_POOL_NEW,
333				      info->snd_portid, info->snd_seq, 0);
334	if (err) {
335		nlmsg_free(msg);
336		return err;
337	}
338
339	return genlmsg_reply(msg, info);
340}
341
342static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
343				struct devlink *devlink,
344				struct devlink_sb *devlink_sb,
345				u32 portid, u32 seq, int flags)
346{
347	u16 pool_count = devlink_sb_pool_count(devlink_sb);
348	u16 pool_index;
349	int err;
350
351	for (pool_index = 0; pool_index < pool_count; pool_index++) {
352		if (*p_idx < start) {
353			(*p_idx)++;
354			continue;
355		}
356		err = devlink_nl_sb_pool_fill(msg, devlink,
357					      devlink_sb,
358					      pool_index,
359					      DEVLINK_CMD_SB_POOL_NEW,
360					      portid, seq, flags);
361		if (err)
362			return err;
363		(*p_idx)++;
364	}
365	return 0;
366}
367
368static int
369devlink_nl_sb_pool_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
370				struct netlink_callback *cb, int flags)
371{
372	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
373	struct devlink_sb *devlink_sb;
374	int err = 0;
375	int idx = 0;
376
377	if (!devlink->ops->sb_pool_get)
378		return 0;
379
380	list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
381		err = __sb_pool_get_dumpit(msg, state->idx, &idx,
382					   devlink, devlink_sb,
383					   NETLINK_CB(cb->skb).portid,
384					   cb->nlh->nlmsg_seq, flags);
385		if (err == -EOPNOTSUPP) {
386			err = 0;
387		} else if (err) {
388			state->idx = idx;
389			break;
390		}
391	}
392
393	return err;
394}
395
396int devlink_nl_sb_pool_get_dumpit(struct sk_buff *skb,
397				  struct netlink_callback *cb)
398{
399	return devlink_nl_dumpit(skb, cb, devlink_nl_sb_pool_get_dump_one);
400}
401
402static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
403			       u16 pool_index, u32 size,
404			       enum devlink_sb_threshold_type threshold_type,
405			       struct netlink_ext_ack *extack)
406
407{
408	const struct devlink_ops *ops = devlink->ops;
409
410	if (ops->sb_pool_set)
411		return ops->sb_pool_set(devlink, sb_index, pool_index,
412					size, threshold_type, extack);
413	return -EOPNOTSUPP;
414}
415
416int devlink_nl_sb_pool_set_doit(struct sk_buff *skb, struct genl_info *info)
417{
418	struct devlink *devlink = info->user_ptr[0];
419	enum devlink_sb_threshold_type threshold_type;
420	struct devlink_sb *devlink_sb;
421	u16 pool_index;
422	u32 size;
423	int err;
424
425	devlink_sb = devlink_sb_get_from_info(devlink, info);
426	if (IS_ERR(devlink_sb))
427		return PTR_ERR(devlink_sb);
428
429	err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
430						  &pool_index);
431	if (err)
432		return err;
433
434	err = devlink_sb_th_type_get_from_info(info, &threshold_type);
435	if (err)
436		return err;
437
438	if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_SB_POOL_SIZE))
439		return -EINVAL;
440
441	size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);
442	return devlink_sb_pool_set(devlink, devlink_sb->index,
443				   pool_index, size, threshold_type,
444				   info->extack);
445}
446
447static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,
448					struct devlink *devlink,
449					struct devlink_port *devlink_port,
450					struct devlink_sb *devlink_sb,
451					u16 pool_index,
452					enum devlink_command cmd,
453					u32 portid, u32 seq, int flags)
454{
455	const struct devlink_ops *ops = devlink->ops;
456	u32 threshold;
457	void *hdr;
458	int err;
459
460	err = ops->sb_port_pool_get(devlink_port, devlink_sb->index,
461				    pool_index, &threshold);
462	if (err)
463		return err;
464
465	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
466	if (!hdr)
467		return -EMSGSIZE;
468
469	if (devlink_nl_put_handle(msg, devlink))
470		goto nla_put_failure;
471	if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
472		goto nla_put_failure;
473	if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
474		goto nla_put_failure;
475	if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
476		goto nla_put_failure;
477	if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
478		goto nla_put_failure;
479
480	if (ops->sb_occ_port_pool_get) {
481		u32 cur;
482		u32 max;
483
484		err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,
485						pool_index, &cur, &max);
486		if (err && err != -EOPNOTSUPP)
487			goto sb_occ_get_failure;
488		if (!err) {
489			if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
490				goto nla_put_failure;
491			if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
492				goto nla_put_failure;
493		}
494	}
495
496	genlmsg_end(msg, hdr);
497	return 0;
498
499nla_put_failure:
500	err = -EMSGSIZE;
501sb_occ_get_failure:
502	genlmsg_cancel(msg, hdr);
503	return err;
504}
505
506int devlink_nl_sb_port_pool_get_doit(struct sk_buff *skb,
507				     struct genl_info *info)
508{
509	struct devlink_port *devlink_port = info->user_ptr[1];
510	struct devlink *devlink = devlink_port->devlink;
511	struct devlink_sb *devlink_sb;
512	struct sk_buff *msg;
513	u16 pool_index;
514	int err;
515
516	devlink_sb = devlink_sb_get_from_info(devlink, info);
517	if (IS_ERR(devlink_sb))
518		return PTR_ERR(devlink_sb);
519
520	err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
521						  &pool_index);
522	if (err)
523		return err;
524
525	if (!devlink->ops->sb_port_pool_get)
526		return -EOPNOTSUPP;
527
528	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
529	if (!msg)
530		return -ENOMEM;
531
532	err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port,
533					   devlink_sb, pool_index,
534					   DEVLINK_CMD_SB_PORT_POOL_NEW,
535					   info->snd_portid, info->snd_seq, 0);
536	if (err) {
537		nlmsg_free(msg);
538		return err;
539	}
540
541	return genlmsg_reply(msg, info);
542}
543
544static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
545				     struct devlink *devlink,
546				     struct devlink_sb *devlink_sb,
547				     u32 portid, u32 seq, int flags)
548{
549	struct devlink_port *devlink_port;
550	u16 pool_count = devlink_sb_pool_count(devlink_sb);
551	unsigned long port_index;
552	u16 pool_index;
553	int err;
554
555	xa_for_each(&devlink->ports, port_index, devlink_port) {
556		for (pool_index = 0; pool_index < pool_count; pool_index++) {
557			if (*p_idx < start) {
558				(*p_idx)++;
559				continue;
560			}
561			err = devlink_nl_sb_port_pool_fill(msg, devlink,
562							   devlink_port,
563							   devlink_sb,
564							   pool_index,
565							   DEVLINK_CMD_SB_PORT_POOL_NEW,
566							   portid, seq, flags);
567			if (err)
568				return err;
569			(*p_idx)++;
570		}
571	}
572	return 0;
573}
574
575static int
576devlink_nl_sb_port_pool_get_dump_one(struct sk_buff *msg,
577				     struct devlink *devlink,
578				     struct netlink_callback *cb, int flags)
579{
580	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
581	struct devlink_sb *devlink_sb;
582	int idx = 0;
583	int err = 0;
584
585	if (!devlink->ops->sb_port_pool_get)
586		return 0;
587
588	list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
589		err = __sb_port_pool_get_dumpit(msg, state->idx, &idx,
590						devlink, devlink_sb,
591						NETLINK_CB(cb->skb).portid,
592						cb->nlh->nlmsg_seq, flags);
593		if (err == -EOPNOTSUPP) {
594			err = 0;
595		} else if (err) {
596			state->idx = idx;
597			break;
598		}
599	}
600
601	return err;
602}
603
604int devlink_nl_sb_port_pool_get_dumpit(struct sk_buff *skb,
605				       struct netlink_callback *cb)
606{
607	return devlink_nl_dumpit(skb, cb, devlink_nl_sb_port_pool_get_dump_one);
608}
609
610static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
611				    unsigned int sb_index, u16 pool_index,
612				    u32 threshold,
613				    struct netlink_ext_ack *extack)
614
615{
616	const struct devlink_ops *ops = devlink_port->devlink->ops;
617
618	if (ops->sb_port_pool_set)
619		return ops->sb_port_pool_set(devlink_port, sb_index,
620					     pool_index, threshold, extack);
621	return -EOPNOTSUPP;
622}
623
624int devlink_nl_sb_port_pool_set_doit(struct sk_buff *skb,
625				     struct genl_info *info)
626{
627	struct devlink_port *devlink_port = info->user_ptr[1];
628	struct devlink *devlink = info->user_ptr[0];
629	struct devlink_sb *devlink_sb;
630	u16 pool_index;
631	u32 threshold;
632	int err;
633
634	devlink_sb = devlink_sb_get_from_info(devlink, info);
635	if (IS_ERR(devlink_sb))
636		return PTR_ERR(devlink_sb);
637
638	err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
639						  &pool_index);
640	if (err)
641		return err;
642
643	if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_SB_THRESHOLD))
644		return -EINVAL;
645
646	threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
647	return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
648					pool_index, threshold, info->extack);
649}
650
651static int
652devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink,
653				struct devlink_port *devlink_port,
654				struct devlink_sb *devlink_sb, u16 tc_index,
655				enum devlink_sb_pool_type pool_type,
656				enum devlink_command cmd,
657				u32 portid, u32 seq, int flags)
658{
659	const struct devlink_ops *ops = devlink->ops;
660	u16 pool_index;
661	u32 threshold;
662	void *hdr;
663	int err;
664
665	err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index,
666				       tc_index, pool_type,
667				       &pool_index, &threshold);
668	if (err)
669		return err;
670
671	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
672	if (!hdr)
673		return -EMSGSIZE;
674
675	if (devlink_nl_put_handle(msg, devlink))
676		goto nla_put_failure;
677	if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
678		goto nla_put_failure;
679	if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
680		goto nla_put_failure;
681	if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index))
682		goto nla_put_failure;
683	if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type))
684		goto nla_put_failure;
685	if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
686		goto nla_put_failure;
687	if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
688		goto nla_put_failure;
689
690	if (ops->sb_occ_tc_port_bind_get) {
691		u32 cur;
692		u32 max;
693
694		err = ops->sb_occ_tc_port_bind_get(devlink_port,
695						   devlink_sb->index,
696						   tc_index, pool_type,
697						   &cur, &max);
698		if (err && err != -EOPNOTSUPP)
699			return err;
700		if (!err) {
701			if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
702				goto nla_put_failure;
703			if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
704				goto nla_put_failure;
705		}
706	}
707
708	genlmsg_end(msg, hdr);
709	return 0;
710
711nla_put_failure:
712	genlmsg_cancel(msg, hdr);
713	return -EMSGSIZE;
714}
715
716int devlink_nl_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
717					struct genl_info *info)
718{
719	struct devlink_port *devlink_port = info->user_ptr[1];
720	struct devlink *devlink = devlink_port->devlink;
721	struct devlink_sb *devlink_sb;
722	struct sk_buff *msg;
723	enum devlink_sb_pool_type pool_type;
724	u16 tc_index;
725	int err;
726
727	devlink_sb = devlink_sb_get_from_info(devlink, info);
728	if (IS_ERR(devlink_sb))
729		return PTR_ERR(devlink_sb);
730
731	err = devlink_sb_pool_type_get_from_info(info, &pool_type);
732	if (err)
733		return err;
734
735	err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
736						pool_type, &tc_index);
737	if (err)
738		return err;
739
740	if (!devlink->ops->sb_tc_pool_bind_get)
741		return -EOPNOTSUPP;
742
743	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
744	if (!msg)
745		return -ENOMEM;
746
747	err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port,
748					      devlink_sb, tc_index, pool_type,
749					      DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
750					      info->snd_portid,
751					      info->snd_seq, 0);
752	if (err) {
753		nlmsg_free(msg);
754		return err;
755	}
756
757	return genlmsg_reply(msg, info);
758}
759
760static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
761					int start, int *p_idx,
762					struct devlink *devlink,
763					struct devlink_sb *devlink_sb,
764					u32 portid, u32 seq, int flags)
765{
766	struct devlink_port *devlink_port;
767	unsigned long port_index;
768	u16 tc_index;
769	int err;
770
771	xa_for_each(&devlink->ports, port_index, devlink_port) {
772		for (tc_index = 0;
773		     tc_index < devlink_sb->ingress_tc_count; tc_index++) {
774			if (*p_idx < start) {
775				(*p_idx)++;
776				continue;
777			}
778			err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
779							      devlink_port,
780							      devlink_sb,
781							      tc_index,
782							      DEVLINK_SB_POOL_TYPE_INGRESS,
783							      DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
784							      portid, seq,
785							      flags);
786			if (err)
787				return err;
788			(*p_idx)++;
789		}
790		for (tc_index = 0;
791		     tc_index < devlink_sb->egress_tc_count; tc_index++) {
792			if (*p_idx < start) {
793				(*p_idx)++;
794				continue;
795			}
796			err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
797							      devlink_port,
798							      devlink_sb,
799							      tc_index,
800							      DEVLINK_SB_POOL_TYPE_EGRESS,
801							      DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
802							      portid, seq,
803							      flags);
804			if (err)
805				return err;
806			(*p_idx)++;
807		}
808	}
809	return 0;
810}
811
812static int devlink_nl_sb_tc_pool_bind_get_dump_one(struct sk_buff *msg,
813						   struct devlink *devlink,
814						   struct netlink_callback *cb,
815						   int flags)
816{
817	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
818	struct devlink_sb *devlink_sb;
819	int idx = 0;
820	int err = 0;
821
822	if (!devlink->ops->sb_tc_pool_bind_get)
823		return 0;
824
825	list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
826		err = __sb_tc_pool_bind_get_dumpit(msg, state->idx, &idx,
827						   devlink, devlink_sb,
828						   NETLINK_CB(cb->skb).portid,
829						   cb->nlh->nlmsg_seq, flags);
830		if (err == -EOPNOTSUPP) {
831			err = 0;
832		} else if (err) {
833			state->idx = idx;
834			break;
835		}
836	}
837
838	return err;
839}
840
841int devlink_nl_sb_tc_pool_bind_get_dumpit(struct sk_buff *skb,
842					  struct netlink_callback *cb)
843{
844	return devlink_nl_dumpit(skb, cb,
845				 devlink_nl_sb_tc_pool_bind_get_dump_one);
846}
847
848static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
849				       unsigned int sb_index, u16 tc_index,
850				       enum devlink_sb_pool_type pool_type,
851				       u16 pool_index, u32 threshold,
852				       struct netlink_ext_ack *extack)
853
854{
855	const struct devlink_ops *ops = devlink_port->devlink->ops;
856
857	if (ops->sb_tc_pool_bind_set)
858		return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
859						tc_index, pool_type,
860						pool_index, threshold, extack);
861	return -EOPNOTSUPP;
862}
863
864int devlink_nl_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
865					struct genl_info *info)
866{
867	struct devlink_port *devlink_port = info->user_ptr[1];
868	struct devlink *devlink = info->user_ptr[0];
869	enum devlink_sb_pool_type pool_type;
870	struct devlink_sb *devlink_sb;
871	u16 tc_index;
872	u16 pool_index;
873	u32 threshold;
874	int err;
875
876	devlink_sb = devlink_sb_get_from_info(devlink, info);
877	if (IS_ERR(devlink_sb))
878		return PTR_ERR(devlink_sb);
879
880	err = devlink_sb_pool_type_get_from_info(info, &pool_type);
881	if (err)
882		return err;
883
884	err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
885						pool_type, &tc_index);
886	if (err)
887		return err;
888
889	err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
890						  &pool_index);
891	if (err)
892		return err;
893
894	if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_SB_THRESHOLD))
895		return -EINVAL;
896
897	threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
898	return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
899					   tc_index, pool_type,
900					   pool_index, threshold, info->extack);
901}
902
903int devlink_nl_sb_occ_snapshot_doit(struct sk_buff *skb, struct genl_info *info)
904{
905	struct devlink *devlink = info->user_ptr[0];
906	const struct devlink_ops *ops = devlink->ops;
907	struct devlink_sb *devlink_sb;
908
909	devlink_sb = devlink_sb_get_from_info(devlink, info);
910	if (IS_ERR(devlink_sb))
911		return PTR_ERR(devlink_sb);
912
913	if (ops->sb_occ_snapshot)
914		return ops->sb_occ_snapshot(devlink, devlink_sb->index);
915	return -EOPNOTSUPP;
916}
917
918int devlink_nl_sb_occ_max_clear_doit(struct sk_buff *skb,
919				     struct genl_info *info)
920{
921	struct devlink *devlink = info->user_ptr[0];
922	const struct devlink_ops *ops = devlink->ops;
923	struct devlink_sb *devlink_sb;
924
925	devlink_sb = devlink_sb_get_from_info(devlink, info);
926	if (IS_ERR(devlink_sb))
927		return PTR_ERR(devlink_sb);
928
929	if (ops->sb_occ_max_clear)
930		return ops->sb_occ_max_clear(devlink, devlink_sb->index);
931	return -EOPNOTSUPP;
932}
933
934int devl_sb_register(struct devlink *devlink, unsigned int sb_index,
935		     u32 size, u16 ingress_pools_count,
936		     u16 egress_pools_count, u16 ingress_tc_count,
937		     u16 egress_tc_count)
938{
939	struct devlink_sb *devlink_sb;
940
941	lockdep_assert_held(&devlink->lock);
942
943	if (devlink_sb_index_exists(devlink, sb_index))
944		return -EEXIST;
945
946	devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
947	if (!devlink_sb)
948		return -ENOMEM;
949	devlink_sb->index = sb_index;
950	devlink_sb->size = size;
951	devlink_sb->ingress_pools_count = ingress_pools_count;
952	devlink_sb->egress_pools_count = egress_pools_count;
953	devlink_sb->ingress_tc_count = ingress_tc_count;
954	devlink_sb->egress_tc_count = egress_tc_count;
955	list_add_tail(&devlink_sb->list, &devlink->sb_list);
956	return 0;
957}
958EXPORT_SYMBOL_GPL(devl_sb_register);
959
960int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
961			u32 size, u16 ingress_pools_count,
962			u16 egress_pools_count, u16 ingress_tc_count,
963			u16 egress_tc_count)
964{
965	int err;
966
967	devl_lock(devlink);
968	err = devl_sb_register(devlink, sb_index, size, ingress_pools_count,
969			       egress_pools_count, ingress_tc_count,
970			       egress_tc_count);
971	devl_unlock(devlink);
972	return err;
973}
974EXPORT_SYMBOL_GPL(devlink_sb_register);
975
976void devl_sb_unregister(struct devlink *devlink, unsigned int sb_index)
977{
978	struct devlink_sb *devlink_sb;
979
980	lockdep_assert_held(&devlink->lock);
981
982	devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
983	WARN_ON(!devlink_sb);
984	list_del(&devlink_sb->list);
985	kfree(devlink_sb);
986}
987EXPORT_SYMBOL_GPL(devl_sb_unregister);
988
989void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
990{
991	devl_lock(devlink);
992	devl_sb_unregister(devlink, sb_index);
993	devl_unlock(devlink);
994}
995EXPORT_SYMBOL_GPL(devlink_sb_unregister);
996