net: devlink: extend port attrs for switch ID
[linux-2.6-block.git] / net / core / devlink.c
CommitLineData
bfcd3a46
JP
1/*
2 * net/core/devlink.c - Network physical/parent device Netlink interface
3 *
4 * Heavily inspired by net/wireless/
5 * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
6 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/types.h>
17#include <linux/slab.h>
18#include <linux/gfp.h>
19#include <linux/device.h>
20#include <linux/list.h>
21#include <linux/netdevice.h>
b8f97554 22#include <linux/spinlock.h>
bfcd3a46
JP
23#include <rdma/ib_verbs.h>
24#include <net/netlink.h>
25#include <net/genetlink.h>
26#include <net/rtnetlink.h>
27#include <net/net_namespace.h>
28#include <net/sock.h>
29#include <net/devlink.h>
e5224f0f
JP
30#define CREATE_TRACE_POINTS
31#include <trace/events/devlink.h>
32
11770091
AS
33static struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = {
34 {
12bdc5e1 35 .name = "destination mac",
11770091
AS
36 .id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
37 .bitwidth = 48,
38 },
39};
40
41struct devlink_dpipe_header devlink_dpipe_header_ethernet = {
42 .name = "ethernet",
43 .id = DEVLINK_DPIPE_HEADER_ETHERNET,
44 .fields = devlink_dpipe_fields_ethernet,
45 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ethernet),
46 .global = true,
47};
48EXPORT_SYMBOL(devlink_dpipe_header_ethernet);
49
3fb886ec
AS
50static struct devlink_dpipe_field devlink_dpipe_fields_ipv4[] = {
51 {
52 .name = "destination ip",
53 .id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
54 .bitwidth = 32,
55 },
56};
57
58struct devlink_dpipe_header devlink_dpipe_header_ipv4 = {
59 .name = "ipv4",
60 .id = DEVLINK_DPIPE_HEADER_IPV4,
61 .fields = devlink_dpipe_fields_ipv4,
62 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv4),
63 .global = true,
64};
65EXPORT_SYMBOL(devlink_dpipe_header_ipv4);
66
1797f5b3
AS
67static struct devlink_dpipe_field devlink_dpipe_fields_ipv6[] = {
68 {
69 .name = "destination ip",
70 .id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
71 .bitwidth = 128,
72 },
73};
74
75struct devlink_dpipe_header devlink_dpipe_header_ipv6 = {
76 .name = "ipv6",
77 .id = DEVLINK_DPIPE_HEADER_IPV6,
78 .fields = devlink_dpipe_fields_ipv6,
79 .fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv6),
80 .global = true,
81};
82EXPORT_SYMBOL(devlink_dpipe_header_ipv6);
83
e5224f0f 84EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg);
57186a5f 85EXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwerr);
bfcd3a46
JP
86
87static LIST_HEAD(devlink_list);
88
89/* devlink_mutex
90 *
91 * An overall lock guarding every operation coming from userspace.
92 * It also guards devlink devices list and it is taken when
93 * driver registers/unregisters it.
94 */
95static DEFINE_MUTEX(devlink_mutex);
96
bfcd3a46
JP
97static struct net *devlink_net(const struct devlink *devlink)
98{
99 return read_pnet(&devlink->_net);
100}
101
102static void devlink_net_set(struct devlink *devlink, struct net *net)
103{
104 write_pnet(&devlink->_net, net);
105}
106
107static struct devlink *devlink_get_from_attrs(struct net *net,
108 struct nlattr **attrs)
109{
110 struct devlink *devlink;
111 char *busname;
112 char *devname;
113
114 if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
115 return ERR_PTR(-EINVAL);
116
117 busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
118 devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
119
dac7c08f
PP
120 lockdep_assert_held(&devlink_mutex);
121
bfcd3a46
JP
122 list_for_each_entry(devlink, &devlink_list, list) {
123 if (strcmp(devlink->dev->bus->name, busname) == 0 &&
124 strcmp(dev_name(devlink->dev), devname) == 0 &&
125 net_eq(devlink_net(devlink), net))
126 return devlink;
127 }
128
129 return ERR_PTR(-ENODEV);
130}
131
132static struct devlink *devlink_get_from_info(struct genl_info *info)
133{
134 return devlink_get_from_attrs(genl_info_net(info), info->attrs);
135}
136
137static struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
138 int port_index)
139{
140 struct devlink_port *devlink_port;
141
142 list_for_each_entry(devlink_port, &devlink->port_list, list) {
143 if (devlink_port->index == port_index)
144 return devlink_port;
145 }
146 return NULL;
147}
148
149static bool devlink_port_index_exists(struct devlink *devlink, int port_index)
150{
151 return devlink_port_get_by_index(devlink, port_index);
152}
153
154static struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink,
155 struct nlattr **attrs)
156{
157 if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
158 u32 port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
159 struct devlink_port *devlink_port;
160
161 devlink_port = devlink_port_get_by_index(devlink, port_index);
162 if (!devlink_port)
163 return ERR_PTR(-ENODEV);
164 return devlink_port;
165 }
166 return ERR_PTR(-EINVAL);
167}
168
169static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink,
170 struct genl_info *info)
171{
172 return devlink_port_get_from_attrs(devlink, info->attrs);
173}
174
bf797471
JP
175struct devlink_sb {
176 struct list_head list;
177 unsigned int index;
178 u32 size;
179 u16 ingress_pools_count;
180 u16 egress_pools_count;
181 u16 ingress_tc_count;
182 u16 egress_tc_count;
183};
184
185static u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb)
186{
187 return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count;
188}
189
190static struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink,
191 unsigned int sb_index)
192{
193 struct devlink_sb *devlink_sb;
194
195 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
196 if (devlink_sb->index == sb_index)
197 return devlink_sb;
198 }
199 return NULL;
200}
201
202static bool devlink_sb_index_exists(struct devlink *devlink,
203 unsigned int sb_index)
204{
205 return devlink_sb_get_by_index(devlink, sb_index);
206}
207
208static struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink,
209 struct nlattr **attrs)
210{
211 if (attrs[DEVLINK_ATTR_SB_INDEX]) {
212 u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]);
213 struct devlink_sb *devlink_sb;
214
215 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
216 if (!devlink_sb)
217 return ERR_PTR(-ENODEV);
218 return devlink_sb;
219 }
220 return ERR_PTR(-EINVAL);
221}
222
223static struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink,
224 struct genl_info *info)
225{
226 return devlink_sb_get_from_attrs(devlink, info->attrs);
227}
228
229static int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb,
230 struct nlattr **attrs,
231 u16 *p_pool_index)
232{
233 u16 val;
234
235 if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX])
236 return -EINVAL;
237
238 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]);
239 if (val >= devlink_sb_pool_count(devlink_sb))
240 return -EINVAL;
241 *p_pool_index = val;
242 return 0;
243}
244
245static int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb,
246 struct genl_info *info,
247 u16 *p_pool_index)
248{
249 return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs,
250 p_pool_index);
251}
252
253static int
254devlink_sb_pool_type_get_from_attrs(struct nlattr **attrs,
255 enum devlink_sb_pool_type *p_pool_type)
256{
257 u8 val;
258
259 if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE])
260 return -EINVAL;
261
262 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]);
263 if (val != DEVLINK_SB_POOL_TYPE_INGRESS &&
264 val != DEVLINK_SB_POOL_TYPE_EGRESS)
265 return -EINVAL;
266 *p_pool_type = val;
267 return 0;
268}
269
270static int
271devlink_sb_pool_type_get_from_info(struct genl_info *info,
272 enum devlink_sb_pool_type *p_pool_type)
273{
274 return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type);
275}
276
277static int
278devlink_sb_th_type_get_from_attrs(struct nlattr **attrs,
279 enum devlink_sb_threshold_type *p_th_type)
280{
281 u8 val;
282
283 if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
284 return -EINVAL;
285
286 val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]);
287 if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC &&
288 val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC)
289 return -EINVAL;
290 *p_th_type = val;
291 return 0;
292}
293
294static int
295devlink_sb_th_type_get_from_info(struct genl_info *info,
296 enum devlink_sb_threshold_type *p_th_type)
297{
298 return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type);
299}
300
301static int
302devlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb,
303 struct nlattr **attrs,
304 enum devlink_sb_pool_type pool_type,
305 u16 *p_tc_index)
306{
307 u16 val;
308
309 if (!attrs[DEVLINK_ATTR_SB_TC_INDEX])
310 return -EINVAL;
311
312 val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]);
313 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS &&
314 val >= devlink_sb->ingress_tc_count)
315 return -EINVAL;
316 if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS &&
317 val >= devlink_sb->egress_tc_count)
318 return -EINVAL;
319 *p_tc_index = val;
320 return 0;
321}
322
323static int
324devlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
325 struct genl_info *info,
326 enum devlink_sb_pool_type pool_type,
327 u16 *p_tc_index)
328{
329 return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs,
330 pool_type, p_tc_index);
331}
332
b16ebe92
AV
333struct devlink_region {
334 struct devlink *devlink;
335 struct list_head list;
336 const char *name;
337 struct list_head snapshot_list;
338 u32 max_snapshots;
339 u32 cur_snapshots;
340 u64 size;
341};
342
d7e52722
AV
343struct devlink_snapshot {
344 struct list_head list;
345 struct devlink_region *region;
346 devlink_snapshot_data_dest_t *data_destructor;
347 u64 data_len;
348 u8 *data;
349 u32 id;
350};
351
b16ebe92
AV
352static struct devlink_region *
353devlink_region_get_by_name(struct devlink *devlink, const char *region_name)
354{
355 struct devlink_region *region;
356
357 list_for_each_entry(region, &devlink->region_list, list)
358 if (!strcmp(region->name, region_name))
359 return region;
360
361 return NULL;
362}
363
d7e52722
AV
364static struct devlink_snapshot *
365devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
366{
367 struct devlink_snapshot *snapshot;
368
369 list_for_each_entry(snapshot, &region->snapshot_list, list)
370 if (snapshot->id == id)
371 return snapshot;
372
373 return NULL;
374}
375
376static void devlink_region_snapshot_del(struct devlink_snapshot *snapshot)
377{
378 snapshot->region->cur_snapshots--;
379 list_del(&snapshot->list);
380 (*snapshot->data_destructor)(snapshot->data);
381 kfree(snapshot);
382}
383
1fc2257e
JP
384#define DEVLINK_NL_FLAG_NEED_DEVLINK BIT(0)
385#define DEVLINK_NL_FLAG_NEED_PORT BIT(1)
bf797471 386#define DEVLINK_NL_FLAG_NEED_SB BIT(2)
2406e7e5
AS
387
388/* The per devlink instance lock is taken by default in the pre-doit
389 * operation, yet several commands do not require this. The global
390 * devlink lock is taken and protects from disruption by user-calls.
391 */
392#define DEVLINK_NL_FLAG_NO_LOCK BIT(3)
bfcd3a46
JP
393
394static int devlink_nl_pre_doit(const struct genl_ops *ops,
395 struct sk_buff *skb, struct genl_info *info)
396{
397 struct devlink *devlink;
2406e7e5 398 int err;
bfcd3a46
JP
399
400 mutex_lock(&devlink_mutex);
401 devlink = devlink_get_from_info(info);
402 if (IS_ERR(devlink)) {
403 mutex_unlock(&devlink_mutex);
404 return PTR_ERR(devlink);
405 }
2406e7e5
AS
406 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
407 mutex_lock(&devlink->lock);
1fc2257e
JP
408 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK) {
409 info->user_ptr[0] = devlink;
410 } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
bfcd3a46
JP
411 struct devlink_port *devlink_port;
412
bfcd3a46
JP
413 devlink_port = devlink_port_get_from_info(devlink, info);
414 if (IS_ERR(devlink_port)) {
2406e7e5
AS
415 err = PTR_ERR(devlink_port);
416 goto unlock;
bfcd3a46 417 }
1fc2257e 418 info->user_ptr[0] = devlink_port;
bfcd3a46 419 }
bf797471
JP
420 if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_SB) {
421 struct devlink_sb *devlink_sb;
422
423 devlink_sb = devlink_sb_get_from_info(devlink, info);
424 if (IS_ERR(devlink_sb)) {
2406e7e5
AS
425 err = PTR_ERR(devlink_sb);
426 goto unlock;
bf797471
JP
427 }
428 info->user_ptr[1] = devlink_sb;
429 }
bfcd3a46 430 return 0;
2406e7e5
AS
431
432unlock:
433 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
434 mutex_unlock(&devlink->lock);
435 mutex_unlock(&devlink_mutex);
436 return err;
bfcd3a46
JP
437}
438
439static void devlink_nl_post_doit(const struct genl_ops *ops,
440 struct sk_buff *skb, struct genl_info *info)
441{
2406e7e5
AS
442 struct devlink *devlink;
443
444 devlink = devlink_get_from_info(info);
445 if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
446 mutex_unlock(&devlink->lock);
bfcd3a46
JP
447 mutex_unlock(&devlink_mutex);
448}
449
489111e5 450static struct genl_family devlink_nl_family;
bfcd3a46
JP
451
452enum devlink_multicast_groups {
453 DEVLINK_MCGRP_CONFIG,
454};
455
456static const struct genl_multicast_group devlink_nl_mcgrps[] = {
457 [DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
458};
459
460static int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
461{
462 if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name))
463 return -EMSGSIZE;
464 if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev)))
465 return -EMSGSIZE;
466 return 0;
467}
468
469static int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
470 enum devlink_command cmd, u32 portid,
471 u32 seq, int flags)
472{
473 void *hdr;
474
475 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
476 if (!hdr)
477 return -EMSGSIZE;
478
479 if (devlink_nl_put_handle(msg, devlink))
480 goto nla_put_failure;
481
482 genlmsg_end(msg, hdr);
483 return 0;
484
485nla_put_failure:
486 genlmsg_cancel(msg, hdr);
487 return -EMSGSIZE;
488}
489
490static void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
491{
492 struct sk_buff *msg;
493 int err;
494
495 WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL);
496
497 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
498 if (!msg)
499 return;
500
501 err = devlink_nl_fill(msg, devlink, cmd, 0, 0, 0);
502 if (err) {
503 nlmsg_free(msg);
504 return;
505 }
506
507 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
508 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
509}
510
b9ffcbaf
JP
511static int devlink_nl_port_attrs_put(struct sk_buff *msg,
512 struct devlink_port *devlink_port)
513{
514 struct devlink_port_attrs *attrs = &devlink_port->attrs;
515
516 if (!attrs->set)
517 return 0;
5ec1380a
JP
518 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
519 return -EMSGSIZE;
b9ffcbaf
JP
520 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER, attrs->port_number))
521 return -EMSGSIZE;
522 if (!attrs->split)
523 return 0;
524 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP, attrs->port_number))
525 return -EMSGSIZE;
526 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
527 attrs->split_subport_number))
528 return -EMSGSIZE;
529 return 0;
530}
531
bfcd3a46
JP
532static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
533 struct devlink_port *devlink_port,
534 enum devlink_command cmd, u32 portid,
535 u32 seq, int flags)
536{
537 void *hdr;
538
539 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
540 if (!hdr)
541 return -EMSGSIZE;
542
543 if (devlink_nl_put_handle(msg, devlink))
544 goto nla_put_failure;
545 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
546 goto nla_put_failure;
b8f97554
JP
547
548 spin_lock(&devlink_port->type_lock);
bfcd3a46 549 if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
b8f97554 550 goto nla_put_failure_type_locked;
bfcd3a46
JP
551 if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
552 nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
553 devlink_port->desired_type))
b8f97554 554 goto nla_put_failure_type_locked;
bfcd3a46
JP
555 if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
556 struct net_device *netdev = devlink_port->type_dev;
557
558 if (netdev &&
559 (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
560 netdev->ifindex) ||
561 nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
562 netdev->name)))
b8f97554 563 goto nla_put_failure_type_locked;
bfcd3a46
JP
564 }
565 if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
566 struct ib_device *ibdev = devlink_port->type_dev;
567
568 if (ibdev &&
569 nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
570 ibdev->name))
b8f97554 571 goto nla_put_failure_type_locked;
bfcd3a46 572 }
b8f97554 573 spin_unlock(&devlink_port->type_lock);
b9ffcbaf 574 if (devlink_nl_port_attrs_put(msg, devlink_port))
bfcd3a46
JP
575 goto nla_put_failure;
576
577 genlmsg_end(msg, hdr);
578 return 0;
579
b8f97554
JP
580nla_put_failure_type_locked:
581 spin_unlock(&devlink_port->type_lock);
bfcd3a46
JP
582nla_put_failure:
583 genlmsg_cancel(msg, hdr);
584 return -EMSGSIZE;
585}
586
587static void devlink_port_notify(struct devlink_port *devlink_port,
588 enum devlink_command cmd)
589{
590 struct devlink *devlink = devlink_port->devlink;
591 struct sk_buff *msg;
592 int err;
593
594 if (!devlink_port->registered)
595 return;
596
597 WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);
598
599 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
600 if (!msg)
601 return;
602
603 err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0);
604 if (err) {
605 nlmsg_free(msg);
606 return;
607 }
608
609 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
610 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
611}
612
613static int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
614{
615 struct devlink *devlink = info->user_ptr[0];
616 struct sk_buff *msg;
617 int err;
618
619 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
620 if (!msg)
621 return -ENOMEM;
622
623 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
624 info->snd_portid, info->snd_seq, 0);
625 if (err) {
626 nlmsg_free(msg);
627 return err;
628 }
629
630 return genlmsg_reply(msg, info);
631}
632
633static int devlink_nl_cmd_get_dumpit(struct sk_buff *msg,
634 struct netlink_callback *cb)
635{
636 struct devlink *devlink;
637 int start = cb->args[0];
638 int idx = 0;
639 int err;
640
641 mutex_lock(&devlink_mutex);
642 list_for_each_entry(devlink, &devlink_list, list) {
643 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
644 continue;
645 if (idx < start) {
646 idx++;
647 continue;
648 }
649 err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
650 NETLINK_CB(cb->skb).portid,
651 cb->nlh->nlmsg_seq, NLM_F_MULTI);
652 if (err)
653 goto out;
654 idx++;
655 }
656out:
657 mutex_unlock(&devlink_mutex);
658
659 cb->args[0] = idx;
660 return msg->len;
661}
662
663static int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
664 struct genl_info *info)
665{
1fc2257e
JP
666 struct devlink_port *devlink_port = info->user_ptr[0];
667 struct devlink *devlink = devlink_port->devlink;
bfcd3a46
JP
668 struct sk_buff *msg;
669 int err;
670
671 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
672 if (!msg)
673 return -ENOMEM;
674
675 err = devlink_nl_port_fill(msg, devlink, devlink_port,
676 DEVLINK_CMD_PORT_NEW,
677 info->snd_portid, info->snd_seq, 0);
678 if (err) {
679 nlmsg_free(msg);
680 return err;
681 }
682
683 return genlmsg_reply(msg, info);
684}
685
686static int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
687 struct netlink_callback *cb)
688{
689 struct devlink *devlink;
690 struct devlink_port *devlink_port;
691 int start = cb->args[0];
692 int idx = 0;
693 int err;
694
695 mutex_lock(&devlink_mutex);
bfcd3a46
JP
696 list_for_each_entry(devlink, &devlink_list, list) {
697 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
698 continue;
2406e7e5 699 mutex_lock(&devlink->lock);
bfcd3a46
JP
700 list_for_each_entry(devlink_port, &devlink->port_list, list) {
701 if (idx < start) {
702 idx++;
703 continue;
704 }
705 err = devlink_nl_port_fill(msg, devlink, devlink_port,
706 DEVLINK_CMD_NEW,
707 NETLINK_CB(cb->skb).portid,
708 cb->nlh->nlmsg_seq,
709 NLM_F_MULTI);
2406e7e5
AS
710 if (err) {
711 mutex_unlock(&devlink->lock);
bfcd3a46 712 goto out;
2406e7e5 713 }
bfcd3a46
JP
714 idx++;
715 }
2406e7e5 716 mutex_unlock(&devlink->lock);
bfcd3a46
JP
717 }
718out:
bfcd3a46
JP
719 mutex_unlock(&devlink_mutex);
720
721 cb->args[0] = idx;
722 return msg->len;
723}
724
725static int devlink_port_type_set(struct devlink *devlink,
726 struct devlink_port *devlink_port,
727 enum devlink_port_type port_type)
728
729{
730 int err;
731
be6fe1d8 732 if (devlink->ops->port_type_set) {
bfcd3a46
JP
733 if (port_type == DEVLINK_PORT_TYPE_NOTSET)
734 return -EINVAL;
6edf1017
ER
735 if (port_type == devlink_port->type)
736 return 0;
bfcd3a46
JP
737 err = devlink->ops->port_type_set(devlink_port, port_type);
738 if (err)
739 return err;
740 devlink_port->desired_type = port_type;
741 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
742 return 0;
743 }
744 return -EOPNOTSUPP;
745}
746
747static int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
748 struct genl_info *info)
749{
1fc2257e
JP
750 struct devlink_port *devlink_port = info->user_ptr[0];
751 struct devlink *devlink = devlink_port->devlink;
bfcd3a46
JP
752 int err;
753
754 if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
755 enum devlink_port_type port_type;
756
757 port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]);
758 err = devlink_port_type_set(devlink, devlink_port, port_type);
759 if (err)
760 return err;
761 }
762 return 0;
763}
764
ac0fc8a1
DA
765static int devlink_port_split(struct devlink *devlink, u32 port_index,
766 u32 count, struct netlink_ext_ack *extack)
bfcd3a46
JP
767
768{
be6fe1d8 769 if (devlink->ops->port_split)
ac0fc8a1
DA
770 return devlink->ops->port_split(devlink, port_index, count,
771 extack);
bfcd3a46
JP
772 return -EOPNOTSUPP;
773}
774
775static int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
776 struct genl_info *info)
777{
778 struct devlink *devlink = info->user_ptr[0];
779 u32 port_index;
780 u32 count;
781
782 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX] ||
783 !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT])
784 return -EINVAL;
785
786 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
787 count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
ac0fc8a1 788 return devlink_port_split(devlink, port_index, count, info->extack);
bfcd3a46
JP
789}
790
ac0fc8a1
DA
791static int devlink_port_unsplit(struct devlink *devlink, u32 port_index,
792 struct netlink_ext_ack *extack)
bfcd3a46
JP
793
794{
be6fe1d8 795 if (devlink->ops->port_unsplit)
ac0fc8a1 796 return devlink->ops->port_unsplit(devlink, port_index, extack);
bfcd3a46
JP
797 return -EOPNOTSUPP;
798}
799
800static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
801 struct genl_info *info)
802{
803 struct devlink *devlink = info->user_ptr[0];
804 u32 port_index;
805
806 if (!info->attrs[DEVLINK_ATTR_PORT_INDEX])
807 return -EINVAL;
808
809 port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
ac0fc8a1 810 return devlink_port_unsplit(devlink, port_index, info->extack);
bfcd3a46
JP
811}
812
bf797471
JP
813static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
814 struct devlink_sb *devlink_sb,
815 enum devlink_command cmd, u32 portid,
816 u32 seq, int flags)
817{
818 void *hdr;
819
820 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
821 if (!hdr)
822 return -EMSGSIZE;
823
824 if (devlink_nl_put_handle(msg, devlink))
825 goto nla_put_failure;
826 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
827 goto nla_put_failure;
828 if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))
829 goto nla_put_failure;
830 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,
831 devlink_sb->ingress_pools_count))
832 goto nla_put_failure;
833 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,
834 devlink_sb->egress_pools_count))
835 goto nla_put_failure;
836 if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,
837 devlink_sb->ingress_tc_count))
838 goto nla_put_failure;
839 if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,
840 devlink_sb->egress_tc_count))
841 goto nla_put_failure;
842
843 genlmsg_end(msg, hdr);
844 return 0;
845
846nla_put_failure:
847 genlmsg_cancel(msg, hdr);
848 return -EMSGSIZE;
849}
850
851static int devlink_nl_cmd_sb_get_doit(struct sk_buff *skb,
852 struct genl_info *info)
853{
854 struct devlink *devlink = info->user_ptr[0];
855 struct devlink_sb *devlink_sb = info->user_ptr[1];
856 struct sk_buff *msg;
857 int err;
858
859 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
860 if (!msg)
861 return -ENOMEM;
862
863 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
864 DEVLINK_CMD_SB_NEW,
865 info->snd_portid, info->snd_seq, 0);
866 if (err) {
867 nlmsg_free(msg);
868 return err;
869 }
870
871 return genlmsg_reply(msg, info);
872}
873
874static int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
875 struct netlink_callback *cb)
876{
877 struct devlink *devlink;
878 struct devlink_sb *devlink_sb;
879 int start = cb->args[0];
880 int idx = 0;
881 int err;
882
883 mutex_lock(&devlink_mutex);
884 list_for_each_entry(devlink, &devlink_list, list) {
885 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
886 continue;
2406e7e5 887 mutex_lock(&devlink->lock);
bf797471
JP
888 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
889 if (idx < start) {
890 idx++;
891 continue;
892 }
893 err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
894 DEVLINK_CMD_SB_NEW,
895 NETLINK_CB(cb->skb).portid,
896 cb->nlh->nlmsg_seq,
897 NLM_F_MULTI);
2406e7e5
AS
898 if (err) {
899 mutex_unlock(&devlink->lock);
bf797471 900 goto out;
2406e7e5 901 }
bf797471
JP
902 idx++;
903 }
2406e7e5 904 mutex_unlock(&devlink->lock);
bf797471
JP
905 }
906out:
907 mutex_unlock(&devlink_mutex);
908
909 cb->args[0] = idx;
910 return msg->len;
911}
912
913static int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,
914 struct devlink_sb *devlink_sb,
915 u16 pool_index, enum devlink_command cmd,
916 u32 portid, u32 seq, int flags)
917{
918 struct devlink_sb_pool_info pool_info;
919 void *hdr;
920 int err;
921
922 err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,
923 pool_index, &pool_info);
924 if (err)
925 return err;
926
927 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
928 if (!hdr)
929 return -EMSGSIZE;
930
931 if (devlink_nl_put_handle(msg, devlink))
932 goto nla_put_failure;
933 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
934 goto nla_put_failure;
935 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
936 goto nla_put_failure;
937 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))
938 goto nla_put_failure;
939 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))
940 goto nla_put_failure;
941 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
942 pool_info.threshold_type))
943 goto nla_put_failure;
bff5731d
JK
944 if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
945 pool_info.cell_size))
946 goto nla_put_failure;
bf797471
JP
947
948 genlmsg_end(msg, hdr);
949 return 0;
950
951nla_put_failure:
952 genlmsg_cancel(msg, hdr);
953 return -EMSGSIZE;
954}
955
956static int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb,
957 struct genl_info *info)
958{
959 struct devlink *devlink = info->user_ptr[0];
960 struct devlink_sb *devlink_sb = info->user_ptr[1];
961 struct sk_buff *msg;
962 u16 pool_index;
963 int err;
964
965 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
966 &pool_index);
967 if (err)
968 return err;
969
be6fe1d8 970 if (!devlink->ops->sb_pool_get)
bf797471
JP
971 return -EOPNOTSUPP;
972
973 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
974 if (!msg)
975 return -ENOMEM;
976
977 err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,
978 DEVLINK_CMD_SB_POOL_NEW,
979 info->snd_portid, info->snd_seq, 0);
980 if (err) {
981 nlmsg_free(msg);
982 return err;
983 }
984
985 return genlmsg_reply(msg, info);
986}
987
988static int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
989 struct devlink *devlink,
990 struct devlink_sb *devlink_sb,
991 u32 portid, u32 seq)
992{
993 u16 pool_count = devlink_sb_pool_count(devlink_sb);
994 u16 pool_index;
995 int err;
996
997 for (pool_index = 0; pool_index < pool_count; pool_index++) {
998 if (*p_idx < start) {
999 (*p_idx)++;
1000 continue;
1001 }
1002 err = devlink_nl_sb_pool_fill(msg, devlink,
1003 devlink_sb,
1004 pool_index,
1005 DEVLINK_CMD_SB_POOL_NEW,
1006 portid, seq, NLM_F_MULTI);
1007 if (err)
1008 return err;
1009 (*p_idx)++;
1010 }
1011 return 0;
1012}
1013
1014static int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,
1015 struct netlink_callback *cb)
1016{
1017 struct devlink *devlink;
1018 struct devlink_sb *devlink_sb;
1019 int start = cb->args[0];
1020 int idx = 0;
1021 int err;
1022
1023 mutex_lock(&devlink_mutex);
1024 list_for_each_entry(devlink, &devlink_list, list) {
1025 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
be6fe1d8 1026 !devlink->ops->sb_pool_get)
bf797471 1027 continue;
2406e7e5 1028 mutex_lock(&devlink->lock);
bf797471
JP
1029 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1030 err = __sb_pool_get_dumpit(msg, start, &idx, devlink,
1031 devlink_sb,
1032 NETLINK_CB(cb->skb).portid,
1033 cb->nlh->nlmsg_seq);
2406e7e5
AS
1034 if (err && err != -EOPNOTSUPP) {
1035 mutex_unlock(&devlink->lock);
bf797471 1036 goto out;
2406e7e5 1037 }
bf797471 1038 }
2406e7e5 1039 mutex_unlock(&devlink->lock);
bf797471
JP
1040 }
1041out:
1042 mutex_unlock(&devlink_mutex);
1043
1044 cb->args[0] = idx;
1045 return msg->len;
1046}
1047
1048static int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
1049 u16 pool_index, u32 size,
1050 enum devlink_sb_threshold_type threshold_type)
1051
1052{
1053 const struct devlink_ops *ops = devlink->ops;
1054
be6fe1d8 1055 if (ops->sb_pool_set)
bf797471
JP
1056 return ops->sb_pool_set(devlink, sb_index, pool_index,
1057 size, threshold_type);
1058 return -EOPNOTSUPP;
1059}
1060
1061static int devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb,
1062 struct genl_info *info)
1063{
1064 struct devlink *devlink = info->user_ptr[0];
1065 struct devlink_sb *devlink_sb = info->user_ptr[1];
1066 enum devlink_sb_threshold_type threshold_type;
1067 u16 pool_index;
1068 u32 size;
1069 int err;
1070
1071 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1072 &pool_index);
1073 if (err)
1074 return err;
1075
1076 err = devlink_sb_th_type_get_from_info(info, &threshold_type);
1077 if (err)
1078 return err;
1079
1080 if (!info->attrs[DEVLINK_ATTR_SB_POOL_SIZE])
1081 return -EINVAL;
1082
1083 size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);
1084 return devlink_sb_pool_set(devlink, devlink_sb->index,
1085 pool_index, size, threshold_type);
1086}
1087
1088static int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,
1089 struct devlink *devlink,
1090 struct devlink_port *devlink_port,
1091 struct devlink_sb *devlink_sb,
1092 u16 pool_index,
1093 enum devlink_command cmd,
1094 u32 portid, u32 seq, int flags)
1095{
df38dafd 1096 const struct devlink_ops *ops = devlink->ops;
bf797471
JP
1097 u32 threshold;
1098 void *hdr;
1099 int err;
1100
df38dafd
JP
1101 err = ops->sb_port_pool_get(devlink_port, devlink_sb->index,
1102 pool_index, &threshold);
bf797471
JP
1103 if (err)
1104 return err;
1105
1106 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1107 if (!hdr)
1108 return -EMSGSIZE;
1109
1110 if (devlink_nl_put_handle(msg, devlink))
1111 goto nla_put_failure;
1112 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1113 goto nla_put_failure;
1114 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1115 goto nla_put_failure;
1116 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1117 goto nla_put_failure;
1118 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1119 goto nla_put_failure;
1120
df38dafd
JP
1121 if (ops->sb_occ_port_pool_get) {
1122 u32 cur;
1123 u32 max;
1124
1125 err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,
1126 pool_index, &cur, &max);
1127 if (err && err != -EOPNOTSUPP)
1128 return err;
1129 if (!err) {
1130 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1131 goto nla_put_failure;
1132 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1133 goto nla_put_failure;
1134 }
1135 }
1136
bf797471
JP
1137 genlmsg_end(msg, hdr);
1138 return 0;
1139
1140nla_put_failure:
1141 genlmsg_cancel(msg, hdr);
1142 return -EMSGSIZE;
1143}
1144
1145static int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb,
1146 struct genl_info *info)
1147{
1148 struct devlink_port *devlink_port = info->user_ptr[0];
1149 struct devlink *devlink = devlink_port->devlink;
1150 struct devlink_sb *devlink_sb = info->user_ptr[1];
1151 struct sk_buff *msg;
1152 u16 pool_index;
1153 int err;
1154
1155 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1156 &pool_index);
1157 if (err)
1158 return err;
1159
be6fe1d8 1160 if (!devlink->ops->sb_port_pool_get)
bf797471
JP
1161 return -EOPNOTSUPP;
1162
1163 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1164 if (!msg)
1165 return -ENOMEM;
1166
1167 err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port,
1168 devlink_sb, pool_index,
1169 DEVLINK_CMD_SB_PORT_POOL_NEW,
1170 info->snd_portid, info->snd_seq, 0);
1171 if (err) {
1172 nlmsg_free(msg);
1173 return err;
1174 }
1175
1176 return genlmsg_reply(msg, info);
1177}
1178
1179static int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
1180 struct devlink *devlink,
1181 struct devlink_sb *devlink_sb,
1182 u32 portid, u32 seq)
1183{
1184 struct devlink_port *devlink_port;
1185 u16 pool_count = devlink_sb_pool_count(devlink_sb);
1186 u16 pool_index;
1187 int err;
1188
1189 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1190 for (pool_index = 0; pool_index < pool_count; pool_index++) {
1191 if (*p_idx < start) {
1192 (*p_idx)++;
1193 continue;
1194 }
1195 err = devlink_nl_sb_port_pool_fill(msg, devlink,
1196 devlink_port,
1197 devlink_sb,
1198 pool_index,
1199 DEVLINK_CMD_SB_PORT_POOL_NEW,
1200 portid, seq,
1201 NLM_F_MULTI);
1202 if (err)
1203 return err;
1204 (*p_idx)++;
1205 }
1206 }
1207 return 0;
1208}
1209
1210static int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,
1211 struct netlink_callback *cb)
1212{
1213 struct devlink *devlink;
1214 struct devlink_sb *devlink_sb;
1215 int start = cb->args[0];
1216 int idx = 0;
1217 int err;
1218
1219 mutex_lock(&devlink_mutex);
bf797471
JP
1220 list_for_each_entry(devlink, &devlink_list, list) {
1221 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
be6fe1d8 1222 !devlink->ops->sb_port_pool_get)
bf797471 1223 continue;
2406e7e5 1224 mutex_lock(&devlink->lock);
bf797471
JP
1225 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1226 err = __sb_port_pool_get_dumpit(msg, start, &idx,
1227 devlink, devlink_sb,
1228 NETLINK_CB(cb->skb).portid,
1229 cb->nlh->nlmsg_seq);
2406e7e5
AS
1230 if (err && err != -EOPNOTSUPP) {
1231 mutex_unlock(&devlink->lock);
bf797471 1232 goto out;
2406e7e5 1233 }
bf797471 1234 }
2406e7e5 1235 mutex_unlock(&devlink->lock);
bf797471
JP
1236 }
1237out:
bf797471
JP
1238 mutex_unlock(&devlink_mutex);
1239
1240 cb->args[0] = idx;
1241 return msg->len;
1242}
1243
1244static int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
1245 unsigned int sb_index, u16 pool_index,
1246 u32 threshold)
1247
1248{
1249 const struct devlink_ops *ops = devlink_port->devlink->ops;
1250
be6fe1d8 1251 if (ops->sb_port_pool_set)
bf797471
JP
1252 return ops->sb_port_pool_set(devlink_port, sb_index,
1253 pool_index, threshold);
1254 return -EOPNOTSUPP;
1255}
1256
1257static int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb,
1258 struct genl_info *info)
1259{
1260 struct devlink_port *devlink_port = info->user_ptr[0];
1261 struct devlink_sb *devlink_sb = info->user_ptr[1];
1262 u16 pool_index;
1263 u32 threshold;
1264 int err;
1265
1266 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1267 &pool_index);
1268 if (err)
1269 return err;
1270
1271 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1272 return -EINVAL;
1273
1274 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1275 return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
1276 pool_index, threshold);
1277}
1278
1279static int
1280devlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink,
1281 struct devlink_port *devlink_port,
1282 struct devlink_sb *devlink_sb, u16 tc_index,
1283 enum devlink_sb_pool_type pool_type,
1284 enum devlink_command cmd,
1285 u32 portid, u32 seq, int flags)
1286{
df38dafd 1287 const struct devlink_ops *ops = devlink->ops;
bf797471
JP
1288 u16 pool_index;
1289 u32 threshold;
1290 void *hdr;
1291 int err;
1292
df38dafd
JP
1293 err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index,
1294 tc_index, pool_type,
1295 &pool_index, &threshold);
bf797471
JP
1296 if (err)
1297 return err;
1298
1299 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1300 if (!hdr)
1301 return -EMSGSIZE;
1302
1303 if (devlink_nl_put_handle(msg, devlink))
1304 goto nla_put_failure;
1305 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
1306 goto nla_put_failure;
1307 if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
1308 goto nla_put_failure;
1309 if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index))
1310 goto nla_put_failure;
1311 if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type))
1312 goto nla_put_failure;
1313 if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
1314 goto nla_put_failure;
1315 if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
1316 goto nla_put_failure;
1317
df38dafd
JP
1318 if (ops->sb_occ_tc_port_bind_get) {
1319 u32 cur;
1320 u32 max;
1321
1322 err = ops->sb_occ_tc_port_bind_get(devlink_port,
1323 devlink_sb->index,
1324 tc_index, pool_type,
1325 &cur, &max);
1326 if (err && err != -EOPNOTSUPP)
1327 return err;
1328 if (!err) {
1329 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
1330 goto nla_put_failure;
1331 if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
1332 goto nla_put_failure;
1333 }
1334 }
1335
bf797471
JP
1336 genlmsg_end(msg, hdr);
1337 return 0;
1338
1339nla_put_failure:
1340 genlmsg_cancel(msg, hdr);
1341 return -EMSGSIZE;
1342}
1343
1344static int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
1345 struct genl_info *info)
1346{
1347 struct devlink_port *devlink_port = info->user_ptr[0];
1348 struct devlink *devlink = devlink_port->devlink;
1349 struct devlink_sb *devlink_sb = info->user_ptr[1];
1350 struct sk_buff *msg;
1351 enum devlink_sb_pool_type pool_type;
1352 u16 tc_index;
1353 int err;
1354
1355 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1356 if (err)
1357 return err;
1358
1359 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1360 pool_type, &tc_index);
1361 if (err)
1362 return err;
1363
be6fe1d8 1364 if (!devlink->ops->sb_tc_pool_bind_get)
bf797471
JP
1365 return -EOPNOTSUPP;
1366
1367 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1368 if (!msg)
1369 return -ENOMEM;
1370
1371 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port,
1372 devlink_sb, tc_index, pool_type,
1373 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1374 info->snd_portid,
1375 info->snd_seq, 0);
1376 if (err) {
1377 nlmsg_free(msg);
1378 return err;
1379 }
1380
1381 return genlmsg_reply(msg, info);
1382}
1383
1384static int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1385 int start, int *p_idx,
1386 struct devlink *devlink,
1387 struct devlink_sb *devlink_sb,
1388 u32 portid, u32 seq)
1389{
1390 struct devlink_port *devlink_port;
1391 u16 tc_index;
1392 int err;
1393
1394 list_for_each_entry(devlink_port, &devlink->port_list, list) {
1395 for (tc_index = 0;
1396 tc_index < devlink_sb->ingress_tc_count; tc_index++) {
1397 if (*p_idx < start) {
1398 (*p_idx)++;
1399 continue;
1400 }
1401 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1402 devlink_port,
1403 devlink_sb,
1404 tc_index,
1405 DEVLINK_SB_POOL_TYPE_INGRESS,
1406 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1407 portid, seq,
1408 NLM_F_MULTI);
1409 if (err)
1410 return err;
1411 (*p_idx)++;
1412 }
1413 for (tc_index = 0;
1414 tc_index < devlink_sb->egress_tc_count; tc_index++) {
1415 if (*p_idx < start) {
1416 (*p_idx)++;
1417 continue;
1418 }
1419 err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
1420 devlink_port,
1421 devlink_sb,
1422 tc_index,
1423 DEVLINK_SB_POOL_TYPE_EGRESS,
1424 DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
1425 portid, seq,
1426 NLM_F_MULTI);
1427 if (err)
1428 return err;
1429 (*p_idx)++;
1430 }
1431 }
1432 return 0;
1433}
1434
1435static int
1436devlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
1437 struct netlink_callback *cb)
1438{
1439 struct devlink *devlink;
1440 struct devlink_sb *devlink_sb;
1441 int start = cb->args[0];
1442 int idx = 0;
1443 int err;
1444
1445 mutex_lock(&devlink_mutex);
bf797471
JP
1446 list_for_each_entry(devlink, &devlink_list, list) {
1447 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
be6fe1d8 1448 !devlink->ops->sb_tc_pool_bind_get)
bf797471 1449 continue;
2406e7e5
AS
1450
1451 mutex_lock(&devlink->lock);
bf797471
JP
1452 list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
1453 err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx,
1454 devlink,
1455 devlink_sb,
1456 NETLINK_CB(cb->skb).portid,
1457 cb->nlh->nlmsg_seq);
2406e7e5
AS
1458 if (err && err != -EOPNOTSUPP) {
1459 mutex_unlock(&devlink->lock);
bf797471 1460 goto out;
2406e7e5 1461 }
bf797471 1462 }
2406e7e5 1463 mutex_unlock(&devlink->lock);
bf797471
JP
1464 }
1465out:
bf797471
JP
1466 mutex_unlock(&devlink_mutex);
1467
1468 cb->args[0] = idx;
1469 return msg->len;
1470}
1471
1472static int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
1473 unsigned int sb_index, u16 tc_index,
1474 enum devlink_sb_pool_type pool_type,
1475 u16 pool_index, u32 threshold)
1476
1477{
1478 const struct devlink_ops *ops = devlink_port->devlink->ops;
1479
be6fe1d8 1480 if (ops->sb_tc_pool_bind_set)
bf797471
JP
1481 return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
1482 tc_index, pool_type,
1483 pool_index, threshold);
1484 return -EOPNOTSUPP;
1485}
1486
1487static int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
1488 struct genl_info *info)
1489{
1490 struct devlink_port *devlink_port = info->user_ptr[0];
1491 struct devlink_sb *devlink_sb = info->user_ptr[1];
1492 enum devlink_sb_pool_type pool_type;
1493 u16 tc_index;
1494 u16 pool_index;
1495 u32 threshold;
1496 int err;
1497
1498 err = devlink_sb_pool_type_get_from_info(info, &pool_type);
1499 if (err)
1500 return err;
1501
1502 err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
1503 pool_type, &tc_index);
1504 if (err)
1505 return err;
1506
1507 err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
1508 &pool_index);
1509 if (err)
1510 return err;
1511
1512 if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
1513 return -EINVAL;
1514
1515 threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
1516 return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
1517 tc_index, pool_type,
1518 pool_index, threshold);
1519}
1520
df38dafd
JP
1521static int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
1522 struct genl_info *info)
1523{
1524 struct devlink *devlink = info->user_ptr[0];
1525 struct devlink_sb *devlink_sb = info->user_ptr[1];
1526 const struct devlink_ops *ops = devlink->ops;
1527
be6fe1d8 1528 if (ops->sb_occ_snapshot)
df38dafd
JP
1529 return ops->sb_occ_snapshot(devlink, devlink_sb->index);
1530 return -EOPNOTSUPP;
1531}
1532
1533static int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb,
1534 struct genl_info *info)
1535{
1536 struct devlink *devlink = info->user_ptr[0];
1537 struct devlink_sb *devlink_sb = info->user_ptr[1];
1538 const struct devlink_ops *ops = devlink->ops;
1539
be6fe1d8 1540 if (ops->sb_occ_max_clear)
df38dafd
JP
1541 return ops->sb_occ_max_clear(devlink, devlink_sb->index);
1542 return -EOPNOTSUPP;
1543}
1544
21e3d2dd
JP
1545static int devlink_nl_eswitch_fill(struct sk_buff *msg, struct devlink *devlink,
1546 enum devlink_command cmd, u32 portid,
1547 u32 seq, int flags)
08f4b591 1548{
59bfde01 1549 const struct devlink_ops *ops = devlink->ops;
f43e9b06 1550 u8 inline_mode, encap_mode;
08f4b591 1551 void *hdr;
59bfde01
RD
1552 int err = 0;
1553 u16 mode;
08f4b591
OG
1554
1555 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
1556 if (!hdr)
1557 return -EMSGSIZE;
1558
59bfde01
RD
1559 err = devlink_nl_put_handle(msg, devlink);
1560 if (err)
1a6aa36b 1561 goto nla_put_failure;
08f4b591 1562
4456f61c
JP
1563 if (ops->eswitch_mode_get) {
1564 err = ops->eswitch_mode_get(devlink, &mode);
1565 if (err)
1566 goto nla_put_failure;
1567 err = nla_put_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode);
1568 if (err)
1569 goto nla_put_failure;
1570 }
59bfde01
RD
1571
1572 if (ops->eswitch_inline_mode_get) {
1573 err = ops->eswitch_inline_mode_get(devlink, &inline_mode);
1574 if (err)
1a6aa36b 1575 goto nla_put_failure;
59bfde01
RD
1576 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1577 inline_mode);
1578 if (err)
1a6aa36b 1579 goto nla_put_failure;
59bfde01 1580 }
08f4b591 1581
f43e9b06
RD
1582 if (ops->eswitch_encap_mode_get) {
1583 err = ops->eswitch_encap_mode_get(devlink, &encap_mode);
1584 if (err)
1585 goto nla_put_failure;
1586 err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, encap_mode);
1587 if (err)
1588 goto nla_put_failure;
1589 }
1590
08f4b591
OG
1591 genlmsg_end(msg, hdr);
1592 return 0;
1593
1a6aa36b 1594nla_put_failure:
08f4b591 1595 genlmsg_cancel(msg, hdr);
59bfde01 1596 return err;
08f4b591
OG
1597}
1598
adf200f3
JP
1599static int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb,
1600 struct genl_info *info)
08f4b591
OG
1601{
1602 struct devlink *devlink = info->user_ptr[0];
08f4b591 1603 struct sk_buff *msg;
08f4b591
OG
1604 int err;
1605
08f4b591
OG
1606 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1607 if (!msg)
1608 return -ENOMEM;
1609
21e3d2dd
JP
1610 err = devlink_nl_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_GET,
1611 info->snd_portid, info->snd_seq, 0);
08f4b591
OG
1612
1613 if (err) {
1614 nlmsg_free(msg);
1615 return err;
1616 }
1617
1618 return genlmsg_reply(msg, info);
1619}
1620
adf200f3
JP
1621static int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb,
1622 struct genl_info *info)
08f4b591
OG
1623{
1624 struct devlink *devlink = info->user_ptr[0];
1625 const struct devlink_ops *ops = devlink->ops;
f43e9b06 1626 u8 inline_mode, encap_mode;
59bfde01 1627 int err = 0;
f43e9b06 1628 u16 mode;
08f4b591 1629
59bfde01
RD
1630 if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {
1631 if (!ops->eswitch_mode_set)
1632 return -EOPNOTSUPP;
1633 mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
db7ff19e 1634 err = ops->eswitch_mode_set(devlink, mode, info->extack);
59bfde01
RD
1635 if (err)
1636 return err;
1637 }
08f4b591 1638
59bfde01
RD
1639 if (info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
1640 if (!ops->eswitch_inline_mode_set)
1641 return -EOPNOTSUPP;
1642 inline_mode = nla_get_u8(
1643 info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]);
db7ff19e
EB
1644 err = ops->eswitch_inline_mode_set(devlink, inline_mode,
1645 info->extack);
59bfde01
RD
1646 if (err)
1647 return err;
1648 }
f43e9b06
RD
1649
1650 if (info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
1651 if (!ops->eswitch_encap_mode_set)
1652 return -EOPNOTSUPP;
1653 encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
db7ff19e
EB
1654 err = ops->eswitch_encap_mode_set(devlink, encap_mode,
1655 info->extack);
f43e9b06
RD
1656 if (err)
1657 return err;
1658 }
1659
1555d204
AS
1660 return 0;
1661}
1662
1663int devlink_dpipe_match_put(struct sk_buff *skb,
1664 struct devlink_dpipe_match *match)
1665{
1666 struct devlink_dpipe_header *header = match->header;
1667 struct devlink_dpipe_field *field = &header->fields[match->field_id];
1668 struct nlattr *match_attr;
1669
1670 match_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_MATCH);
1671 if (!match_attr)
1672 return -EMSGSIZE;
1673
1674 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
1675 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
1676 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1677 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1678 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1679 goto nla_put_failure;
1680
1681 nla_nest_end(skb, match_attr);
1682 return 0;
1683
1684nla_put_failure:
1685 nla_nest_cancel(skb, match_attr);
1686 return -EMSGSIZE;
1687}
1688EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
1689
1690static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
1691 struct sk_buff *skb)
1692{
1693 struct nlattr *matches_attr;
1694
1695 matches_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
1696 if (!matches_attr)
1697 return -EMSGSIZE;
1698
1699 if (table->table_ops->matches_dump(table->priv, skb))
1700 goto nla_put_failure;
1701
1702 nla_nest_end(skb, matches_attr);
1703 return 0;
1704
1705nla_put_failure:
1706 nla_nest_cancel(skb, matches_attr);
1707 return -EMSGSIZE;
1708}
1709
1710int devlink_dpipe_action_put(struct sk_buff *skb,
1711 struct devlink_dpipe_action *action)
1712{
1713 struct devlink_dpipe_header *header = action->header;
1714 struct devlink_dpipe_field *field = &header->fields[action->field_id];
1715 struct nlattr *action_attr;
1716
1717 action_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_ACTION);
1718 if (!action_attr)
1719 return -EMSGSIZE;
1720
1721 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
1722 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
1723 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
1724 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
1725 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
1726 goto nla_put_failure;
1727
1728 nla_nest_end(skb, action_attr);
1729 return 0;
1730
1731nla_put_failure:
1732 nla_nest_cancel(skb, action_attr);
1733 return -EMSGSIZE;
1734}
1735EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
1736
1737static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
1738 struct sk_buff *skb)
1739{
1740 struct nlattr *actions_attr;
1741
1742 actions_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
1743 if (!actions_attr)
1744 return -EMSGSIZE;
1745
1746 if (table->table_ops->actions_dump(table->priv, skb))
1747 goto nla_put_failure;
1748
1749 nla_nest_end(skb, actions_attr);
1750 return 0;
1751
1752nla_put_failure:
1753 nla_nest_cancel(skb, actions_attr);
1754 return -EMSGSIZE;
1755}
1756
1757static int devlink_dpipe_table_put(struct sk_buff *skb,
1758 struct devlink_dpipe_table *table)
1759{
1760 struct nlattr *table_attr;
ffd3cdcc 1761 u64 table_size;
1555d204 1762
ffd3cdcc 1763 table_size = table->table_ops->size_get(table->priv);
1555d204
AS
1764 table_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLE);
1765 if (!table_attr)
1766 return -EMSGSIZE;
1767
1768 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
ffd3cdcc 1769 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size,
1555d204
AS
1770 DEVLINK_ATTR_PAD))
1771 goto nla_put_failure;
1772 if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
1773 table->counters_enabled))
1774 goto nla_put_failure;
1775
56dc7cd0 1776 if (table->resource_valid) {
3d18e4f1
AS
1777 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
1778 table->resource_id, DEVLINK_ATTR_PAD) ||
1779 nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
1780 table->resource_units, DEVLINK_ATTR_PAD))
1781 goto nla_put_failure;
56dc7cd0 1782 }
1555d204
AS
1783 if (devlink_dpipe_matches_put(table, skb))
1784 goto nla_put_failure;
1785
1786 if (devlink_dpipe_actions_put(table, skb))
1787 goto nla_put_failure;
1788
1789 nla_nest_end(skb, table_attr);
1790 return 0;
1791
1792nla_put_failure:
1793 nla_nest_cancel(skb, table_attr);
1794 return -EMSGSIZE;
1795}
1796
1797static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
1798 struct genl_info *info)
1799{
1800 int err;
1801
1802 if (*pskb) {
1803 err = genlmsg_reply(*pskb, info);
1804 if (err)
1805 return err;
1806 }
1807 *pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
1808 if (!*pskb)
1809 return -ENOMEM;
1810 return 0;
1811}
1812
1813static int devlink_dpipe_tables_fill(struct genl_info *info,
1814 enum devlink_command cmd, int flags,
1815 struct list_head *dpipe_tables,
1816 const char *table_name)
1817{
1818 struct devlink *devlink = info->user_ptr[0];
1819 struct devlink_dpipe_table *table;
1820 struct nlattr *tables_attr;
1821 struct sk_buff *skb = NULL;
1822 struct nlmsghdr *nlh;
1823 bool incomplete;
1824 void *hdr;
1825 int i;
1826 int err;
1827
1828 table = list_first_entry(dpipe_tables,
1829 struct devlink_dpipe_table, list);
1830start_again:
1831 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
1832 if (err)
1833 return err;
1834
1835 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
1836 &devlink_nl_family, NLM_F_MULTI, cmd);
6044bd4a
HY
1837 if (!hdr) {
1838 nlmsg_free(skb);
1555d204 1839 return -EMSGSIZE;
6044bd4a 1840 }
1555d204
AS
1841
1842 if (devlink_nl_put_handle(skb, devlink))
1843 goto nla_put_failure;
1844 tables_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_TABLES);
1845 if (!tables_attr)
1846 goto nla_put_failure;
1847
1848 i = 0;
1849 incomplete = false;
1850 list_for_each_entry_from(table, dpipe_tables, list) {
1851 if (!table_name) {
1852 err = devlink_dpipe_table_put(skb, table);
1853 if (err) {
1854 if (!i)
1855 goto err_table_put;
1856 incomplete = true;
1857 break;
1858 }
1859 } else {
1860 if (!strcmp(table->name, table_name)) {
1861 err = devlink_dpipe_table_put(skb, table);
1862 if (err)
1863 break;
1864 }
1865 }
1866 i++;
1867 }
1868
1869 nla_nest_end(skb, tables_attr);
1870 genlmsg_end(skb, hdr);
1871 if (incomplete)
1872 goto start_again;
1873
1874send_done:
1875 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
1876 NLMSG_DONE, 0, flags | NLM_F_MULTI);
1877 if (!nlh) {
1878 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
1879 if (err)
7fe4d6dc 1880 return err;
1555d204
AS
1881 goto send_done;
1882 }
1883
1884 return genlmsg_reply(skb, info);
1885
1886nla_put_failure:
1887 err = -EMSGSIZE;
1888err_table_put:
1555d204
AS
1889 nlmsg_free(skb);
1890 return err;
1891}
1892
1893static int devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb,
1894 struct genl_info *info)
1895{
1896 struct devlink *devlink = info->user_ptr[0];
1897 const char *table_name = NULL;
1898
1899 if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
1900 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
1901
1902 return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
1903 &devlink->dpipe_table_list,
1904 table_name);
1905}
1906
1907static int devlink_dpipe_value_put(struct sk_buff *skb,
1908 struct devlink_dpipe_value *value)
1909{
1910 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
1911 value->value_size, value->value))
1912 return -EMSGSIZE;
1913 if (value->mask)
1914 if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
1915 value->value_size, value->mask))
1916 return -EMSGSIZE;
1917 if (value->mapping_valid)
1918 if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
1919 value->mapping_value))
1920 return -EMSGSIZE;
1921 return 0;
1922}
1923
1924static int devlink_dpipe_action_value_put(struct sk_buff *skb,
1925 struct devlink_dpipe_value *value)
1926{
1927 if (!value->action)
1928 return -EINVAL;
1929 if (devlink_dpipe_action_put(skb, value->action))
1930 return -EMSGSIZE;
1931 if (devlink_dpipe_value_put(skb, value))
1932 return -EMSGSIZE;
1933 return 0;
1934}
1935
1936static int devlink_dpipe_action_values_put(struct sk_buff *skb,
1937 struct devlink_dpipe_value *values,
1938 unsigned int values_count)
1939{
1940 struct nlattr *action_attr;
1941 int i;
1942 int err;
1943
1944 for (i = 0; i < values_count; i++) {
1945 action_attr = nla_nest_start(skb,
1946 DEVLINK_ATTR_DPIPE_ACTION_VALUE);
1947 if (!action_attr)
1948 return -EMSGSIZE;
1949 err = devlink_dpipe_action_value_put(skb, &values[i]);
1950 if (err)
1951 goto err_action_value_put;
1952 nla_nest_end(skb, action_attr);
1953 }
1954 return 0;
1955
1956err_action_value_put:
1957 nla_nest_cancel(skb, action_attr);
1958 return err;
1959}
1960
1961static int devlink_dpipe_match_value_put(struct sk_buff *skb,
1962 struct devlink_dpipe_value *value)
1963{
1964 if (!value->match)
1965 return -EINVAL;
1966 if (devlink_dpipe_match_put(skb, value->match))
1967 return -EMSGSIZE;
1968 if (devlink_dpipe_value_put(skb, value))
1969 return -EMSGSIZE;
1970 return 0;
1971}
1972
1973static int devlink_dpipe_match_values_put(struct sk_buff *skb,
1974 struct devlink_dpipe_value *values,
1975 unsigned int values_count)
1976{
1977 struct nlattr *match_attr;
1978 int i;
1979 int err;
1980
1981 for (i = 0; i < values_count; i++) {
1982 match_attr = nla_nest_start(skb,
1983 DEVLINK_ATTR_DPIPE_MATCH_VALUE);
1984 if (!match_attr)
1985 return -EMSGSIZE;
1986 err = devlink_dpipe_match_value_put(skb, &values[i]);
1987 if (err)
1988 goto err_match_value_put;
1989 nla_nest_end(skb, match_attr);
1990 }
1991 return 0;
1992
1993err_match_value_put:
1994 nla_nest_cancel(skb, match_attr);
1995 return err;
1996}
1997
1998static int devlink_dpipe_entry_put(struct sk_buff *skb,
1999 struct devlink_dpipe_entry *entry)
2000{
2001 struct nlattr *entry_attr, *matches_attr, *actions_attr;
2002 int err;
2003
2004 entry_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_ENTRY);
2005 if (!entry_attr)
2006 return -EMSGSIZE;
2007
2008 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index,
2009 DEVLINK_ATTR_PAD))
2010 goto nla_put_failure;
2011 if (entry->counter_valid)
2012 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
2013 entry->counter, DEVLINK_ATTR_PAD))
2014 goto nla_put_failure;
2015
2016 matches_attr = nla_nest_start(skb,
2017 DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
2018 if (!matches_attr)
2019 goto nla_put_failure;
2020
2021 err = devlink_dpipe_match_values_put(skb, entry->match_values,
2022 entry->match_values_count);
2023 if (err) {
2024 nla_nest_cancel(skb, matches_attr);
2025 goto err_match_values_put;
2026 }
2027 nla_nest_end(skb, matches_attr);
2028
2029 actions_attr = nla_nest_start(skb,
2030 DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
2031 if (!actions_attr)
2032 goto nla_put_failure;
2033
2034 err = devlink_dpipe_action_values_put(skb, entry->action_values,
2035 entry->action_values_count);
2036 if (err) {
2037 nla_nest_cancel(skb, actions_attr);
2038 goto err_action_values_put;
2039 }
2040 nla_nest_end(skb, actions_attr);
59bfde01 2041
1555d204 2042 nla_nest_end(skb, entry_attr);
59bfde01 2043 return 0;
1555d204
AS
2044
2045nla_put_failure:
2046 err = -EMSGSIZE;
2047err_match_values_put:
2048err_action_values_put:
2049 nla_nest_cancel(skb, entry_attr);
2050 return err;
2051}
2052
2053static struct devlink_dpipe_table *
2054devlink_dpipe_table_find(struct list_head *dpipe_tables,
2055 const char *table_name)
2056{
2057 struct devlink_dpipe_table *table;
2058
2059 list_for_each_entry_rcu(table, dpipe_tables, list) {
2060 if (!strcmp(table->name, table_name))
2061 return table;
2062 }
2063 return NULL;
2064}
2065
2066int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
2067{
2068 struct devlink *devlink;
2069 int err;
2070
2071 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
2072 dump_ctx->info);
2073 if (err)
2074 return err;
2075
2076 dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
2077 dump_ctx->info->snd_portid,
2078 dump_ctx->info->snd_seq,
2079 &devlink_nl_family, NLM_F_MULTI,
2080 dump_ctx->cmd);
2081 if (!dump_ctx->hdr)
2082 goto nla_put_failure;
2083
2084 devlink = dump_ctx->info->user_ptr[0];
2085 if (devlink_nl_put_handle(dump_ctx->skb, devlink))
2086 goto nla_put_failure;
2087 dump_ctx->nest = nla_nest_start(dump_ctx->skb,
2088 DEVLINK_ATTR_DPIPE_ENTRIES);
2089 if (!dump_ctx->nest)
2090 goto nla_put_failure;
2091 return 0;
2092
2093nla_put_failure:
1555d204
AS
2094 nlmsg_free(dump_ctx->skb);
2095 return -EMSGSIZE;
2096}
2097EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
2098
2099int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
2100 struct devlink_dpipe_entry *entry)
2101{
2102 return devlink_dpipe_entry_put(dump_ctx->skb, entry);
2103}
2104EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
2105
2106int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
2107{
2108 nla_nest_end(dump_ctx->skb, dump_ctx->nest);
2109 genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
2110 return 0;
2111}
2112EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
2113
35807324
AS
2114void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
2115
2116{
2117 unsigned int value_count, value_index;
2118 struct devlink_dpipe_value *value;
2119
2120 value = entry->action_values;
2121 value_count = entry->action_values_count;
2122 for (value_index = 0; value_index < value_count; value_index++) {
2123 kfree(value[value_index].value);
2124 kfree(value[value_index].mask);
2125 }
2126
2127 value = entry->match_values;
2128 value_count = entry->match_values_count;
2129 for (value_index = 0; value_index < value_count; value_index++) {
2130 kfree(value[value_index].value);
2131 kfree(value[value_index].mask);
2132 }
2133}
2134EXPORT_SYMBOL(devlink_dpipe_entry_clear);
2135
1555d204
AS
2136static int devlink_dpipe_entries_fill(struct genl_info *info,
2137 enum devlink_command cmd, int flags,
2138 struct devlink_dpipe_table *table)
2139{
2140 struct devlink_dpipe_dump_ctx dump_ctx;
2141 struct nlmsghdr *nlh;
2142 int err;
2143
2144 dump_ctx.skb = NULL;
2145 dump_ctx.cmd = cmd;
2146 dump_ctx.info = info;
2147
2148 err = table->table_ops->entries_dump(table->priv,
2149 table->counters_enabled,
2150 &dump_ctx);
2151 if (err)
7fe4d6dc 2152 return err;
1555d204
AS
2153
2154send_done:
2155 nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
2156 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2157 if (!nlh) {
2158 err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
2159 if (err)
7fe4d6dc 2160 return err;
1555d204
AS
2161 goto send_done;
2162 }
2163 return genlmsg_reply(dump_ctx.skb, info);
1555d204
AS
2164}
2165
2166static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
2167 struct genl_info *info)
2168{
2169 struct devlink *devlink = info->user_ptr[0];
2170 struct devlink_dpipe_table *table;
2171 const char *table_name;
2172
2173 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
2174 return -EINVAL;
2175
2176 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2177 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2178 table_name);
2179 if (!table)
2180 return -EINVAL;
2181
2182 if (!table->table_ops->entries_dump)
2183 return -EINVAL;
2184
2185 return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
2186 0, table);
2187}
2188
2189static int devlink_dpipe_fields_put(struct sk_buff *skb,
2190 const struct devlink_dpipe_header *header)
2191{
2192 struct devlink_dpipe_field *field;
2193 struct nlattr *field_attr;
2194 int i;
2195
2196 for (i = 0; i < header->fields_count; i++) {
2197 field = &header->fields[i];
2198 field_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_FIELD);
2199 if (!field_attr)
2200 return -EMSGSIZE;
2201 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
2202 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
2203 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
2204 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
2205 goto nla_put_failure;
2206 nla_nest_end(skb, field_attr);
2207 }
2208 return 0;
2209
2210nla_put_failure:
2211 nla_nest_cancel(skb, field_attr);
2212 return -EMSGSIZE;
2213}
2214
2215static int devlink_dpipe_header_put(struct sk_buff *skb,
2216 struct devlink_dpipe_header *header)
2217{
2218 struct nlattr *fields_attr, *header_attr;
2219 int err;
2220
2221 header_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_HEADER);
cb6bf9cf 2222 if (!header_attr)
1555d204
AS
2223 return -EMSGSIZE;
2224
2225 if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
2226 nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
2227 nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
2228 goto nla_put_failure;
2229
2230 fields_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
2231 if (!fields_attr)
2232 goto nla_put_failure;
2233
2234 err = devlink_dpipe_fields_put(skb, header);
2235 if (err) {
2236 nla_nest_cancel(skb, fields_attr);
2237 goto nla_put_failure;
2238 }
2239 nla_nest_end(skb, fields_attr);
2240 nla_nest_end(skb, header_attr);
2241 return 0;
2242
2243nla_put_failure:
2244 err = -EMSGSIZE;
2245 nla_nest_cancel(skb, header_attr);
2246 return err;
2247}
2248
2249static int devlink_dpipe_headers_fill(struct genl_info *info,
2250 enum devlink_command cmd, int flags,
2251 struct devlink_dpipe_headers *
2252 dpipe_headers)
2253{
2254 struct devlink *devlink = info->user_ptr[0];
2255 struct nlattr *headers_attr;
2256 struct sk_buff *skb = NULL;
2257 struct nlmsghdr *nlh;
2258 void *hdr;
2259 int i, j;
2260 int err;
2261
2262 i = 0;
2263start_again:
2264 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2265 if (err)
2266 return err;
2267
2268 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2269 &devlink_nl_family, NLM_F_MULTI, cmd);
6044bd4a
HY
2270 if (!hdr) {
2271 nlmsg_free(skb);
1555d204 2272 return -EMSGSIZE;
6044bd4a 2273 }
1555d204
AS
2274
2275 if (devlink_nl_put_handle(skb, devlink))
2276 goto nla_put_failure;
2277 headers_attr = nla_nest_start(skb, DEVLINK_ATTR_DPIPE_HEADERS);
2278 if (!headers_attr)
2279 goto nla_put_failure;
2280
2281 j = 0;
2282 for (; i < dpipe_headers->headers_count; i++) {
2283 err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
2284 if (err) {
2285 if (!j)
2286 goto err_table_put;
2287 break;
2288 }
2289 j++;
2290 }
2291 nla_nest_end(skb, headers_attr);
2292 genlmsg_end(skb, hdr);
2293 if (i != dpipe_headers->headers_count)
2294 goto start_again;
2295
2296send_done:
2297 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2298 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2299 if (!nlh) {
2300 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2301 if (err)
7fe4d6dc 2302 return err;
1555d204
AS
2303 goto send_done;
2304 }
2305 return genlmsg_reply(skb, info);
2306
2307nla_put_failure:
2308 err = -EMSGSIZE;
2309err_table_put:
1555d204
AS
2310 nlmsg_free(skb);
2311 return err;
2312}
2313
2314static int devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb,
2315 struct genl_info *info)
2316{
2317 struct devlink *devlink = info->user_ptr[0];
2318
2319 if (!devlink->dpipe_headers)
2320 return -EOPNOTSUPP;
2321 return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
2322 0, devlink->dpipe_headers);
2323}
2324
2325static int devlink_dpipe_table_counters_set(struct devlink *devlink,
2326 const char *table_name,
2327 bool enable)
2328{
2329 struct devlink_dpipe_table *table;
2330
2331 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
2332 table_name);
2333 if (!table)
2334 return -EINVAL;
2335
2336 if (table->counter_control_extern)
2337 return -EOPNOTSUPP;
2338
2339 if (!(table->counters_enabled ^ enable))
2340 return 0;
2341
2342 table->counters_enabled = enable;
2343 if (table->table_ops->counters_set_update)
2344 table->table_ops->counters_set_update(table->priv, enable);
2345 return 0;
2346}
2347
2348static int devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb,
2349 struct genl_info *info)
2350{
2351 struct devlink *devlink = info->user_ptr[0];
2352 const char *table_name;
2353 bool counters_enable;
2354
2355 if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
2356 !info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED])
2357 return -EINVAL;
2358
2359 table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
2360 counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
2361
2362 return devlink_dpipe_table_counters_set(devlink, table_name,
2363 counters_enable);
08f4b591
OG
2364}
2365
43dd7512 2366static struct devlink_resource *
d9f9b9a4
AS
2367devlink_resource_find(struct devlink *devlink,
2368 struct devlink_resource *resource, u64 resource_id)
2369{
2370 struct list_head *resource_list;
2371
2372 if (resource)
2373 resource_list = &resource->resource_list;
2374 else
2375 resource_list = &devlink->resource_list;
2376
2377 list_for_each_entry(resource, resource_list, list) {
2378 struct devlink_resource *child_resource;
2379
2380 if (resource->id == resource_id)
2381 return resource;
2382
2383 child_resource = devlink_resource_find(devlink, resource,
2384 resource_id);
2385 if (child_resource)
2386 return child_resource;
2387 }
2388 return NULL;
2389}
2390
43dd7512
WY
2391static void
2392devlink_resource_validate_children(struct devlink_resource *resource)
d9f9b9a4
AS
2393{
2394 struct devlink_resource *child_resource;
2395 bool size_valid = true;
2396 u64 parts_size = 0;
2397
2398 if (list_empty(&resource->resource_list))
2399 goto out;
2400
2401 list_for_each_entry(child_resource, &resource->resource_list, list)
2402 parts_size += child_resource->size_new;
2403
b9d17175 2404 if (parts_size > resource->size_new)
d9f9b9a4
AS
2405 size_valid = false;
2406out:
2407 resource->size_valid = size_valid;
2408}
2409
cc944ead
AS
2410static int
2411devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
2412 struct netlink_ext_ack *extack)
2413{
2414 u64 reminder;
2415 int err = 0;
2416
0f3e9c97 2417 if (size > resource->size_params.size_max) {
cc944ead
AS
2418 NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum");
2419 err = -EINVAL;
2420 }
2421
0f3e9c97 2422 if (size < resource->size_params.size_min) {
cc944ead
AS
2423 NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum");
2424 err = -EINVAL;
2425 }
2426
0f3e9c97 2427 div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
cc944ead
AS
2428 if (reminder) {
2429 NL_SET_ERR_MSG_MOD(extack, "Wrong granularity");
2430 err = -EINVAL;
2431 }
2432
2433 return err;
2434}
2435
d9f9b9a4
AS
2436static int devlink_nl_cmd_resource_set(struct sk_buff *skb,
2437 struct genl_info *info)
2438{
2439 struct devlink *devlink = info->user_ptr[0];
2440 struct devlink_resource *resource;
2441 u64 resource_id;
2442 u64 size;
2443 int err;
2444
2445 if (!info->attrs[DEVLINK_ATTR_RESOURCE_ID] ||
2446 !info->attrs[DEVLINK_ATTR_RESOURCE_SIZE])
2447 return -EINVAL;
2448 resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
2449
2450 resource = devlink_resource_find(devlink, NULL, resource_id);
2451 if (!resource)
2452 return -EINVAL;
2453
d9f9b9a4 2454 size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
cc944ead 2455 err = devlink_resource_validate_size(resource, size, info->extack);
d9f9b9a4
AS
2456 if (err)
2457 return err;
2458
2459 resource->size_new = size;
2460 devlink_resource_validate_children(resource);
2461 if (resource->parent)
2462 devlink_resource_validate_children(resource->parent);
2463 return 0;
2464}
2465
3d18e4f1 2466static int
d9f9b9a4
AS
2467devlink_resource_size_params_put(struct devlink_resource *resource,
2468 struct sk_buff *skb)
2469{
2470 struct devlink_resource_size_params *size_params;
2471
77d27096 2472 size_params = &resource->size_params;
3d18e4f1
AS
2473 if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
2474 size_params->size_granularity, DEVLINK_ATTR_PAD) ||
2475 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
2476 size_params->size_max, DEVLINK_ATTR_PAD) ||
2477 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
2478 size_params->size_min, DEVLINK_ATTR_PAD) ||
2479 nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
2480 return -EMSGSIZE;
2481 return 0;
d9f9b9a4
AS
2482}
2483
fc56be47
JP
2484static int devlink_resource_occ_put(struct devlink_resource *resource,
2485 struct sk_buff *skb)
2486{
2487 if (!resource->occ_get)
2488 return 0;
2489 return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
2490 resource->occ_get(resource->occ_get_priv),
2491 DEVLINK_ATTR_PAD);
2492}
2493
d9f9b9a4
AS
2494static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
2495 struct devlink_resource *resource)
2496{
2497 struct devlink_resource *child_resource;
2498 struct nlattr *child_resource_attr;
2499 struct nlattr *resource_attr;
2500
2501 resource_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE);
2502 if (!resource_attr)
2503 return -EMSGSIZE;
2504
2505 if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
2506 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
2507 DEVLINK_ATTR_PAD) ||
2508 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
2509 DEVLINK_ATTR_PAD))
2510 goto nla_put_failure;
2511 if (resource->size != resource->size_new)
2512 nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
2513 resource->size_new, DEVLINK_ATTR_PAD);
fc56be47
JP
2514 if (devlink_resource_occ_put(resource, skb))
2515 goto nla_put_failure;
3d18e4f1
AS
2516 if (devlink_resource_size_params_put(resource, skb))
2517 goto nla_put_failure;
d9f9b9a4
AS
2518 if (list_empty(&resource->resource_list))
2519 goto out;
2520
2521 if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
2522 resource->size_valid))
2523 goto nla_put_failure;
2524
2525 child_resource_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE_LIST);
2526 if (!child_resource_attr)
2527 goto nla_put_failure;
2528
2529 list_for_each_entry(child_resource, &resource->resource_list, list) {
2530 if (devlink_resource_put(devlink, skb, child_resource))
2531 goto resource_put_failure;
2532 }
2533
2534 nla_nest_end(skb, child_resource_attr);
2535out:
2536 nla_nest_end(skb, resource_attr);
2537 return 0;
2538
2539resource_put_failure:
2540 nla_nest_cancel(skb, child_resource_attr);
2541nla_put_failure:
2542 nla_nest_cancel(skb, resource_attr);
2543 return -EMSGSIZE;
2544}
2545
2546static int devlink_resource_fill(struct genl_info *info,
2547 enum devlink_command cmd, int flags)
2548{
2549 struct devlink *devlink = info->user_ptr[0];
2550 struct devlink_resource *resource;
2551 struct nlattr *resources_attr;
2552 struct sk_buff *skb = NULL;
2553 struct nlmsghdr *nlh;
2554 bool incomplete;
2555 void *hdr;
2556 int i;
2557 int err;
2558
2559 resource = list_first_entry(&devlink->resource_list,
2560 struct devlink_resource, list);
2561start_again:
2562 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2563 if (err)
2564 return err;
2565
2566 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
2567 &devlink_nl_family, NLM_F_MULTI, cmd);
2568 if (!hdr) {
2569 nlmsg_free(skb);
2570 return -EMSGSIZE;
2571 }
2572
2573 if (devlink_nl_put_handle(skb, devlink))
2574 goto nla_put_failure;
2575
2576 resources_attr = nla_nest_start(skb, DEVLINK_ATTR_RESOURCE_LIST);
2577 if (!resources_attr)
2578 goto nla_put_failure;
2579
2580 incomplete = false;
2581 i = 0;
2582 list_for_each_entry_from(resource, &devlink->resource_list, list) {
2583 err = devlink_resource_put(devlink, skb, resource);
2584 if (err) {
2585 if (!i)
2586 goto err_resource_put;
2587 incomplete = true;
2588 break;
2589 }
2590 i++;
2591 }
2592 nla_nest_end(skb, resources_attr);
2593 genlmsg_end(skb, hdr);
2594 if (incomplete)
2595 goto start_again;
2596send_done:
2597 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
2598 NLMSG_DONE, 0, flags | NLM_F_MULTI);
2599 if (!nlh) {
2600 err = devlink_dpipe_send_and_alloc_skb(&skb, info);
2601 if (err)
83fe9a96 2602 return err;
d9f9b9a4
AS
2603 goto send_done;
2604 }
2605 return genlmsg_reply(skb, info);
2606
2607nla_put_failure:
2608 err = -EMSGSIZE;
2609err_resource_put:
d9f9b9a4
AS
2610 nlmsg_free(skb);
2611 return err;
2612}
2613
2614static int devlink_nl_cmd_resource_dump(struct sk_buff *skb,
2615 struct genl_info *info)
2616{
2617 struct devlink *devlink = info->user_ptr[0];
2618
2619 if (list_empty(&devlink->resource_list))
2620 return -EOPNOTSUPP;
2621
2622 return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
2623}
2624
2d8dc5bb
AS
2625static int
2626devlink_resources_validate(struct devlink *devlink,
2627 struct devlink_resource *resource,
2628 struct genl_info *info)
2629{
2630 struct list_head *resource_list;
2631 int err = 0;
2632
2633 if (resource)
2634 resource_list = &resource->resource_list;
2635 else
2636 resource_list = &devlink->resource_list;
2637
2638 list_for_each_entry(resource, resource_list, list) {
2639 if (!resource->size_valid)
2640 return -EINVAL;
2641 err = devlink_resources_validate(devlink, resource, info);
2642 if (err)
2643 return err;
2644 }
2645 return err;
2646}
2647
2648static int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
2649{
2650 struct devlink *devlink = info->user_ptr[0];
2651 int err;
2652
2653 if (!devlink->ops->reload)
2654 return -EOPNOTSUPP;
2655
2656 err = devlink_resources_validate(devlink, NULL, info);
2657 if (err) {
2658 NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed");
2659 return err;
2660 }
ac0fc8a1 2661 return devlink->ops->reload(devlink, info->extack);
2d8dc5bb
AS
2662}
2663
76726ccb
JK
2664static int devlink_nl_cmd_flash_update(struct sk_buff *skb,
2665 struct genl_info *info)
2666{
2667 struct devlink *devlink = info->user_ptr[0];
2668 const char *file_name, *component;
2669 struct nlattr *nla_component;
2670
2671 if (!devlink->ops->flash_update)
2672 return -EOPNOTSUPP;
2673
2674 if (!info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME])
2675 return -EINVAL;
2676 file_name = nla_data(info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME]);
2677
2678 nla_component = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT];
2679 component = nla_component ? nla_data(nla_component) : NULL;
2680
2681 return devlink->ops->flash_update(devlink, file_name, component,
2682 info->extack);
2683}
2684
036467c3
MS
2685static const struct devlink_param devlink_param_generic[] = {
2686 {
2687 .id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
2688 .name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
2689 .type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
2690 },
2691 {
2692 .id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
2693 .name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
2694 .type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
2695 },
f567bcda
VV
2696 {
2697 .id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
2698 .name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
2699 .type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
2700 },
f6a69885
AV
2701 {
2702 .id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
2703 .name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
2704 .type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
2705 },
e3b51061
VV
2706 {
2707 .id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
2708 .name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
2709 .type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
2710 },
f61cba42
VV
2711 {
2712 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
2713 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
2714 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
2715 },
16511789
VV
2716 {
2717 .id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
2718 .name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
2719 .type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
2720 },
846e980a
ST
2721 {
2722 .id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
2723 .name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
2724 .type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
2725 },
036467c3 2726};
eabaef18
MS
2727
2728static int devlink_param_generic_verify(const struct devlink_param *param)
2729{
2730 /* verify it match generic parameter by id and name */
2731 if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
2732 return -EINVAL;
2733 if (strcmp(param->name, devlink_param_generic[param->id].name))
2734 return -ENOENT;
2735
2736 WARN_ON(param->type != devlink_param_generic[param->id].type);
2737
2738 return 0;
2739}
2740
2741static int devlink_param_driver_verify(const struct devlink_param *param)
2742{
2743 int i;
2744
2745 if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
2746 return -EINVAL;
2747 /* verify no such name in generic params */
2748 for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
2749 if (!strcmp(param->name, devlink_param_generic[i].name))
2750 return -EEXIST;
2751
2752 return 0;
2753}
2754
2755static struct devlink_param_item *
2756devlink_param_find_by_name(struct list_head *param_list,
2757 const char *param_name)
2758{
2759 struct devlink_param_item *param_item;
2760
2761 list_for_each_entry(param_item, param_list, list)
2762 if (!strcmp(param_item->param->name, param_name))
2763 return param_item;
2764 return NULL;
2765}
2766
ec01aeb1
MS
2767static struct devlink_param_item *
2768devlink_param_find_by_id(struct list_head *param_list, u32 param_id)
2769{
2770 struct devlink_param_item *param_item;
2771
2772 list_for_each_entry(param_item, param_list, list)
2773 if (param_item->param->id == param_id)
2774 return param_item;
2775 return NULL;
2776}
2777
45f05def
MS
2778static bool
2779devlink_param_cmode_is_supported(const struct devlink_param *param,
2780 enum devlink_param_cmode cmode)
2781{
2782 return test_bit(cmode, &param->supported_cmodes);
2783}
2784
2785static int devlink_param_get(struct devlink *devlink,
2786 const struct devlink_param *param,
2787 struct devlink_param_gset_ctx *ctx)
2788{
2789 if (!param->get)
2790 return -EOPNOTSUPP;
2791 return param->get(devlink, param->id, ctx);
2792}
2793
e3b7ca18
MS
2794static int devlink_param_set(struct devlink *devlink,
2795 const struct devlink_param *param,
2796 struct devlink_param_gset_ctx *ctx)
2797{
2798 if (!param->set)
2799 return -EOPNOTSUPP;
2800 return param->set(devlink, param->id, ctx);
2801}
2802
45f05def
MS
2803static int
2804devlink_param_type_to_nla_type(enum devlink_param_type param_type)
2805{
2806 switch (param_type) {
2807 case DEVLINK_PARAM_TYPE_U8:
2808 return NLA_U8;
2809 case DEVLINK_PARAM_TYPE_U16:
2810 return NLA_U16;
2811 case DEVLINK_PARAM_TYPE_U32:
2812 return NLA_U32;
2813 case DEVLINK_PARAM_TYPE_STRING:
2814 return NLA_STRING;
2815 case DEVLINK_PARAM_TYPE_BOOL:
2816 return NLA_FLAG;
2817 default:
2818 return -EINVAL;
2819 }
2820}
2821
2822static int
2823devlink_nl_param_value_fill_one(struct sk_buff *msg,
2824 enum devlink_param_type type,
2825 enum devlink_param_cmode cmode,
2826 union devlink_param_value val)
2827{
2828 struct nlattr *param_value_attr;
2829
2830 param_value_attr = nla_nest_start(msg, DEVLINK_ATTR_PARAM_VALUE);
2831 if (!param_value_attr)
2832 goto nla_put_failure;
2833
2834 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
2835 goto value_nest_cancel;
2836
2837 switch (type) {
2838 case DEVLINK_PARAM_TYPE_U8:
2839 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
2840 goto value_nest_cancel;
2841 break;
2842 case DEVLINK_PARAM_TYPE_U16:
2843 if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
2844 goto value_nest_cancel;
2845 break;
2846 case DEVLINK_PARAM_TYPE_U32:
2847 if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
2848 goto value_nest_cancel;
2849 break;
2850 case DEVLINK_PARAM_TYPE_STRING:
2851 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
2852 val.vstr))
2853 goto value_nest_cancel;
2854 break;
2855 case DEVLINK_PARAM_TYPE_BOOL:
2856 if (val.vbool &&
2857 nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
2858 goto value_nest_cancel;
2859 break;
2860 }
2861
2862 nla_nest_end(msg, param_value_attr);
2863 return 0;
2864
2865value_nest_cancel:
2866 nla_nest_cancel(msg, param_value_attr);
2867nla_put_failure:
2868 return -EMSGSIZE;
2869}
2870
2871static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
f4601dee 2872 unsigned int port_index,
45f05def
MS
2873 struct devlink_param_item *param_item,
2874 enum devlink_command cmd,
2875 u32 portid, u32 seq, int flags)
2876{
2877 union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
7c62cfb8 2878 bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
45f05def
MS
2879 const struct devlink_param *param = param_item->param;
2880 struct devlink_param_gset_ctx ctx;
2881 struct nlattr *param_values_list;
2882 struct nlattr *param_attr;
2883 int nla_type;
2884 void *hdr;
2885 int err;
2886 int i;
2887
2888 /* Get value from driver part to driverinit configuration mode */
2889 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
2890 if (!devlink_param_cmode_is_supported(param, i))
2891 continue;
2892 if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
2893 if (!param_item->driverinit_value_valid)
2894 return -EOPNOTSUPP;
2895 param_value[i] = param_item->driverinit_value;
2896 } else {
7c62cfb8
JP
2897 if (!param_item->published)
2898 continue;
45f05def
MS
2899 ctx.cmode = i;
2900 err = devlink_param_get(devlink, param, &ctx);
2901 if (err)
2902 return err;
2903 param_value[i] = ctx.val;
2904 }
7c62cfb8 2905 param_value_set[i] = true;
45f05def
MS
2906 }
2907
2908 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
2909 if (!hdr)
2910 return -EMSGSIZE;
2911
2912 if (devlink_nl_put_handle(msg, devlink))
2913 goto genlmsg_cancel;
f4601dee 2914
c1e5786d
VV
2915 if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
2916 cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
2917 cmd == DEVLINK_CMD_PORT_PARAM_DEL)
f4601dee
VV
2918 if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
2919 goto genlmsg_cancel;
2920
45f05def
MS
2921 param_attr = nla_nest_start(msg, DEVLINK_ATTR_PARAM);
2922 if (!param_attr)
2923 goto genlmsg_cancel;
2924 if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
2925 goto param_nest_cancel;
2926 if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
2927 goto param_nest_cancel;
2928
2929 nla_type = devlink_param_type_to_nla_type(param->type);
2930 if (nla_type < 0)
2931 goto param_nest_cancel;
2932 if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
2933 goto param_nest_cancel;
2934
2935 param_values_list = nla_nest_start(msg, DEVLINK_ATTR_PARAM_VALUES_LIST);
2936 if (!param_values_list)
2937 goto param_nest_cancel;
2938
2939 for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
7c62cfb8 2940 if (!param_value_set[i])
45f05def
MS
2941 continue;
2942 err = devlink_nl_param_value_fill_one(msg, param->type,
2943 i, param_value[i]);
2944 if (err)
2945 goto values_list_nest_cancel;
2946 }
2947
2948 nla_nest_end(msg, param_values_list);
2949 nla_nest_end(msg, param_attr);
2950 genlmsg_end(msg, hdr);
2951 return 0;
2952
2953values_list_nest_cancel:
2954 nla_nest_end(msg, param_values_list);
2955param_nest_cancel:
2956 nla_nest_cancel(msg, param_attr);
2957genlmsg_cancel:
2958 genlmsg_cancel(msg, hdr);
2959 return -EMSGSIZE;
2960}
2961
ea601e17 2962static void devlink_param_notify(struct devlink *devlink,
c1e5786d 2963 unsigned int port_index,
ea601e17
MS
2964 struct devlink_param_item *param_item,
2965 enum devlink_command cmd)
2966{
2967 struct sk_buff *msg;
2968 int err;
2969
c1e5786d
VV
2970 WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
2971 cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
2972 cmd != DEVLINK_CMD_PORT_PARAM_DEL);
ea601e17
MS
2973
2974 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
2975 if (!msg)
2976 return;
c1e5786d
VV
2977 err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
2978 0, 0, 0);
ea601e17
MS
2979 if (err) {
2980 nlmsg_free(msg);
2981 return;
2982 }
2983
2984 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
2985 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
2986}
2987
45f05def
MS
2988static int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
2989 struct netlink_callback *cb)
2990{
2991 struct devlink_param_item *param_item;
2992 struct devlink *devlink;
2993 int start = cb->args[0];
2994 int idx = 0;
2995 int err;
2996
2997 mutex_lock(&devlink_mutex);
2998 list_for_each_entry(devlink, &devlink_list, list) {
2999 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3000 continue;
3001 mutex_lock(&devlink->lock);
3002 list_for_each_entry(param_item, &devlink->param_list, list) {
3003 if (idx < start) {
3004 idx++;
3005 continue;
3006 }
f4601dee 3007 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
45f05def
MS
3008 DEVLINK_CMD_PARAM_GET,
3009 NETLINK_CB(cb->skb).portid,
3010 cb->nlh->nlmsg_seq,
3011 NLM_F_MULTI);
3012 if (err) {
3013 mutex_unlock(&devlink->lock);
3014 goto out;
3015 }
3016 idx++;
3017 }
3018 mutex_unlock(&devlink->lock);
3019 }
3020out:
3021 mutex_unlock(&devlink_mutex);
3022
3023 cb->args[0] = idx;
3024 return msg->len;
3025}
3026
e3b7ca18
MS
3027static int
3028devlink_param_type_get_from_info(struct genl_info *info,
3029 enum devlink_param_type *param_type)
3030{
3031 if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
3032 return -EINVAL;
3033
3034 switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
3035 case NLA_U8:
3036 *param_type = DEVLINK_PARAM_TYPE_U8;
3037 break;
3038 case NLA_U16:
3039 *param_type = DEVLINK_PARAM_TYPE_U16;
3040 break;
3041 case NLA_U32:
3042 *param_type = DEVLINK_PARAM_TYPE_U32;
3043 break;
3044 case NLA_STRING:
3045 *param_type = DEVLINK_PARAM_TYPE_STRING;
3046 break;
3047 case NLA_FLAG:
3048 *param_type = DEVLINK_PARAM_TYPE_BOOL;
3049 break;
3050 default:
3051 return -EINVAL;
3052 }
3053
3054 return 0;
3055}
3056
3057static int
3058devlink_param_value_get_from_info(const struct devlink_param *param,
3059 struct genl_info *info,
3060 union devlink_param_value *value)
3061{
f355cfcd
MS
3062 int len;
3063
e3b7ca18
MS
3064 if (param->type != DEVLINK_PARAM_TYPE_BOOL &&
3065 !info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA])
3066 return -EINVAL;
3067
3068 switch (param->type) {
3069 case DEVLINK_PARAM_TYPE_U8:
3070 value->vu8 = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3071 break;
3072 case DEVLINK_PARAM_TYPE_U16:
3073 value->vu16 = nla_get_u16(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3074 break;
3075 case DEVLINK_PARAM_TYPE_U32:
3076 value->vu32 = nla_get_u32(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]);
3077 break;
3078 case DEVLINK_PARAM_TYPE_STRING:
f355cfcd
MS
3079 len = strnlen(nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]),
3080 nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
3081 if (len == nla_len(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]) ||
bde74ad1 3082 len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
e3b7ca18 3083 return -EINVAL;
f355cfcd
MS
3084 strcpy(value->vstr,
3085 nla_data(info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA]));
e3b7ca18
MS
3086 break;
3087 case DEVLINK_PARAM_TYPE_BOOL:
3088 value->vbool = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA] ?
3089 true : false;
3090 break;
3091 }
3092 return 0;
3093}
3094
45f05def 3095static struct devlink_param_item *
f4601dee 3096devlink_param_get_from_info(struct list_head *param_list,
45f05def
MS
3097 struct genl_info *info)
3098{
3099 char *param_name;
3100
3101 if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
3102 return NULL;
3103
3104 param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
f4601dee 3105 return devlink_param_find_by_name(param_list, param_name);
45f05def
MS
3106}
3107
3108static int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
3109 struct genl_info *info)
3110{
3111 struct devlink *devlink = info->user_ptr[0];
3112 struct devlink_param_item *param_item;
3113 struct sk_buff *msg;
3114 int err;
3115
f4601dee 3116 param_item = devlink_param_get_from_info(&devlink->param_list, info);
45f05def
MS
3117 if (!param_item)
3118 return -EINVAL;
3119
3120 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3121 if (!msg)
3122 return -ENOMEM;
3123
f4601dee 3124 err = devlink_nl_param_fill(msg, devlink, 0, param_item,
45f05def
MS
3125 DEVLINK_CMD_PARAM_GET,
3126 info->snd_portid, info->snd_seq, 0);
3127 if (err) {
3128 nlmsg_free(msg);
3129 return err;
3130 }
3131
3132 return genlmsg_reply(msg, info);
3133}
3134
9c54873b 3135static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
c1e5786d 3136 unsigned int port_index,
9c54873b
VV
3137 struct list_head *param_list,
3138 struct genl_info *info,
3139 enum devlink_command cmd)
e3b7ca18 3140{
e3b7ca18
MS
3141 enum devlink_param_type param_type;
3142 struct devlink_param_gset_ctx ctx;
3143 enum devlink_param_cmode cmode;
3144 struct devlink_param_item *param_item;
3145 const struct devlink_param *param;
3146 union devlink_param_value value;
3147 int err = 0;
3148
9c54873b 3149 param_item = devlink_param_get_from_info(param_list, info);
e3b7ca18
MS
3150 if (!param_item)
3151 return -EINVAL;
3152 param = param_item->param;
3153 err = devlink_param_type_get_from_info(info, &param_type);
3154 if (err)
3155 return err;
3156 if (param_type != param->type)
3157 return -EINVAL;
3158 err = devlink_param_value_get_from_info(param, info, &value);
3159 if (err)
3160 return err;
3161 if (param->validate) {
3162 err = param->validate(devlink, param->id, value, info->extack);
3163 if (err)
3164 return err;
3165 }
3166
3167 if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
3168 return -EINVAL;
3169 cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3170 if (!devlink_param_cmode_is_supported(param, cmode))
3171 return -EOPNOTSUPP;
3172
3173 if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
1276534c
MS
3174 if (param->type == DEVLINK_PARAM_TYPE_STRING)
3175 strcpy(param_item->driverinit_value.vstr, value.vstr);
3176 else
3177 param_item->driverinit_value = value;
e3b7ca18
MS
3178 param_item->driverinit_value_valid = true;
3179 } else {
3180 if (!param->set)
3181 return -EOPNOTSUPP;
3182 ctx.val = value;
3183 ctx.cmode = cmode;
3184 err = devlink_param_set(devlink, param, &ctx);
3185 if (err)
3186 return err;
3187 }
3188
c1e5786d 3189 devlink_param_notify(devlink, port_index, param_item, cmd);
e3b7ca18
MS
3190 return 0;
3191}
3192
9c54873b
VV
3193static int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
3194 struct genl_info *info)
3195{
3196 struct devlink *devlink = info->user_ptr[0];
3197
c1e5786d 3198 return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
9c54873b
VV
3199 info, DEVLINK_CMD_PARAM_NEW);
3200}
3201
eabaef18 3202static int devlink_param_register_one(struct devlink *devlink,
c1e5786d 3203 unsigned int port_index,
39e6160e 3204 struct list_head *param_list,
c1e5786d
VV
3205 const struct devlink_param *param,
3206 enum devlink_command cmd)
eabaef18
MS
3207{
3208 struct devlink_param_item *param_item;
3209
39e6160e 3210 if (devlink_param_find_by_name(param_list, param->name))
eabaef18
MS
3211 return -EEXIST;
3212
3213 if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
3214 WARN_ON(param->get || param->set);
3215 else
3216 WARN_ON(!param->get || !param->set);
3217
3218 param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
3219 if (!param_item)
3220 return -ENOMEM;
3221 param_item->param = param;
3222
39e6160e 3223 list_add_tail(&param_item->list, param_list);
c1e5786d 3224 devlink_param_notify(devlink, port_index, param_item, cmd);
eabaef18
MS
3225 return 0;
3226}
3227
3228static void devlink_param_unregister_one(struct devlink *devlink,
c1e5786d 3229 unsigned int port_index,
39e6160e 3230 struct list_head *param_list,
c1e5786d
VV
3231 const struct devlink_param *param,
3232 enum devlink_command cmd)
eabaef18
MS
3233{
3234 struct devlink_param_item *param_item;
3235
39e6160e 3236 param_item = devlink_param_find_by_name(param_list, param->name);
eabaef18 3237 WARN_ON(!param_item);
c1e5786d 3238 devlink_param_notify(devlink, port_index, param_item, cmd);
eabaef18
MS
3239 list_del(&param_item->list);
3240 kfree(param_item);
3241}
3242
f4601dee
VV
3243static int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
3244 struct netlink_callback *cb)
3245{
3246 struct devlink_param_item *param_item;
3247 struct devlink_port *devlink_port;
3248 struct devlink *devlink;
3249 int start = cb->args[0];
3250 int idx = 0;
3251 int err;
3252
3253 mutex_lock(&devlink_mutex);
3254 list_for_each_entry(devlink, &devlink_list, list) {
3255 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3256 continue;
3257 mutex_lock(&devlink->lock);
3258 list_for_each_entry(devlink_port, &devlink->port_list, list) {
3259 list_for_each_entry(param_item,
3260 &devlink_port->param_list, list) {
3261 if (idx < start) {
3262 idx++;
3263 continue;
3264 }
3265 err = devlink_nl_param_fill(msg,
3266 devlink_port->devlink,
3267 devlink_port->index, param_item,
3268 DEVLINK_CMD_PORT_PARAM_GET,
3269 NETLINK_CB(cb->skb).portid,
3270 cb->nlh->nlmsg_seq,
3271 NLM_F_MULTI);
3272 if (err) {
3273 mutex_unlock(&devlink->lock);
3274 goto out;
3275 }
3276 idx++;
3277 }
3278 }
3279 mutex_unlock(&devlink->lock);
3280 }
3281out:
3282 mutex_unlock(&devlink_mutex);
3283
3284 cb->args[0] = idx;
3285 return msg->len;
3286}
3287
3288static int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
3289 struct genl_info *info)
3290{
3291 struct devlink_port *devlink_port = info->user_ptr[0];
3292 struct devlink_param_item *param_item;
3293 struct sk_buff *msg;
3294 int err;
3295
3296 param_item = devlink_param_get_from_info(&devlink_port->param_list,
3297 info);
3298 if (!param_item)
3299 return -EINVAL;
3300
3301 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3302 if (!msg)
3303 return -ENOMEM;
3304
3305 err = devlink_nl_param_fill(msg, devlink_port->devlink,
3306 devlink_port->index, param_item,
3307 DEVLINK_CMD_PORT_PARAM_GET,
3308 info->snd_portid, info->snd_seq, 0);
3309 if (err) {
3310 nlmsg_free(msg);
3311 return err;
3312 }
3313
3314 return genlmsg_reply(msg, info);
3315}
3316
9c54873b
VV
3317static int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
3318 struct genl_info *info)
3319{
3320 struct devlink_port *devlink_port = info->user_ptr[0];
3321
3322 return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
c1e5786d
VV
3323 devlink_port->index,
3324 &devlink_port->param_list, info,
3325 DEVLINK_CMD_PORT_PARAM_NEW);
9c54873b
VV
3326}
3327
a006d467
AV
3328static int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
3329 struct devlink *devlink,
3330 struct devlink_snapshot *snapshot)
3331{
3332 struct nlattr *snap_attr;
3333 int err;
3334
3335 snap_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
3336 if (!snap_attr)
3337 return -EINVAL;
3338
3339 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
3340 if (err)
3341 goto nla_put_failure;
3342
3343 nla_nest_end(msg, snap_attr);
3344 return 0;
3345
3346nla_put_failure:
3347 nla_nest_cancel(msg, snap_attr);
3348 return err;
3349}
3350
3351static int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
3352 struct devlink *devlink,
3353 struct devlink_region *region)
3354{
3355 struct devlink_snapshot *snapshot;
3356 struct nlattr *snapshots_attr;
3357 int err;
3358
3359 snapshots_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_SNAPSHOTS);
3360 if (!snapshots_attr)
3361 return -EINVAL;
3362
3363 list_for_each_entry(snapshot, &region->snapshot_list, list) {
3364 err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
3365 if (err)
3366 goto nla_put_failure;
3367 }
3368
3369 nla_nest_end(msg, snapshots_attr);
3370 return 0;
3371
3372nla_put_failure:
3373 nla_nest_cancel(msg, snapshots_attr);
3374 return err;
3375}
3376
d8db7ea5
AV
3377static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
3378 enum devlink_command cmd, u32 portid,
3379 u32 seq, int flags,
3380 struct devlink_region *region)
3381{
3382 void *hdr;
3383 int err;
3384
3385 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3386 if (!hdr)
3387 return -EMSGSIZE;
3388
3389 err = devlink_nl_put_handle(msg, devlink);
3390 if (err)
3391 goto nla_put_failure;
3392
3393 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->name);
3394 if (err)
3395 goto nla_put_failure;
3396
3397 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3398 region->size,
3399 DEVLINK_ATTR_PAD);
3400 if (err)
3401 goto nla_put_failure;
3402
a006d467
AV
3403 err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
3404 if (err)
3405 goto nla_put_failure;
3406
d8db7ea5
AV
3407 genlmsg_end(msg, hdr);
3408 return 0;
3409
3410nla_put_failure:
3411 genlmsg_cancel(msg, hdr);
3412 return err;
3413}
3414
866319bb
AV
3415static void devlink_nl_region_notify(struct devlink_region *region,
3416 struct devlink_snapshot *snapshot,
3417 enum devlink_command cmd)
3418{
3419 struct devlink *devlink = region->devlink;
3420 struct sk_buff *msg;
3421 void *hdr;
3422 int err;
3423
3424 WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
3425
3426 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3427 if (!msg)
3428 return;
3429
3430 hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
3431 if (!hdr)
3432 goto out_free_msg;
3433
3434 err = devlink_nl_put_handle(msg, devlink);
3435 if (err)
3436 goto out_cancel_msg;
3437
3438 err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
3439 region->name);
3440 if (err)
3441 goto out_cancel_msg;
3442
3443 if (snapshot) {
3444 err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
3445 snapshot->id);
3446 if (err)
3447 goto out_cancel_msg;
3448 } else {
3449 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
3450 region->size, DEVLINK_ATTR_PAD);
3451 if (err)
3452 goto out_cancel_msg;
3453 }
3454 genlmsg_end(msg, hdr);
3455
3456 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
3457 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
3458
3459 return;
3460
3461out_cancel_msg:
3462 genlmsg_cancel(msg, hdr);
3463out_free_msg:
3464 nlmsg_free(msg);
3465}
3466
d8db7ea5
AV
3467static int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
3468 struct genl_info *info)
3469{
3470 struct devlink *devlink = info->user_ptr[0];
3471 struct devlink_region *region;
3472 const char *region_name;
3473 struct sk_buff *msg;
3474 int err;
3475
3476 if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
3477 return -EINVAL;
3478
3479 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3480 region = devlink_region_get_by_name(devlink, region_name);
3481 if (!region)
3482 return -EINVAL;
3483
3484 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3485 if (!msg)
3486 return -ENOMEM;
3487
3488 err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
3489 info->snd_portid, info->snd_seq, 0,
3490 region);
3491 if (err) {
3492 nlmsg_free(msg);
3493 return err;
3494 }
3495
3496 return genlmsg_reply(msg, info);
3497}
3498
3499static int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
3500 struct netlink_callback *cb)
3501{
3502 struct devlink_region *region;
3503 struct devlink *devlink;
3504 int start = cb->args[0];
3505 int idx = 0;
3506 int err;
3507
3508 mutex_lock(&devlink_mutex);
3509 list_for_each_entry(devlink, &devlink_list, list) {
3510 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3511 continue;
3512
3513 mutex_lock(&devlink->lock);
3514 list_for_each_entry(region, &devlink->region_list, list) {
3515 if (idx < start) {
3516 idx++;
3517 continue;
3518 }
3519 err = devlink_nl_region_fill(msg, devlink,
3520 DEVLINK_CMD_REGION_GET,
3521 NETLINK_CB(cb->skb).portid,
3522 cb->nlh->nlmsg_seq,
3523 NLM_F_MULTI, region);
3524 if (err) {
3525 mutex_unlock(&devlink->lock);
3526 goto out;
3527 }
3528 idx++;
3529 }
3530 mutex_unlock(&devlink->lock);
3531 }
3532out:
3533 mutex_unlock(&devlink_mutex);
3534 cb->args[0] = idx;
3535 return msg->len;
3536}
3537
866319bb
AV
3538static int devlink_nl_cmd_region_del(struct sk_buff *skb,
3539 struct genl_info *info)
3540{
3541 struct devlink *devlink = info->user_ptr[0];
3542 struct devlink_snapshot *snapshot;
3543 struct devlink_region *region;
3544 const char *region_name;
3545 u32 snapshot_id;
3546
3547 if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
3548 !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
3549 return -EINVAL;
3550
3551 region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
3552 snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3553
3554 region = devlink_region_get_by_name(devlink, region_name);
3555 if (!region)
3556 return -EINVAL;
3557
3558 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3559 if (!snapshot)
3560 return -EINVAL;
3561
3562 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
3563 devlink_region_snapshot_del(snapshot);
3564 return 0;
3565}
3566
4e54795a
AV
3567static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
3568 struct devlink *devlink,
3569 u8 *chunk, u32 chunk_size,
3570 u64 addr)
3571{
3572 struct nlattr *chunk_attr;
3573 int err;
3574
3575 chunk_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_CHUNK);
3576 if (!chunk_attr)
3577 return -EINVAL;
3578
3579 err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
3580 if (err)
3581 goto nla_put_failure;
3582
3583 err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
3584 DEVLINK_ATTR_PAD);
3585 if (err)
3586 goto nla_put_failure;
3587
3588 nla_nest_end(msg, chunk_attr);
3589 return 0;
3590
3591nla_put_failure:
3592 nla_nest_cancel(msg, chunk_attr);
3593 return err;
3594}
3595
3596#define DEVLINK_REGION_READ_CHUNK_SIZE 256
3597
3598static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
3599 struct devlink *devlink,
3600 struct devlink_region *region,
3601 struct nlattr **attrs,
3602 u64 start_offset,
3603 u64 end_offset,
3604 bool dump,
3605 u64 *new_offset)
3606{
3607 struct devlink_snapshot *snapshot;
3608 u64 curr_offset = start_offset;
3609 u32 snapshot_id;
3610 int err = 0;
3611
3612 *new_offset = start_offset;
3613
3614 snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3615 snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3616 if (!snapshot)
3617 return -EINVAL;
3618
3619 if (end_offset > snapshot->data_len || dump)
3620 end_offset = snapshot->data_len;
3621
3622 while (curr_offset < end_offset) {
3623 u32 data_size;
3624 u8 *data;
3625
3626 if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
3627 data_size = end_offset - curr_offset;
3628 else
3629 data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
3630
3631 data = &snapshot->data[curr_offset];
3632 err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
3633 data, data_size,
3634 curr_offset);
3635 if (err)
3636 break;
3637
3638 curr_offset += data_size;
3639 }
3640 *new_offset = curr_offset;
3641
3642 return err;
3643}
3644
3645static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
3646 struct netlink_callback *cb)
3647{
3648 u64 ret_offset, start_offset, end_offset = 0;
4e54795a
AV
3649 struct devlink_region *region;
3650 struct nlattr *chunks_attr;
3651 const char *region_name;
3652 struct devlink *devlink;
68750561 3653 struct nlattr **attrs;
4e54795a
AV
3654 bool dump = true;
3655 void *hdr;
3656 int err;
3657
3658 start_offset = *((u64 *)&cb->args[0]);
3659
68750561
JK
3660 attrs = kmalloc_array(DEVLINK_ATTR_MAX + 1, sizeof(*attrs), GFP_KERNEL);
3661 if (!attrs)
3662 return -ENOMEM;
3663
4e54795a 3664 err = nlmsg_parse(cb->nlh, GENL_HDRLEN + devlink_nl_family.hdrsize,
3b0f31f2
JB
3665 attrs, DEVLINK_ATTR_MAX, devlink_nl_family.policy,
3666 cb->extack);
4e54795a 3667 if (err)
68750561 3668 goto out_free;
4e54795a 3669
dac7c08f 3670 mutex_lock(&devlink_mutex);
4e54795a 3671 devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
fdd41ec2
PP
3672 if (IS_ERR(devlink)) {
3673 err = PTR_ERR(devlink);
dac7c08f 3674 goto out_dev;
fdd41ec2 3675 }
4e54795a 3676
4e54795a
AV
3677 mutex_lock(&devlink->lock);
3678
3679 if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
fdd41ec2
PP
3680 !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) {
3681 err = -EINVAL;
4e54795a 3682 goto out_unlock;
fdd41ec2 3683 }
4e54795a
AV
3684
3685 region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
3686 region = devlink_region_get_by_name(devlink, region_name);
fdd41ec2
PP
3687 if (!region) {
3688 err = -EINVAL;
4e54795a 3689 goto out_unlock;
fdd41ec2 3690 }
4e54795a
AV
3691
3692 hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
3693 &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
3694 DEVLINK_CMD_REGION_READ);
fdd41ec2
PP
3695 if (!hdr) {
3696 err = -EMSGSIZE;
4e54795a 3697 goto out_unlock;
fdd41ec2 3698 }
4e54795a
AV
3699
3700 err = devlink_nl_put_handle(skb, devlink);
3701 if (err)
3702 goto nla_put_failure;
3703
3704 err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
3705 if (err)
3706 goto nla_put_failure;
3707
3708 chunks_attr = nla_nest_start(skb, DEVLINK_ATTR_REGION_CHUNKS);
fdd41ec2
PP
3709 if (!chunks_attr) {
3710 err = -EMSGSIZE;
4e54795a 3711 goto nla_put_failure;
fdd41ec2 3712 }
4e54795a
AV
3713
3714 if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
3715 attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
3716 if (!start_offset)
3717 start_offset =
3718 nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3719
3720 end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3721 end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
3722 dump = false;
3723 }
3724
3725 err = devlink_nl_region_read_snapshot_fill(skb, devlink,
3726 region, attrs,
3727 start_offset,
3728 end_offset, dump,
3729 &ret_offset);
3730
3731 if (err && err != -EMSGSIZE)
3732 goto nla_put_failure;
3733
3734 /* Check if there was any progress done to prevent infinite loop */
fdd41ec2
PP
3735 if (ret_offset == start_offset) {
3736 err = -EINVAL;
4e54795a 3737 goto nla_put_failure;
fdd41ec2 3738 }
4e54795a
AV
3739
3740 *((u64 *)&cb->args[0]) = ret_offset;
3741
3742 nla_nest_end(skb, chunks_attr);
3743 genlmsg_end(skb, hdr);
3744 mutex_unlock(&devlink->lock);
3745 mutex_unlock(&devlink_mutex);
68750561 3746 kfree(attrs);
4e54795a
AV
3747
3748 return skb->len;
3749
3750nla_put_failure:
3751 genlmsg_cancel(skb, hdr);
3752out_unlock:
3753 mutex_unlock(&devlink->lock);
dac7c08f 3754out_dev:
4e54795a 3755 mutex_unlock(&devlink_mutex);
68750561
JK
3756out_free:
3757 kfree(attrs);
fdd41ec2 3758 return err;
4e54795a
AV
3759}
3760
f9cf2288
JK
3761struct devlink_info_req {
3762 struct sk_buff *msg;
3763};
3764
3765int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
3766{
3767 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
3768}
3769EXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
3770
3771int devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
3772{
3773 return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
3774}
3775EXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
3776
fc6fae7d
JK
3777static int devlink_info_version_put(struct devlink_info_req *req, int attr,
3778 const char *version_name,
3779 const char *version_value)
3780{
3781 struct nlattr *nest;
3782 int err;
3783
3784 nest = nla_nest_start(req->msg, attr);
3785 if (!nest)
3786 return -EMSGSIZE;
3787
3788 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
3789 version_name);
3790 if (err)
3791 goto nla_put_failure;
3792
3793 err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
3794 version_value);
3795 if (err)
3796 goto nla_put_failure;
3797
3798 nla_nest_end(req->msg, nest);
3799
3800 return 0;
3801
3802nla_put_failure:
3803 nla_nest_cancel(req->msg, nest);
3804 return err;
3805}
3806
3807int devlink_info_version_fixed_put(struct devlink_info_req *req,
3808 const char *version_name,
3809 const char *version_value)
3810{
3811 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
3812 version_name, version_value);
3813}
3814EXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
3815
3816int devlink_info_version_stored_put(struct devlink_info_req *req,
3817 const char *version_name,
3818 const char *version_value)
3819{
3820 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
3821 version_name, version_value);
3822}
3823EXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
3824
3825int devlink_info_version_running_put(struct devlink_info_req *req,
3826 const char *version_name,
3827 const char *version_value)
3828{
3829 return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
3830 version_name, version_value);
3831}
3832EXPORT_SYMBOL_GPL(devlink_info_version_running_put);
3833
f9cf2288
JK
3834static int
3835devlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
3836 enum devlink_command cmd, u32 portid,
3837 u32 seq, int flags, struct netlink_ext_ack *extack)
3838{
3839 struct devlink_info_req req;
3840 void *hdr;
3841 int err;
3842
3843 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
3844 if (!hdr)
3845 return -EMSGSIZE;
3846
3847 err = -EMSGSIZE;
3848 if (devlink_nl_put_handle(msg, devlink))
3849 goto err_cancel_msg;
3850
3851 req.msg = msg;
3852 err = devlink->ops->info_get(devlink, &req, extack);
3853 if (err)
3854 goto err_cancel_msg;
3855
3856 genlmsg_end(msg, hdr);
3857 return 0;
3858
3859err_cancel_msg:
3860 genlmsg_cancel(msg, hdr);
3861 return err;
3862}
3863
3864static int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
3865 struct genl_info *info)
3866{
3867 struct devlink *devlink = info->user_ptr[0];
3868 struct sk_buff *msg;
3869 int err;
3870
be6fe1d8 3871 if (!devlink->ops->info_get)
f9cf2288
JK
3872 return -EOPNOTSUPP;
3873
3874 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
3875 if (!msg)
3876 return -ENOMEM;
3877
3878 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
3879 info->snd_portid, info->snd_seq, 0,
3880 info->extack);
3881 if (err) {
3882 nlmsg_free(msg);
3883 return err;
3884 }
3885
3886 return genlmsg_reply(msg, info);
3887}
3888
3889static int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
3890 struct netlink_callback *cb)
3891{
3892 struct devlink *devlink;
3893 int start = cb->args[0];
3894 int idx = 0;
3895 int err;
3896
3897 mutex_lock(&devlink_mutex);
3898 list_for_each_entry(devlink, &devlink_list, list) {
3899 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
3900 continue;
3901 if (idx < start) {
3902 idx++;
3903 continue;
3904 }
3905
c493b09b
JP
3906 if (!devlink->ops->info_get) {
3907 idx++;
3908 continue;
3909 }
3910
f9cf2288
JK
3911 mutex_lock(&devlink->lock);
3912 err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
3913 NETLINK_CB(cb->skb).portid,
3914 cb->nlh->nlmsg_seq, NLM_F_MULTI,
3915 cb->extack);
3916 mutex_unlock(&devlink->lock);
3917 if (err)
3918 break;
3919 idx++;
3920 }
3921 mutex_unlock(&devlink_mutex);
3922
3923 cb->args[0] = idx;
3924 return msg->len;
3925}
3926
1db64e87
EBE
3927struct devlink_fmsg_item {
3928 struct list_head list;
3929 int attrtype;
3930 u8 nla_type;
3931 u16 len;
3932 int value[0];
3933};
3934
3935struct devlink_fmsg {
3936 struct list_head item_list;
3937};
3938
3939static struct devlink_fmsg *devlink_fmsg_alloc(void)
3940{
3941 struct devlink_fmsg *fmsg;
3942
3943 fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
3944 if (!fmsg)
3945 return NULL;
3946
3947 INIT_LIST_HEAD(&fmsg->item_list);
3948
3949 return fmsg;
3950}
3951
3952static void devlink_fmsg_free(struct devlink_fmsg *fmsg)
3953{
3954 struct devlink_fmsg_item *item, *tmp;
3955
3956 list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
3957 list_del(&item->list);
3958 kfree(item);
3959 }
3960 kfree(fmsg);
3961}
3962
3963static int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
3964 int attrtype)
3965{
3966 struct devlink_fmsg_item *item;
3967
3968 item = kzalloc(sizeof(*item), GFP_KERNEL);
3969 if (!item)
3970 return -ENOMEM;
3971
3972 item->attrtype = attrtype;
3973 list_add_tail(&item->list, &fmsg->item_list);
3974
3975 return 0;
3976}
3977
3978int devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
3979{
3980 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
3981}
3982EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
3983
3984static int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
3985{
3986 return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
3987}
3988
3989int devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
3990{
3991 return devlink_fmsg_nest_end(fmsg);
3992}
3993EXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
3994
3995#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
3996
3997static int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
3998{
3999 struct devlink_fmsg_item *item;
4000
4001 if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
4002 return -EMSGSIZE;
4003
4004 item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
4005 if (!item)
4006 return -ENOMEM;
4007
4008 item->nla_type = NLA_NUL_STRING;
4009 item->len = strlen(name) + 1;
4010 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
4011 memcpy(&item->value, name, item->len);
4012 list_add_tail(&item->list, &fmsg->item_list);
4013
4014 return 0;
4015}
4016
4017int devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
4018{
4019 int err;
4020
4021 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
4022 if (err)
4023 return err;
4024
4025 err = devlink_fmsg_put_name(fmsg, name);
4026 if (err)
4027 return err;
4028
4029 return 0;
4030}
4031EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
4032
4033int devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
4034{
4035 return devlink_fmsg_nest_end(fmsg);
4036}
4037EXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
4038
4039int devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
4040 const char *name)
4041{
4042 int err;
4043
4044 err = devlink_fmsg_pair_nest_start(fmsg, name);
4045 if (err)
4046 return err;
4047
4048 err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
4049 if (err)
4050 return err;
4051
4052 return 0;
4053}
4054EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
4055
4056int devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
4057{
4058 int err;
4059
4060 err = devlink_fmsg_nest_end(fmsg);
4061 if (err)
4062 return err;
4063
4064 err = devlink_fmsg_nest_end(fmsg);
4065 if (err)
4066 return err;
4067
4068 return 0;
4069}
4070EXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
4071
4072static int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
4073 const void *value, u16 value_len,
4074 u8 value_nla_type)
4075{
4076 struct devlink_fmsg_item *item;
4077
4078 if (value_len > DEVLINK_FMSG_MAX_SIZE)
4079 return -EMSGSIZE;
4080
4081 item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
4082 if (!item)
4083 return -ENOMEM;
4084
4085 item->nla_type = value_nla_type;
4086 item->len = value_len;
4087 item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4088 memcpy(&item->value, value, item->len);
4089 list_add_tail(&item->list, &fmsg->item_list);
4090
4091 return 0;
4092}
4093
4094int devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
4095{
4096 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
4097}
4098EXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
4099
4100int devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
4101{
4102 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
4103}
4104EXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
4105
4106int devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
4107{
4108 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
4109}
4110EXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
4111
4112int devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
4113{
4114 return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
4115}
4116EXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
4117
4118int devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
4119{
4120 return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
4121 NLA_NUL_STRING);
4122}
4123EXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
4124
4125int devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
4126 u16 value_len)
4127{
4128 return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
4129}
4130EXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
4131
4132int devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
4133 bool value)
4134{
4135 int err;
4136
4137 err = devlink_fmsg_pair_nest_start(fmsg, name);
4138 if (err)
4139 return err;
4140
4141 err = devlink_fmsg_bool_put(fmsg, value);
4142 if (err)
4143 return err;
4144
4145 err = devlink_fmsg_pair_nest_end(fmsg);
4146 if (err)
4147 return err;
4148
4149 return 0;
4150}
4151EXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
4152
4153int devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
4154 u8 value)
4155{
4156 int err;
4157
4158 err = devlink_fmsg_pair_nest_start(fmsg, name);
4159 if (err)
4160 return err;
4161
4162 err = devlink_fmsg_u8_put(fmsg, value);
4163 if (err)
4164 return err;
4165
4166 err = devlink_fmsg_pair_nest_end(fmsg);
4167 if (err)
4168 return err;
4169
4170 return 0;
4171}
4172EXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
4173
4174int devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
4175 u32 value)
4176{
4177 int err;
4178
4179 err = devlink_fmsg_pair_nest_start(fmsg, name);
4180 if (err)
4181 return err;
4182
4183 err = devlink_fmsg_u32_put(fmsg, value);
4184 if (err)
4185 return err;
4186
4187 err = devlink_fmsg_pair_nest_end(fmsg);
4188 if (err)
4189 return err;
4190
4191 return 0;
4192}
4193EXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
4194
4195int devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
4196 u64 value)
4197{
4198 int err;
4199
4200 err = devlink_fmsg_pair_nest_start(fmsg, name);
4201 if (err)
4202 return err;
4203
4204 err = devlink_fmsg_u64_put(fmsg, value);
4205 if (err)
4206 return err;
4207
4208 err = devlink_fmsg_pair_nest_end(fmsg);
4209 if (err)
4210 return err;
4211
4212 return 0;
4213}
4214EXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
4215
4216int devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
4217 const char *value)
4218{
4219 int err;
4220
4221 err = devlink_fmsg_pair_nest_start(fmsg, name);
4222 if (err)
4223 return err;
4224
4225 err = devlink_fmsg_string_put(fmsg, value);
4226 if (err)
4227 return err;
4228
4229 err = devlink_fmsg_pair_nest_end(fmsg);
4230 if (err)
4231 return err;
4232
4233 return 0;
4234}
4235EXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
4236
4237int devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
4238 const void *value, u16 value_len)
4239{
4240 int err;
4241
4242 err = devlink_fmsg_pair_nest_start(fmsg, name);
4243 if (err)
4244 return err;
4245
4246 err = devlink_fmsg_binary_put(fmsg, value, value_len);
4247 if (err)
4248 return err;
4249
4250 err = devlink_fmsg_pair_nest_end(fmsg);
4251 if (err)
4252 return err;
4253
4254 return 0;
4255}
4256EXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
4257
4258static int
4259devlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4260{
4261 switch (msg->nla_type) {
4262 case NLA_FLAG:
4263 case NLA_U8:
4264 case NLA_U32:
4265 case NLA_U64:
4266 case NLA_NUL_STRING:
4267 case NLA_BINARY:
4268 return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
4269 msg->nla_type);
4270 default:
4271 return -EINVAL;
4272 }
4273}
4274
4275static int
4276devlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
4277{
4278 int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
4279 u8 tmp;
4280
4281 switch (msg->nla_type) {
4282 case NLA_FLAG:
4283 /* Always provide flag data, regardless of its value */
4284 tmp = *(bool *) msg->value;
4285
4286 return nla_put_u8(skb, attrtype, tmp);
4287 case NLA_U8:
4288 return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
4289 case NLA_U32:
4290 return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
4291 case NLA_U64:
4292 return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
4293 DEVLINK_ATTR_PAD);
4294 case NLA_NUL_STRING:
4295 return nla_put_string(skb, attrtype, (char *) &msg->value);
4296 case NLA_BINARY:
4297 return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
4298 default:
4299 return -EINVAL;
4300 }
4301}
4302
4303static int
4304devlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
4305 int *start)
4306{
4307 struct devlink_fmsg_item *item;
4308 struct nlattr *fmsg_nlattr;
4309 int i = 0;
4310 int err;
4311
4312 fmsg_nlattr = nla_nest_start(skb, DEVLINK_ATTR_FMSG);
4313 if (!fmsg_nlattr)
4314 return -EMSGSIZE;
4315
4316 list_for_each_entry(item, &fmsg->item_list, list) {
4317 if (i < *start) {
4318 i++;
4319 continue;
4320 }
4321
4322 switch (item->attrtype) {
4323 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
4324 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
4325 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
4326 case DEVLINK_ATTR_FMSG_NEST_END:
4327 err = nla_put_flag(skb, item->attrtype);
4328 break;
4329 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
4330 err = devlink_fmsg_item_fill_type(item, skb);
4331 if (err)
4332 break;
4333 err = devlink_fmsg_item_fill_data(item, skb);
4334 break;
4335 case DEVLINK_ATTR_FMSG_OBJ_NAME:
4336 err = nla_put_string(skb, item->attrtype,
4337 (char *) &item->value);
4338 break;
4339 default:
4340 err = -EINVAL;
4341 break;
4342 }
4343 if (!err)
4344 *start = ++i;
4345 else
4346 break;
4347 }
4348
4349 nla_nest_end(skb, fmsg_nlattr);
4350 return err;
4351}
4352
4353static int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
4354 struct genl_info *info,
4355 enum devlink_command cmd, int flags)
4356{
4357 struct nlmsghdr *nlh;
4358 struct sk_buff *skb;
4359 bool last = false;
4360 int index = 0;
4361 void *hdr;
4362 int err;
4363
4364 while (!last) {
4365 int tmp_index = index;
4366
4367 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4368 if (!skb)
4369 return -ENOMEM;
4370
4371 hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
4372 &devlink_nl_family, flags | NLM_F_MULTI, cmd);
4373 if (!hdr) {
4374 err = -EMSGSIZE;
4375 goto nla_put_failure;
4376 }
4377
4378 err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
4379 if (!err)
4380 last = true;
4381 else if (err != -EMSGSIZE || tmp_index == index)
4382 goto nla_put_failure;
4383
4384 genlmsg_end(skb, hdr);
4385 err = genlmsg_reply(skb, info);
4386 if (err)
4387 return err;
4388 }
4389
4390 skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
4391 if (!skb)
4392 return -ENOMEM;
4393 nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
4394 NLMSG_DONE, 0, flags | NLM_F_MULTI);
4395 if (!nlh) {
4396 err = -EMSGSIZE;
4397 goto nla_put_failure;
4398 }
1db64e87 4399
fde55ea7 4400 return genlmsg_reply(skb, info);
1db64e87
EBE
4401
4402nla_put_failure:
4403 nlmsg_free(skb);
4404 return err;
4405}
4406
a0bdcc59
EBE
4407struct devlink_health_reporter {
4408 struct list_head list;
4409 void *priv;
4410 const struct devlink_health_reporter_ops *ops;
4411 struct devlink *devlink;
c8e1da0b
EBE
4412 struct devlink_fmsg *dump_fmsg;
4413 struct mutex dump_lock; /* lock parallel read/write from dump buffers */
a0bdcc59
EBE
4414 u64 graceful_period;
4415 bool auto_recover;
4416 u8 health_state;
c8e1da0b
EBE
4417 u64 dump_ts;
4418 u64 error_count;
4419 u64 recovery_count;
4420 u64 last_recovery_ts;
4421};
4422
a0bdcc59
EBE
4423void *
4424devlink_health_reporter_priv(struct devlink_health_reporter *reporter)
4425{
4426 return reporter->priv;
4427}
4428EXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
4429
4430static struct devlink_health_reporter *
4431devlink_health_reporter_find_by_name(struct devlink *devlink,
4432 const char *reporter_name)
4433{
4434 struct devlink_health_reporter *reporter;
4435
4436 list_for_each_entry(reporter, &devlink->reporter_list, list)
4437 if (!strcmp(reporter->ops->name, reporter_name))
4438 return reporter;
4439 return NULL;
4440}
4441
4442/**
4443 * devlink_health_reporter_create - create devlink health reporter
4444 *
4445 * @devlink: devlink
4446 * @ops: ops
4447 * @graceful_period: to avoid recovery loops, in msecs
4448 * @auto_recover: auto recover when error occurs
4449 * @priv: priv
4450 */
4451struct devlink_health_reporter *
4452devlink_health_reporter_create(struct devlink *devlink,
4453 const struct devlink_health_reporter_ops *ops,
4454 u64 graceful_period, bool auto_recover,
4455 void *priv)
4456{
4457 struct devlink_health_reporter *reporter;
4458
4459 mutex_lock(&devlink->lock);
4460 if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
4461 reporter = ERR_PTR(-EEXIST);
4462 goto unlock;
4463 }
4464
4465 if (WARN_ON(auto_recover && !ops->recover) ||
4466 WARN_ON(graceful_period && !ops->recover)) {
4467 reporter = ERR_PTR(-EINVAL);
4468 goto unlock;
4469 }
4470
4471 reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
4472 if (!reporter) {
4473 reporter = ERR_PTR(-ENOMEM);
4474 goto unlock;
4475 }
4476
4477 reporter->priv = priv;
4478 reporter->ops = ops;
4479 reporter->devlink = devlink;
4480 reporter->graceful_period = graceful_period;
4481 reporter->auto_recover = auto_recover;
c8e1da0b 4482 mutex_init(&reporter->dump_lock);
a0bdcc59
EBE
4483 list_add_tail(&reporter->list, &devlink->reporter_list);
4484unlock:
4485 mutex_unlock(&devlink->lock);
4486 return reporter;
4487}
4488EXPORT_SYMBOL_GPL(devlink_health_reporter_create);
4489
4490/**
4491 * devlink_health_reporter_destroy - destroy devlink health reporter
4492 *
4493 * @reporter: devlink health reporter to destroy
4494 */
4495void
4496devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
4497{
4498 mutex_lock(&reporter->devlink->lock);
4499 list_del(&reporter->list);
375cf8c6 4500 mutex_destroy(&reporter->dump_lock);
a0bdcc59 4501 mutex_unlock(&reporter->devlink->lock);
c8e1da0b
EBE
4502 if (reporter->dump_fmsg)
4503 devlink_fmsg_free(reporter->dump_fmsg);
a0bdcc59
EBE
4504 kfree(reporter);
4505}
4506EXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
4507
3167b27a
EBE
4508void
4509devlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
4510 enum devlink_health_reporter_state state)
4511{
4512 if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
4513 state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
4514 return;
4515
4516 if (reporter->health_state == state)
4517 return;
4518
4519 reporter->health_state = state;
4520 trace_devlink_health_reporter_state_update(reporter->devlink,
4521 reporter->ops->name, state);
4522}
4523EXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
4524
c8e1da0b
EBE
4525static int
4526devlink_health_reporter_recover(struct devlink_health_reporter *reporter,
4527 void *priv_ctx)
4528{
4529 int err;
4530
4531 if (!reporter->ops->recover)
4532 return -EOPNOTSUPP;
4533
4534 err = reporter->ops->recover(reporter, priv_ctx);
4535 if (err)
4536 return err;
4537
4538 reporter->recovery_count++;
4539 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
4540 reporter->last_recovery_ts = jiffies;
4541
4542 return 0;
4543}
4544
4545static void
4546devlink_health_dump_clear(struct devlink_health_reporter *reporter)
4547{
4548 if (!reporter->dump_fmsg)
4549 return;
4550 devlink_fmsg_free(reporter->dump_fmsg);
4551 reporter->dump_fmsg = NULL;
4552}
4553
4554static int devlink_health_do_dump(struct devlink_health_reporter *reporter,
4555 void *priv_ctx)
4556{
4557 int err;
4558
4559 if (!reporter->ops->dump)
4560 return 0;
4561
4562 if (reporter->dump_fmsg)
4563 return 0;
4564
4565 reporter->dump_fmsg = devlink_fmsg_alloc();
4566 if (!reporter->dump_fmsg) {
4567 err = -ENOMEM;
4568 return err;
4569 }
4570
4571 err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
4572 if (err)
4573 goto dump_err;
4574
4575 err = reporter->ops->dump(reporter, reporter->dump_fmsg,
4576 priv_ctx);
4577 if (err)
4578 goto dump_err;
4579
4580 err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
4581 if (err)
4582 goto dump_err;
4583
4584 reporter->dump_ts = jiffies;
4585
4586 return 0;
4587
4588dump_err:
4589 devlink_health_dump_clear(reporter);
4590 return err;
4591}
4592
4593int devlink_health_report(struct devlink_health_reporter *reporter,
4594 const char *msg, void *priv_ctx)
4595{
a0a21adb 4596 enum devlink_health_reporter_state prev_health_state;
c8e1da0b
EBE
4597 struct devlink *devlink = reporter->devlink;
4598
4599 /* write a log message of the current error */
4600 WARN_ON(!msg);
4601 trace_devlink_health_report(devlink, reporter->ops->name, msg);
4602 reporter->error_count++;
a0a21adb
EBE
4603 prev_health_state = reporter->health_state;
4604 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
c8e1da0b
EBE
4605
4606 /* abort if the previous error wasn't recovered */
4607 if (reporter->auto_recover &&
a0a21adb 4608 (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
c8e1da0b
EBE
4609 jiffies - reporter->last_recovery_ts <
4610 msecs_to_jiffies(reporter->graceful_period))) {
4611 trace_devlink_health_recover_aborted(devlink,
4612 reporter->ops->name,
4613 reporter->health_state,
4614 jiffies -
4615 reporter->last_recovery_ts);
4616 return -ECANCELED;
4617 }
4618
4619 reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
4620
4621 mutex_lock(&reporter->dump_lock);
4622 /* store current dump of current error, for later analysis */
4623 devlink_health_do_dump(reporter, priv_ctx);
4624 mutex_unlock(&reporter->dump_lock);
4625
4626 if (reporter->auto_recover)
4627 return devlink_health_reporter_recover(reporter, priv_ctx);
4628
4629 return 0;
4630}
4631EXPORT_SYMBOL_GPL(devlink_health_report);
4632
7afe335a
EBE
4633static struct devlink_health_reporter *
4634devlink_health_reporter_get_from_info(struct devlink *devlink,
4635 struct genl_info *info)
4636{
4637 char *reporter_name;
4638
4639 if (!info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
4640 return NULL;
4641
4642 reporter_name =
4643 nla_data(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
4644 return devlink_health_reporter_find_by_name(devlink, reporter_name);
4645}
4646
4647static int
4648devlink_nl_health_reporter_fill(struct sk_buff *msg,
4649 struct devlink *devlink,
4650 struct devlink_health_reporter *reporter,
4651 enum devlink_command cmd, u32 portid,
4652 u32 seq, int flags)
4653{
4654 struct nlattr *reporter_attr;
4655 void *hdr;
4656
4657 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
4658 if (!hdr)
4659 return -EMSGSIZE;
4660
4661 if (devlink_nl_put_handle(msg, devlink))
4662 goto genlmsg_cancel;
4663
4664 reporter_attr = nla_nest_start(msg, DEVLINK_ATTR_HEALTH_REPORTER);
4665 if (!reporter_attr)
4666 goto genlmsg_cancel;
4667 if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
4668 reporter->ops->name))
4669 goto reporter_nest_cancel;
4670 if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
4671 reporter->health_state))
4672 goto reporter_nest_cancel;
54719527 4673 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
7afe335a
EBE
4674 reporter->error_count, DEVLINK_ATTR_PAD))
4675 goto reporter_nest_cancel;
54719527 4676 if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
7afe335a
EBE
4677 reporter->recovery_count, DEVLINK_ATTR_PAD))
4678 goto reporter_nest_cancel;
574b1e1f
AL
4679 if (reporter->ops->recover &&
4680 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
7afe335a
EBE
4681 reporter->graceful_period,
4682 DEVLINK_ATTR_PAD))
4683 goto reporter_nest_cancel;
574b1e1f
AL
4684 if (reporter->ops->recover &&
4685 nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
7afe335a
EBE
4686 reporter->auto_recover))
4687 goto reporter_nest_cancel;
4688 if (reporter->dump_fmsg &&
4689 nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
4690 jiffies_to_msecs(reporter->dump_ts),
4691 DEVLINK_ATTR_PAD))
4692 goto reporter_nest_cancel;
4693
4694 nla_nest_end(msg, reporter_attr);
4695 genlmsg_end(msg, hdr);
4696 return 0;
4697
4698reporter_nest_cancel:
4699 nla_nest_end(msg, reporter_attr);
4700genlmsg_cancel:
4701 genlmsg_cancel(msg, hdr);
4702 return -EMSGSIZE;
4703}
4704
4705static int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
4706 struct genl_info *info)
4707{
4708 struct devlink *devlink = info->user_ptr[0];
4709 struct devlink_health_reporter *reporter;
4710 struct sk_buff *msg;
4711 int err;
4712
4713 reporter = devlink_health_reporter_get_from_info(devlink, info);
4714 if (!reporter)
4715 return -EINVAL;
4716
4717 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
4718 if (!msg)
4719 return -ENOMEM;
4720
4721 err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
4722 DEVLINK_CMD_HEALTH_REPORTER_GET,
4723 info->snd_portid, info->snd_seq,
4724 0);
4725 if (err) {
4726 nlmsg_free(msg);
4727 return err;
4728 }
4729
4730 return genlmsg_reply(msg, info);
4731}
4732
4733static int
4734devlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
4735 struct netlink_callback *cb)
4736{
4737 struct devlink_health_reporter *reporter;
4738 struct devlink *devlink;
4739 int start = cb->args[0];
4740 int idx = 0;
4741 int err;
4742
4743 mutex_lock(&devlink_mutex);
4744 list_for_each_entry(devlink, &devlink_list, list) {
4745 if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
4746 continue;
4747 mutex_lock(&devlink->lock);
4748 list_for_each_entry(reporter, &devlink->reporter_list,
4749 list) {
4750 if (idx < start) {
4751 idx++;
4752 continue;
4753 }
4754 err = devlink_nl_health_reporter_fill(msg, devlink,
4755 reporter,
4756 DEVLINK_CMD_HEALTH_REPORTER_GET,
4757 NETLINK_CB(cb->skb).portid,
4758 cb->nlh->nlmsg_seq,
4759 NLM_F_MULTI);
4760 if (err) {
4761 mutex_unlock(&devlink->lock);
4762 goto out;
4763 }
4764 idx++;
4765 }
4766 mutex_unlock(&devlink->lock);
4767 }
4768out:
4769 mutex_unlock(&devlink_mutex);
4770
4771 cb->args[0] = idx;
4772 return msg->len;
4773}
4774
a1e55ec0
EBE
4775static int
4776devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
4777 struct genl_info *info)
4778{
4779 struct devlink *devlink = info->user_ptr[0];
4780 struct devlink_health_reporter *reporter;
4781
4782 reporter = devlink_health_reporter_get_from_info(devlink, info);
4783 if (!reporter)
4784 return -EINVAL;
4785
4786 if (!reporter->ops->recover &&
4787 (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
4788 info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]))
4789 return -EOPNOTSUPP;
4790
4791 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
4792 reporter->graceful_period =
4793 nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
4794
4795 if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
4796 reporter->auto_recover =
4797 nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
4798
4799 return 0;
4800}
4801
20a0943a
EBE
4802static int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
4803 struct genl_info *info)
4804{
4805 struct devlink *devlink = info->user_ptr[0];
4806 struct devlink_health_reporter *reporter;
4807
4808 reporter = devlink_health_reporter_get_from_info(devlink, info);
4809 if (!reporter)
4810 return -EINVAL;
4811
4812 return devlink_health_reporter_recover(reporter, NULL);
4813}
4814
fca42a27
EBE
4815static int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
4816 struct genl_info *info)
4817{
4818 struct devlink *devlink = info->user_ptr[0];
4819 struct devlink_health_reporter *reporter;
4820 struct devlink_fmsg *fmsg;
4821 int err;
4822
4823 reporter = devlink_health_reporter_get_from_info(devlink, info);
4824 if (!reporter)
4825 return -EINVAL;
4826
4827 if (!reporter->ops->diagnose)
4828 return -EOPNOTSUPP;
4829
4830 fmsg = devlink_fmsg_alloc();
4831 if (!fmsg)
4832 return -ENOMEM;
4833
4834 err = devlink_fmsg_obj_nest_start(fmsg);
4835 if (err)
4836 goto out;
4837
4838 err = reporter->ops->diagnose(reporter, fmsg);
4839 if (err)
4840 goto out;
4841
4842 err = devlink_fmsg_obj_nest_end(fmsg);
4843 if (err)
4844 goto out;
4845
4846 err = devlink_fmsg_snd(fmsg, info,
4847 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
4848
4849out:
4850 devlink_fmsg_free(fmsg);
4851 return err;
4852}
4853
35455e23
EBE
4854static int devlink_nl_cmd_health_reporter_dump_get_doit(struct sk_buff *skb,
4855 struct genl_info *info)
4856{
4857 struct devlink *devlink = info->user_ptr[0];
4858 struct devlink_health_reporter *reporter;
4859 int err;
4860
4861 reporter = devlink_health_reporter_get_from_info(devlink, info);
4862 if (!reporter)
4863 return -EINVAL;
4864
4865 if (!reporter->ops->dump)
4866 return -EOPNOTSUPP;
4867
4868 mutex_lock(&reporter->dump_lock);
4869 err = devlink_health_do_dump(reporter, NULL);
4870 if (err)
4871 goto out;
4872
4873 err = devlink_fmsg_snd(reporter->dump_fmsg, info,
4874 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET, 0);
4875
4876out:
4877 mutex_unlock(&reporter->dump_lock);
4878 return err;
4879}
4880
4881static int
4882devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
4883 struct genl_info *info)
4884{
4885 struct devlink *devlink = info->user_ptr[0];
4886 struct devlink_health_reporter *reporter;
4887
4888 reporter = devlink_health_reporter_get_from_info(devlink, info);
4889 if (!reporter)
4890 return -EINVAL;
4891
4892 if (!reporter->ops->dump)
4893 return -EOPNOTSUPP;
4894
4895 mutex_lock(&reporter->dump_lock);
4896 devlink_health_dump_clear(reporter);
4897 mutex_unlock(&reporter->dump_lock);
4898 return 0;
4899}
4900
bfcd3a46
JP
4901static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
4902 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
4903 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
4904 [DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
4905 [DEVLINK_ATTR_PORT_TYPE] = { .type = NLA_U16 },
4906 [DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
bf797471
JP
4907 [DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
4908 [DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
4909 [DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
4910 [DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
4911 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
4912 [DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
4913 [DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
08f4b591 4914 [DEVLINK_ATTR_ESWITCH_MODE] = { .type = NLA_U16 },
59bfde01 4915 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
f43e9b06 4916 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
1555d204
AS
4917 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
4918 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
d9f9b9a4
AS
4919 [DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
4920 [DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
e3b7ca18
MS
4921 [DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
4922 [DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
4923 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
d8db7ea5 4924 [DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
866319bb 4925 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
7afe335a 4926 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
a1e55ec0
EBE
4927 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
4928 [DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
76726ccb
JK
4929 [DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
4930 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
bfcd3a46
JP
4931};
4932
4933static const struct genl_ops devlink_nl_ops[] = {
4934 {
4935 .cmd = DEVLINK_CMD_GET,
4936 .doit = devlink_nl_cmd_get_doit,
4937 .dumpit = devlink_nl_cmd_get_dumpit,
1fc2257e 4938 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
bfcd3a46
JP
4939 /* can be retrieved by unprivileged users */
4940 },
4941 {
4942 .cmd = DEVLINK_CMD_PORT_GET,
4943 .doit = devlink_nl_cmd_port_get_doit,
4944 .dumpit = devlink_nl_cmd_port_get_dumpit,
bfcd3a46
JP
4945 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
4946 /* can be retrieved by unprivileged users */
4947 },
4948 {
4949 .cmd = DEVLINK_CMD_PORT_SET,
4950 .doit = devlink_nl_cmd_port_set_doit,
bfcd3a46
JP
4951 .flags = GENL_ADMIN_PERM,
4952 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
4953 },
4954 {
4955 .cmd = DEVLINK_CMD_PORT_SPLIT,
4956 .doit = devlink_nl_cmd_port_split_doit,
bfcd3a46 4957 .flags = GENL_ADMIN_PERM,
2406e7e5
AS
4958 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4959 DEVLINK_NL_FLAG_NO_LOCK,
bfcd3a46
JP
4960 },
4961 {
4962 .cmd = DEVLINK_CMD_PORT_UNSPLIT,
4963 .doit = devlink_nl_cmd_port_unsplit_doit,
bfcd3a46 4964 .flags = GENL_ADMIN_PERM,
2406e7e5
AS
4965 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4966 DEVLINK_NL_FLAG_NO_LOCK,
bfcd3a46 4967 },
bf797471
JP
4968 {
4969 .cmd = DEVLINK_CMD_SB_GET,
4970 .doit = devlink_nl_cmd_sb_get_doit,
4971 .dumpit = devlink_nl_cmd_sb_get_dumpit,
bf797471
JP
4972 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4973 DEVLINK_NL_FLAG_NEED_SB,
4974 /* can be retrieved by unprivileged users */
4975 },
4976 {
4977 .cmd = DEVLINK_CMD_SB_POOL_GET,
4978 .doit = devlink_nl_cmd_sb_pool_get_doit,
4979 .dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
bf797471
JP
4980 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4981 DEVLINK_NL_FLAG_NEED_SB,
4982 /* can be retrieved by unprivileged users */
4983 },
4984 {
4985 .cmd = DEVLINK_CMD_SB_POOL_SET,
4986 .doit = devlink_nl_cmd_sb_pool_set_doit,
bf797471
JP
4987 .flags = GENL_ADMIN_PERM,
4988 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
4989 DEVLINK_NL_FLAG_NEED_SB,
4990 },
4991 {
4992 .cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
4993 .doit = devlink_nl_cmd_sb_port_pool_get_doit,
4994 .dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
bf797471
JP
4995 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
4996 DEVLINK_NL_FLAG_NEED_SB,
4997 /* can be retrieved by unprivileged users */
4998 },
4999 {
5000 .cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
5001 .doit = devlink_nl_cmd_sb_port_pool_set_doit,
bf797471
JP
5002 .flags = GENL_ADMIN_PERM,
5003 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5004 DEVLINK_NL_FLAG_NEED_SB,
5005 },
5006 {
5007 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
5008 .doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
5009 .dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
bf797471
JP
5010 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5011 DEVLINK_NL_FLAG_NEED_SB,
5012 /* can be retrieved by unprivileged users */
5013 },
5014 {
5015 .cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
5016 .doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
bf797471
JP
5017 .flags = GENL_ADMIN_PERM,
5018 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT |
5019 DEVLINK_NL_FLAG_NEED_SB,
5020 },
df38dafd
JP
5021 {
5022 .cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
5023 .doit = devlink_nl_cmd_sb_occ_snapshot_doit,
df38dafd
JP
5024 .flags = GENL_ADMIN_PERM,
5025 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
2406e7e5 5026 DEVLINK_NL_FLAG_NEED_SB,
df38dafd
JP
5027 },
5028 {
5029 .cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
5030 .doit = devlink_nl_cmd_sb_occ_max_clear_doit,
df38dafd
JP
5031 .flags = GENL_ADMIN_PERM,
5032 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
2406e7e5 5033 DEVLINK_NL_FLAG_NEED_SB,
df38dafd 5034 },
08f4b591 5035 {
adf200f3
JP
5036 .cmd = DEVLINK_CMD_ESWITCH_GET,
5037 .doit = devlink_nl_cmd_eswitch_get_doit,
08f4b591
OG
5038 .flags = GENL_ADMIN_PERM,
5039 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5040 },
5041 {
adf200f3
JP
5042 .cmd = DEVLINK_CMD_ESWITCH_SET,
5043 .doit = devlink_nl_cmd_eswitch_set_doit,
08f4b591 5044 .flags = GENL_ADMIN_PERM,
7ac1cc9a
JK
5045 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5046 DEVLINK_NL_FLAG_NO_LOCK,
08f4b591 5047 },
1555d204
AS
5048 {
5049 .cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
5050 .doit = devlink_nl_cmd_dpipe_table_get,
1555d204 5051 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 5052 /* can be retrieved by unprivileged users */
1555d204
AS
5053 },
5054 {
5055 .cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
5056 .doit = devlink_nl_cmd_dpipe_entries_get,
1555d204 5057 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 5058 /* can be retrieved by unprivileged users */
1555d204
AS
5059 },
5060 {
5061 .cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
5062 .doit = devlink_nl_cmd_dpipe_headers_get,
1555d204 5063 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 5064 /* can be retrieved by unprivileged users */
1555d204
AS
5065 },
5066 {
5067 .cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
5068 .doit = devlink_nl_cmd_dpipe_table_counters_set,
1555d204
AS
5069 .flags = GENL_ADMIN_PERM,
5070 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5071 },
d9f9b9a4
AS
5072 {
5073 .cmd = DEVLINK_CMD_RESOURCE_SET,
5074 .doit = devlink_nl_cmd_resource_set,
d9f9b9a4
AS
5075 .flags = GENL_ADMIN_PERM,
5076 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5077 },
5078 {
5079 .cmd = DEVLINK_CMD_RESOURCE_DUMP,
5080 .doit = devlink_nl_cmd_resource_dump,
d9f9b9a4 5081 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
67ae686b 5082 /* can be retrieved by unprivileged users */
d9f9b9a4 5083 },
2d8dc5bb
AS
5084 {
5085 .cmd = DEVLINK_CMD_RELOAD,
5086 .doit = devlink_nl_cmd_reload,
2d8dc5bb
AS
5087 .flags = GENL_ADMIN_PERM,
5088 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5089 DEVLINK_NL_FLAG_NO_LOCK,
5090 },
45f05def
MS
5091 {
5092 .cmd = DEVLINK_CMD_PARAM_GET,
5093 .doit = devlink_nl_cmd_param_get_doit,
5094 .dumpit = devlink_nl_cmd_param_get_dumpit,
45f05def
MS
5095 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5096 /* can be retrieved by unprivileged users */
5097 },
e3b7ca18
MS
5098 {
5099 .cmd = DEVLINK_CMD_PARAM_SET,
5100 .doit = devlink_nl_cmd_param_set_doit,
e3b7ca18
MS
5101 .flags = GENL_ADMIN_PERM,
5102 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5103 },
f4601dee
VV
5104 {
5105 .cmd = DEVLINK_CMD_PORT_PARAM_GET,
5106 .doit = devlink_nl_cmd_port_param_get_doit,
5107 .dumpit = devlink_nl_cmd_port_param_get_dumpit,
f4601dee
VV
5108 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5109 /* can be retrieved by unprivileged users */
5110 },
9c54873b
VV
5111 {
5112 .cmd = DEVLINK_CMD_PORT_PARAM_SET,
5113 .doit = devlink_nl_cmd_port_param_set_doit,
9c54873b
VV
5114 .flags = GENL_ADMIN_PERM,
5115 .internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
5116 },
d8db7ea5
AV
5117 {
5118 .cmd = DEVLINK_CMD_REGION_GET,
5119 .doit = devlink_nl_cmd_region_get_doit,
5120 .dumpit = devlink_nl_cmd_region_get_dumpit,
d8db7ea5
AV
5121 .flags = GENL_ADMIN_PERM,
5122 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5123 },
866319bb
AV
5124 {
5125 .cmd = DEVLINK_CMD_REGION_DEL,
5126 .doit = devlink_nl_cmd_region_del,
866319bb
AV
5127 .flags = GENL_ADMIN_PERM,
5128 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5129 },
4e54795a
AV
5130 {
5131 .cmd = DEVLINK_CMD_REGION_READ,
5132 .dumpit = devlink_nl_cmd_region_read_dumpit,
4e54795a
AV
5133 .flags = GENL_ADMIN_PERM,
5134 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5135 },
f9cf2288
JK
5136 {
5137 .cmd = DEVLINK_CMD_INFO_GET,
5138 .doit = devlink_nl_cmd_info_get_doit,
5139 .dumpit = devlink_nl_cmd_info_get_dumpit,
f9cf2288
JK
5140 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5141 /* can be retrieved by unprivileged users */
5142 },
7afe335a
EBE
5143 {
5144 .cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
5145 .doit = devlink_nl_cmd_health_reporter_get_doit,
5146 .dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
7afe335a
EBE
5147 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5148 /* can be retrieved by unprivileged users */
5149 },
a1e55ec0
EBE
5150 {
5151 .cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
5152 .doit = devlink_nl_cmd_health_reporter_set_doit,
a1e55ec0
EBE
5153 .flags = GENL_ADMIN_PERM,
5154 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5155 },
20a0943a
EBE
5156 {
5157 .cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
5158 .doit = devlink_nl_cmd_health_reporter_recover_doit,
20a0943a
EBE
5159 .flags = GENL_ADMIN_PERM,
5160 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5161 },
fca42a27
EBE
5162 {
5163 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
5164 .doit = devlink_nl_cmd_health_reporter_diagnose_doit,
fca42a27
EBE
5165 .flags = GENL_ADMIN_PERM,
5166 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5167 },
35455e23
EBE
5168 {
5169 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
5170 .doit = devlink_nl_cmd_health_reporter_dump_get_doit,
35455e23
EBE
5171 .flags = GENL_ADMIN_PERM,
5172 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5173 DEVLINK_NL_FLAG_NO_LOCK,
5174 },
5175 {
5176 .cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
5177 .doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
35455e23
EBE
5178 .flags = GENL_ADMIN_PERM,
5179 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK |
5180 DEVLINK_NL_FLAG_NO_LOCK,
5181 },
76726ccb
JK
5182 {
5183 .cmd = DEVLINK_CMD_FLASH_UPDATE,
5184 .doit = devlink_nl_cmd_flash_update,
76726ccb
JK
5185 .flags = GENL_ADMIN_PERM,
5186 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
5187 },
bfcd3a46
JP
5188};
5189
56989f6d 5190static struct genl_family devlink_nl_family __ro_after_init = {
489111e5
JB
5191 .name = DEVLINK_GENL_NAME,
5192 .version = DEVLINK_GENL_VERSION,
5193 .maxattr = DEVLINK_ATTR_MAX,
3b0f31f2 5194 .policy = devlink_nl_policy,
489111e5
JB
5195 .netnsok = true,
5196 .pre_doit = devlink_nl_pre_doit,
5197 .post_doit = devlink_nl_post_doit,
5198 .module = THIS_MODULE,
5199 .ops = devlink_nl_ops,
5200 .n_ops = ARRAY_SIZE(devlink_nl_ops),
5201 .mcgrps = devlink_nl_mcgrps,
5202 .n_mcgrps = ARRAY_SIZE(devlink_nl_mcgrps),
5203};
5204
bfcd3a46
JP
5205/**
5206 * devlink_alloc - Allocate new devlink instance resources
5207 *
5208 * @ops: ops
5209 * @priv_size: size of user private data
5210 *
5211 * Allocate new devlink instance resources, including devlink index
5212 * and name.
5213 */
5214struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
5215{
5216 struct devlink *devlink;
5217
be6fe1d8
JK
5218 if (WARN_ON(!ops))
5219 return NULL;
5220
bfcd3a46
JP
5221 devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
5222 if (!devlink)
5223 return NULL;
5224 devlink->ops = ops;
5225 devlink_net_set(devlink, &init_net);
5226 INIT_LIST_HEAD(&devlink->port_list);
bf797471 5227 INIT_LIST_HEAD(&devlink->sb_list);
1555d204 5228 INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
d9f9b9a4 5229 INIT_LIST_HEAD(&devlink->resource_list);
eabaef18 5230 INIT_LIST_HEAD(&devlink->param_list);
b16ebe92 5231 INIT_LIST_HEAD(&devlink->region_list);
a0bdcc59 5232 INIT_LIST_HEAD(&devlink->reporter_list);
2406e7e5 5233 mutex_init(&devlink->lock);
bfcd3a46
JP
5234 return devlink;
5235}
5236EXPORT_SYMBOL_GPL(devlink_alloc);
5237
5238/**
5239 * devlink_register - Register devlink instance
5240 *
5241 * @devlink: devlink
eeaadd82 5242 * @dev: parent device
bfcd3a46
JP
5243 */
5244int devlink_register(struct devlink *devlink, struct device *dev)
5245{
5246 mutex_lock(&devlink_mutex);
5247 devlink->dev = dev;
5248 list_add_tail(&devlink->list, &devlink_list);
5249 devlink_notify(devlink, DEVLINK_CMD_NEW);
5250 mutex_unlock(&devlink_mutex);
5251 return 0;
5252}
5253EXPORT_SYMBOL_GPL(devlink_register);
5254
5255/**
5256 * devlink_unregister - Unregister devlink instance
5257 *
5258 * @devlink: devlink
5259 */
5260void devlink_unregister(struct devlink *devlink)
5261{
5262 mutex_lock(&devlink_mutex);
5263 devlink_notify(devlink, DEVLINK_CMD_DEL);
5264 list_del(&devlink->list);
5265 mutex_unlock(&devlink_mutex);
5266}
5267EXPORT_SYMBOL_GPL(devlink_unregister);
5268
5269/**
5270 * devlink_free - Free devlink instance resources
5271 *
5272 * @devlink: devlink
5273 */
5274void devlink_free(struct devlink *devlink)
5275{
375cf8c6 5276 mutex_destroy(&devlink->lock);
b904aada
PP
5277 WARN_ON(!list_empty(&devlink->reporter_list));
5278 WARN_ON(!list_empty(&devlink->region_list));
5279 WARN_ON(!list_empty(&devlink->param_list));
5280 WARN_ON(!list_empty(&devlink->resource_list));
5281 WARN_ON(!list_empty(&devlink->dpipe_table_list));
5282 WARN_ON(!list_empty(&devlink->sb_list));
5283 WARN_ON(!list_empty(&devlink->port_list));
5284
bfcd3a46
JP
5285 kfree(devlink);
5286}
5287EXPORT_SYMBOL_GPL(devlink_free);
5288
5289/**
5290 * devlink_port_register - Register devlink port
5291 *
5292 * @devlink: devlink
5293 * @devlink_port: devlink port
eeaadd82 5294 * @port_index: driver-specific numerical identifier of the port
bfcd3a46
JP
5295 *
5296 * Register devlink port with provided port index. User can use
5297 * any indexing, even hw-related one. devlink_port structure
5298 * is convenient to be embedded inside user driver private structure.
5299 * Note that the caller should take care of zeroing the devlink_port
5300 * structure.
5301 */
5302int devlink_port_register(struct devlink *devlink,
5303 struct devlink_port *devlink_port,
5304 unsigned int port_index)
5305{
2406e7e5 5306 mutex_lock(&devlink->lock);
bfcd3a46 5307 if (devlink_port_index_exists(devlink, port_index)) {
2406e7e5 5308 mutex_unlock(&devlink->lock);
bfcd3a46
JP
5309 return -EEXIST;
5310 }
5311 devlink_port->devlink = devlink;
5312 devlink_port->index = port_index;
bfcd3a46 5313 devlink_port->registered = true;
b8f97554 5314 spin_lock_init(&devlink_port->type_lock);
bfcd3a46 5315 list_add_tail(&devlink_port->list, &devlink->port_list);
39e6160e 5316 INIT_LIST_HEAD(&devlink_port->param_list);
2406e7e5 5317 mutex_unlock(&devlink->lock);
bfcd3a46
JP
5318 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5319 return 0;
5320}
5321EXPORT_SYMBOL_GPL(devlink_port_register);
5322
5323/**
5324 * devlink_port_unregister - Unregister devlink port
5325 *
5326 * @devlink_port: devlink port
5327 */
5328void devlink_port_unregister(struct devlink_port *devlink_port)
5329{
2406e7e5
AS
5330 struct devlink *devlink = devlink_port->devlink;
5331
bfcd3a46 5332 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
2406e7e5 5333 mutex_lock(&devlink->lock);
bfcd3a46 5334 list_del(&devlink_port->list);
2406e7e5 5335 mutex_unlock(&devlink->lock);
bfcd3a46
JP
5336}
5337EXPORT_SYMBOL_GPL(devlink_port_unregister);
5338
5339static void __devlink_port_type_set(struct devlink_port *devlink_port,
5340 enum devlink_port_type type,
5341 void *type_dev)
5342{
2b239e70
JP
5343 if (WARN_ON(!devlink_port->registered))
5344 return;
b8f97554 5345 spin_lock(&devlink_port->type_lock);
bfcd3a46
JP
5346 devlink_port->type = type;
5347 devlink_port->type_dev = type_dev;
b8f97554 5348 spin_unlock(&devlink_port->type_lock);
bfcd3a46
JP
5349 devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
5350}
5351
5352/**
5353 * devlink_port_type_eth_set - Set port type to Ethernet
5354 *
5355 * @devlink_port: devlink port
5356 * @netdev: related netdevice
5357 */
5358void devlink_port_type_eth_set(struct devlink_port *devlink_port,
5359 struct net_device *netdev)
5360{
746364f2
JP
5361 /* If driver registers devlink port, it should set devlink port
5362 * attributes accordingly so the compat functions are called
5363 * and the original ops are not used.
5364 */
5365 if (netdev->netdev_ops->ndo_get_phys_port_name) {
5366 /* Some drivers use the same set of ndos for netdevs
5367 * that have devlink_port registered and also for
5368 * those who don't. Make sure that ndo_get_phys_port_name
5369 * returns -EOPNOTSUPP here in case it is defined.
5370 * Warn if not.
5371 */
5372 const struct net_device_ops *ops = netdev->netdev_ops;
5373 char name[IFNAMSIZ];
5374 int err;
5375
5376 err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name));
5377 WARN_ON(err != -EOPNOTSUPP);
5378 }
773b1f38 5379 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev);
bfcd3a46
JP
5380}
5381EXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
5382
5383/**
5384 * devlink_port_type_ib_set - Set port type to InfiniBand
5385 *
5386 * @devlink_port: devlink port
5387 * @ibdev: related IB device
5388 */
5389void devlink_port_type_ib_set(struct devlink_port *devlink_port,
5390 struct ib_device *ibdev)
5391{
773b1f38 5392 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
bfcd3a46
JP
5393}
5394EXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
5395
5396/**
5397 * devlink_port_type_clear - Clear port type
5398 *
5399 * @devlink_port: devlink port
5400 */
5401void devlink_port_type_clear(struct devlink_port *devlink_port)
5402{
773b1f38 5403 __devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
bfcd3a46
JP
5404}
5405EXPORT_SYMBOL_GPL(devlink_port_type_clear);
5406
5407/**
b9ffcbaf 5408 * devlink_port_attrs_set - Set port attributes
bfcd3a46
JP
5409 *
5410 * @devlink_port: devlink port
5ec1380a 5411 * @flavour: flavour of the port
b9ffcbaf
JP
5412 * @port_number: number of the port that is facing user, for example
5413 * the front panel port number
5414 * @split: indicates if this is split port
5415 * @split_subport_number: if the port is split, this is the number
5416 * of subport.
bec5267c
JP
5417 * @switch_id: if the port is part of switch, this is buffer with ID,
5418 * otwerwise this is NULL
5419 * @switch_id_len: length of the switch_id buffer
bfcd3a46 5420 */
b9ffcbaf 5421void devlink_port_attrs_set(struct devlink_port *devlink_port,
5ec1380a 5422 enum devlink_port_flavour flavour,
b9ffcbaf 5423 u32 port_number, bool split,
bec5267c
JP
5424 u32 split_subport_number,
5425 const unsigned char *switch_id,
5426 unsigned char switch_id_len)
bfcd3a46 5427{
b9ffcbaf
JP
5428 struct devlink_port_attrs *attrs = &devlink_port->attrs;
5429
45b86112
JP
5430 if (WARN_ON(devlink_port->registered))
5431 return;
b9ffcbaf 5432 attrs->set = true;
5ec1380a 5433 attrs->flavour = flavour;
b9ffcbaf
JP
5434 attrs->port_number = port_number;
5435 attrs->split = split;
5436 attrs->split_subport_number = split_subport_number;
bec5267c
JP
5437 if (switch_id) {
5438 attrs->switch_port = true;
5439 if (WARN_ON(switch_id_len > MAX_PHYS_ITEM_ID_LEN))
5440 switch_id_len = MAX_PHYS_ITEM_ID_LEN;
5441 memcpy(attrs->switch_id.id, switch_id, switch_id_len);
5442 attrs->switch_id.id_len = switch_id_len;
5443 } else {
5444 attrs->switch_port = false;
5445 }
bfcd3a46 5446}
b9ffcbaf 5447EXPORT_SYMBOL_GPL(devlink_port_attrs_set);
bfcd3a46 5448
af3836df
JP
5449static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
5450 char *name, size_t len)
08474c1a
JP
5451{
5452 struct devlink_port_attrs *attrs = &devlink_port->attrs;
5453 int n = 0;
5454
5455 if (!attrs->set)
5456 return -EOPNOTSUPP;
5457
5458 switch (attrs->flavour) {
5459 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
5460 if (!attrs->split)
5461 n = snprintf(name, len, "p%u", attrs->port_number);
5462 else
5463 n = snprintf(name, len, "p%us%u", attrs->port_number,
5464 attrs->split_subport_number);
5465 break;
5466 case DEVLINK_PORT_FLAVOUR_CPU:
5467 case DEVLINK_PORT_FLAVOUR_DSA:
5468 /* As CPU and DSA ports do not have a netdevice associated
5469 * case should not ever happen.
5470 */
5471 WARN_ON(1);
5472 return -EINVAL;
5473 }
5474
5475 if (n >= len)
5476 return -EINVAL;
5477
5478 return 0;
5479}
af3836df 5480
bf797471
JP
5481int devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
5482 u32 size, u16 ingress_pools_count,
5483 u16 egress_pools_count, u16 ingress_tc_count,
5484 u16 egress_tc_count)
5485{
5486 struct devlink_sb *devlink_sb;
5487 int err = 0;
5488
2406e7e5 5489 mutex_lock(&devlink->lock);
bf797471
JP
5490 if (devlink_sb_index_exists(devlink, sb_index)) {
5491 err = -EEXIST;
5492 goto unlock;
5493 }
5494
5495 devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
5496 if (!devlink_sb) {
5497 err = -ENOMEM;
5498 goto unlock;
5499 }
5500 devlink_sb->index = sb_index;
5501 devlink_sb->size = size;
5502 devlink_sb->ingress_pools_count = ingress_pools_count;
5503 devlink_sb->egress_pools_count = egress_pools_count;
5504 devlink_sb->ingress_tc_count = ingress_tc_count;
5505 devlink_sb->egress_tc_count = egress_tc_count;
5506 list_add_tail(&devlink_sb->list, &devlink->sb_list);
5507unlock:
2406e7e5 5508 mutex_unlock(&devlink->lock);
bf797471
JP
5509 return err;
5510}
5511EXPORT_SYMBOL_GPL(devlink_sb_register);
5512
5513void devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
5514{
5515 struct devlink_sb *devlink_sb;
5516
2406e7e5 5517 mutex_lock(&devlink->lock);
bf797471
JP
5518 devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
5519 WARN_ON(!devlink_sb);
5520 list_del(&devlink_sb->list);
2406e7e5 5521 mutex_unlock(&devlink->lock);
bf797471
JP
5522 kfree(devlink_sb);
5523}
5524EXPORT_SYMBOL_GPL(devlink_sb_unregister);
5525
1555d204
AS
5526/**
5527 * devlink_dpipe_headers_register - register dpipe headers
5528 *
5529 * @devlink: devlink
5530 * @dpipe_headers: dpipe header array
5531 *
5532 * Register the headers supported by hardware.
5533 */
5534int devlink_dpipe_headers_register(struct devlink *devlink,
5535 struct devlink_dpipe_headers *dpipe_headers)
5536{
2406e7e5 5537 mutex_lock(&devlink->lock);
1555d204 5538 devlink->dpipe_headers = dpipe_headers;
2406e7e5 5539 mutex_unlock(&devlink->lock);
1555d204
AS
5540 return 0;
5541}
5542EXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
5543
5544/**
5545 * devlink_dpipe_headers_unregister - unregister dpipe headers
5546 *
5547 * @devlink: devlink
5548 *
5549 * Unregister the headers supported by hardware.
5550 */
5551void devlink_dpipe_headers_unregister(struct devlink *devlink)
5552{
2406e7e5 5553 mutex_lock(&devlink->lock);
1555d204 5554 devlink->dpipe_headers = NULL;
2406e7e5 5555 mutex_unlock(&devlink->lock);
1555d204
AS
5556}
5557EXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
5558
5559/**
5560 * devlink_dpipe_table_counter_enabled - check if counter allocation
5561 * required
5562 * @devlink: devlink
5563 * @table_name: tables name
5564 *
5565 * Used by driver to check if counter allocation is required.
5566 * After counter allocation is turned on the table entries
5567 * are updated to include counter statistics.
5568 *
5569 * After that point on the driver must respect the counter
5570 * state so that each entry added to the table is added
5571 * with a counter.
5572 */
5573bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
5574 const char *table_name)
5575{
5576 struct devlink_dpipe_table *table;
5577 bool enabled;
5578
5579 rcu_read_lock();
5580 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5581 table_name);
5582 enabled = false;
5583 if (table)
5584 enabled = table->counters_enabled;
5585 rcu_read_unlock();
5586 return enabled;
5587}
5588EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
5589
5590/**
5591 * devlink_dpipe_table_register - register dpipe table
5592 *
5593 * @devlink: devlink
5594 * @table_name: table name
5595 * @table_ops: table ops
5596 * @priv: priv
1555d204
AS
5597 * @counter_control_extern: external control for counters
5598 */
5599int devlink_dpipe_table_register(struct devlink *devlink,
5600 const char *table_name,
5601 struct devlink_dpipe_table_ops *table_ops,
ffd3cdcc 5602 void *priv, bool counter_control_extern)
1555d204
AS
5603{
5604 struct devlink_dpipe_table *table;
5605
5606 if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name))
5607 return -EEXIST;
5608
ffd3cdcc
AS
5609 if (WARN_ON(!table_ops->size_get))
5610 return -EINVAL;
5611
1555d204
AS
5612 table = kzalloc(sizeof(*table), GFP_KERNEL);
5613 if (!table)
5614 return -ENOMEM;
5615
5616 table->name = table_name;
5617 table->table_ops = table_ops;
5618 table->priv = priv;
1555d204
AS
5619 table->counter_control_extern = counter_control_extern;
5620
2406e7e5 5621 mutex_lock(&devlink->lock);
1555d204 5622 list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
2406e7e5 5623 mutex_unlock(&devlink->lock);
1555d204
AS
5624 return 0;
5625}
5626EXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
5627
5628/**
5629 * devlink_dpipe_table_unregister - unregister dpipe table
5630 *
5631 * @devlink: devlink
5632 * @table_name: table name
5633 */
5634void devlink_dpipe_table_unregister(struct devlink *devlink,
5635 const char *table_name)
5636{
5637 struct devlink_dpipe_table *table;
5638
2406e7e5 5639 mutex_lock(&devlink->lock);
1555d204
AS
5640 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5641 table_name);
5642 if (!table)
5643 goto unlock;
5644 list_del_rcu(&table->list);
2406e7e5 5645 mutex_unlock(&devlink->lock);
1555d204
AS
5646 kfree_rcu(table, rcu);
5647 return;
5648unlock:
2406e7e5 5649 mutex_unlock(&devlink->lock);
1555d204
AS
5650}
5651EXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
5652
d9f9b9a4
AS
5653/**
5654 * devlink_resource_register - devlink resource register
5655 *
5656 * @devlink: devlink
5657 * @resource_name: resource's name
d9f9b9a4
AS
5658 * @resource_size: resource's size
5659 * @resource_id: resource's id
eeaadd82
JK
5660 * @parent_resource_id: resource's parent id
5661 * @size_params: size parameters
d9f9b9a4
AS
5662 */
5663int devlink_resource_register(struct devlink *devlink,
5664 const char *resource_name,
d9f9b9a4
AS
5665 u64 resource_size,
5666 u64 resource_id,
5667 u64 parent_resource_id,
fc56be47 5668 const struct devlink_resource_size_params *size_params)
d9f9b9a4
AS
5669{
5670 struct devlink_resource *resource;
5671 struct list_head *resource_list;
14530746 5672 bool top_hierarchy;
d9f9b9a4
AS
5673 int err = 0;
5674
14530746
DA
5675 top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
5676
d9f9b9a4
AS
5677 mutex_lock(&devlink->lock);
5678 resource = devlink_resource_find(devlink, NULL, resource_id);
5679 if (resource) {
5680 err = -EINVAL;
5681 goto out;
5682 }
5683
5684 resource = kzalloc(sizeof(*resource), GFP_KERNEL);
5685 if (!resource) {
5686 err = -ENOMEM;
5687 goto out;
5688 }
5689
5690 if (top_hierarchy) {
5691 resource_list = &devlink->resource_list;
5692 } else {
5693 struct devlink_resource *parent_resource;
5694
5695 parent_resource = devlink_resource_find(devlink, NULL,
5696 parent_resource_id);
5697 if (parent_resource) {
5698 resource_list = &parent_resource->resource_list;
5699 resource->parent = parent_resource;
5700 } else {
b75703de 5701 kfree(resource);
d9f9b9a4
AS
5702 err = -EINVAL;
5703 goto out;
5704 }
5705 }
5706
5707 resource->name = resource_name;
5708 resource->size = resource_size;
5709 resource->size_new = resource_size;
5710 resource->id = resource_id;
d9f9b9a4 5711 resource->size_valid = true;
77d27096
JP
5712 memcpy(&resource->size_params, size_params,
5713 sizeof(resource->size_params));
d9f9b9a4
AS
5714 INIT_LIST_HEAD(&resource->resource_list);
5715 list_add_tail(&resource->list, resource_list);
5716out:
5717 mutex_unlock(&devlink->lock);
5718 return err;
5719}
5720EXPORT_SYMBOL_GPL(devlink_resource_register);
5721
5722/**
5723 * devlink_resources_unregister - free all resources
5724 *
5725 * @devlink: devlink
5726 * @resource: resource
5727 */
5728void devlink_resources_unregister(struct devlink *devlink,
5729 struct devlink_resource *resource)
5730{
5731 struct devlink_resource *tmp, *child_resource;
5732 struct list_head *resource_list;
5733
5734 if (resource)
5735 resource_list = &resource->resource_list;
5736 else
5737 resource_list = &devlink->resource_list;
5738
5739 if (!resource)
5740 mutex_lock(&devlink->lock);
5741
5742 list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
5743 devlink_resources_unregister(devlink, child_resource);
5744 list_del(&child_resource->list);
5745 kfree(child_resource);
5746 }
5747
5748 if (!resource)
5749 mutex_unlock(&devlink->lock);
5750}
5751EXPORT_SYMBOL_GPL(devlink_resources_unregister);
5752
5753/**
5754 * devlink_resource_size_get - get and update size
5755 *
5756 * @devlink: devlink
5757 * @resource_id: the requested resource id
5758 * @p_resource_size: ptr to update
5759 */
5760int devlink_resource_size_get(struct devlink *devlink,
5761 u64 resource_id,
5762 u64 *p_resource_size)
5763{
5764 struct devlink_resource *resource;
5765 int err = 0;
5766
5767 mutex_lock(&devlink->lock);
5768 resource = devlink_resource_find(devlink, NULL, resource_id);
5769 if (!resource) {
5770 err = -EINVAL;
5771 goto out;
5772 }
5773 *p_resource_size = resource->size_new;
5774 resource->size = resource->size_new;
5775out:
5776 mutex_unlock(&devlink->lock);
5777 return err;
5778}
5779EXPORT_SYMBOL_GPL(devlink_resource_size_get);
5780
56dc7cd0
AS
5781/**
5782 * devlink_dpipe_table_resource_set - set the resource id
5783 *
5784 * @devlink: devlink
5785 * @table_name: table name
5786 * @resource_id: resource id
5787 * @resource_units: number of resource's units consumed per table's entry
5788 */
5789int devlink_dpipe_table_resource_set(struct devlink *devlink,
5790 const char *table_name, u64 resource_id,
5791 u64 resource_units)
5792{
5793 struct devlink_dpipe_table *table;
5794 int err = 0;
5795
5796 mutex_lock(&devlink->lock);
5797 table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
5798 table_name);
5799 if (!table) {
5800 err = -EINVAL;
5801 goto out;
5802 }
5803 table->resource_id = resource_id;
5804 table->resource_units = resource_units;
5805 table->resource_valid = true;
5806out:
5807 mutex_unlock(&devlink->lock);
5808 return err;
5809}
5810EXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
5811
fc56be47
JP
5812/**
5813 * devlink_resource_occ_get_register - register occupancy getter
5814 *
5815 * @devlink: devlink
5816 * @resource_id: resource id
5817 * @occ_get: occupancy getter callback
5818 * @occ_get_priv: occupancy getter callback priv
5819 */
5820void devlink_resource_occ_get_register(struct devlink *devlink,
5821 u64 resource_id,
5822 devlink_resource_occ_get_t *occ_get,
5823 void *occ_get_priv)
5824{
5825 struct devlink_resource *resource;
5826
5827 mutex_lock(&devlink->lock);
5828 resource = devlink_resource_find(devlink, NULL, resource_id);
5829 if (WARN_ON(!resource))
5830 goto out;
5831 WARN_ON(resource->occ_get);
5832
5833 resource->occ_get = occ_get;
5834 resource->occ_get_priv = occ_get_priv;
5835out:
5836 mutex_unlock(&devlink->lock);
5837}
5838EXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
5839
5840/**
5841 * devlink_resource_occ_get_unregister - unregister occupancy getter
5842 *
5843 * @devlink: devlink
5844 * @resource_id: resource id
5845 */
5846void devlink_resource_occ_get_unregister(struct devlink *devlink,
5847 u64 resource_id)
5848{
5849 struct devlink_resource *resource;
5850
5851 mutex_lock(&devlink->lock);
5852 resource = devlink_resource_find(devlink, NULL, resource_id);
5853 if (WARN_ON(!resource))
5854 goto out;
5855 WARN_ON(!resource->occ_get);
5856
5857 resource->occ_get = NULL;
5858 resource->occ_get_priv = NULL;
5859out:
5860 mutex_unlock(&devlink->lock);
5861}
5862EXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
5863
39e6160e
VV
5864static int devlink_param_verify(const struct devlink_param *param)
5865{
5866 if (!param || !param->name || !param->supported_cmodes)
5867 return -EINVAL;
5868 if (param->generic)
5869 return devlink_param_generic_verify(param);
5870 else
5871 return devlink_param_driver_verify(param);
5872}
5873
5874static int __devlink_params_register(struct devlink *devlink,
c1e5786d 5875 unsigned int port_index,
39e6160e
VV
5876 struct list_head *param_list,
5877 const struct devlink_param *params,
c1e5786d
VV
5878 size_t params_count,
5879 enum devlink_command reg_cmd,
5880 enum devlink_command unreg_cmd)
eabaef18
MS
5881{
5882 const struct devlink_param *param = params;
5883 int i;
5884 int err;
5885
5886 mutex_lock(&devlink->lock);
5887 for (i = 0; i < params_count; i++, param++) {
39e6160e
VV
5888 err = devlink_param_verify(param);
5889 if (err)
eabaef18 5890 goto rollback;
39e6160e 5891
c1e5786d
VV
5892 err = devlink_param_register_one(devlink, port_index,
5893 param_list, param, reg_cmd);
eabaef18
MS
5894 if (err)
5895 goto rollback;
5896 }
5897
5898 mutex_unlock(&devlink->lock);
5899 return 0;
5900
5901rollback:
5902 if (!i)
5903 goto unlock;
5904 for (param--; i > 0; i--, param--)
c1e5786d
VV
5905 devlink_param_unregister_one(devlink, port_index, param_list,
5906 param, unreg_cmd);
eabaef18
MS
5907unlock:
5908 mutex_unlock(&devlink->lock);
5909 return err;
5910}
39e6160e
VV
5911
5912static void __devlink_params_unregister(struct devlink *devlink,
c1e5786d 5913 unsigned int port_index,
39e6160e
VV
5914 struct list_head *param_list,
5915 const struct devlink_param *params,
c1e5786d
VV
5916 size_t params_count,
5917 enum devlink_command cmd)
39e6160e
VV
5918{
5919 const struct devlink_param *param = params;
5920 int i;
5921
5922 mutex_lock(&devlink->lock);
5923 for (i = 0; i < params_count; i++, param++)
c1e5786d
VV
5924 devlink_param_unregister_one(devlink, 0, param_list, param,
5925 cmd);
39e6160e
VV
5926 mutex_unlock(&devlink->lock);
5927}
5928
5929/**
5930 * devlink_params_register - register configuration parameters
5931 *
5932 * @devlink: devlink
5933 * @params: configuration parameters array
5934 * @params_count: number of parameters provided
5935 *
5936 * Register the configuration parameters supported by the driver.
5937 */
5938int devlink_params_register(struct devlink *devlink,
5939 const struct devlink_param *params,
5940 size_t params_count)
5941{
c1e5786d
VV
5942 return __devlink_params_register(devlink, 0, &devlink->param_list,
5943 params, params_count,
5944 DEVLINK_CMD_PARAM_NEW,
5945 DEVLINK_CMD_PARAM_DEL);
39e6160e 5946}
eabaef18
MS
5947EXPORT_SYMBOL_GPL(devlink_params_register);
5948
5949/**
5950 * devlink_params_unregister - unregister configuration parameters
5951 * @devlink: devlink
5952 * @params: configuration parameters to unregister
5953 * @params_count: number of parameters provided
5954 */
5955void devlink_params_unregister(struct devlink *devlink,
5956 const struct devlink_param *params,
5957 size_t params_count)
5958{
c1e5786d
VV
5959 return __devlink_params_unregister(devlink, 0, &devlink->param_list,
5960 params, params_count,
5961 DEVLINK_CMD_PARAM_DEL);
eabaef18
MS
5962}
5963EXPORT_SYMBOL_GPL(devlink_params_unregister);
5964
7c62cfb8
JP
5965/**
5966 * devlink_params_publish - publish configuration parameters
5967 *
5968 * @devlink: devlink
5969 *
5970 * Publish previously registered configuration parameters.
5971 */
5972void devlink_params_publish(struct devlink *devlink)
5973{
5974 struct devlink_param_item *param_item;
5975
5976 list_for_each_entry(param_item, &devlink->param_list, list) {
5977 if (param_item->published)
5978 continue;
5979 param_item->published = true;
5980 devlink_param_notify(devlink, 0, param_item,
5981 DEVLINK_CMD_PARAM_NEW);
5982 }
5983}
5984EXPORT_SYMBOL_GPL(devlink_params_publish);
5985
5986/**
5987 * devlink_params_unpublish - unpublish configuration parameters
5988 *
5989 * @devlink: devlink
5990 *
5991 * Unpublish previously registered configuration parameters.
5992 */
5993void devlink_params_unpublish(struct devlink *devlink)
5994{
5995 struct devlink_param_item *param_item;
5996
5997 list_for_each_entry(param_item, &devlink->param_list, list) {
5998 if (!param_item->published)
5999 continue;
6000 param_item->published = false;
6001 devlink_param_notify(devlink, 0, param_item,
6002 DEVLINK_CMD_PARAM_DEL);
6003 }
6004}
6005EXPORT_SYMBOL_GPL(devlink_params_unpublish);
6006
39e6160e
VV
6007/**
6008 * devlink_port_params_register - register port configuration parameters
6009 *
6010 * @devlink_port: devlink port
6011 * @params: configuration parameters array
6012 * @params_count: number of parameters provided
6013 *
6014 * Register the configuration parameters supported by the port.
6015 */
6016int devlink_port_params_register(struct devlink_port *devlink_port,
6017 const struct devlink_param *params,
6018 size_t params_count)
6019{
6020 return __devlink_params_register(devlink_port->devlink,
c1e5786d 6021 devlink_port->index,
39e6160e 6022 &devlink_port->param_list, params,
c1e5786d
VV
6023 params_count,
6024 DEVLINK_CMD_PORT_PARAM_NEW,
6025 DEVLINK_CMD_PORT_PARAM_DEL);
39e6160e
VV
6026}
6027EXPORT_SYMBOL_GPL(devlink_port_params_register);
6028
6029/**
6030 * devlink_port_params_unregister - unregister port configuration
6031 * parameters
6032 *
6033 * @devlink_port: devlink port
6034 * @params: configuration parameters array
6035 * @params_count: number of parameters provided
6036 */
6037void devlink_port_params_unregister(struct devlink_port *devlink_port,
6038 const struct devlink_param *params,
6039 size_t params_count)
6040{
6041 return __devlink_params_unregister(devlink_port->devlink,
c1e5786d 6042 devlink_port->index,
39e6160e 6043 &devlink_port->param_list,
c1e5786d
VV
6044 params, params_count,
6045 DEVLINK_CMD_PORT_PARAM_DEL);
39e6160e
VV
6046}
6047EXPORT_SYMBOL_GPL(devlink_port_params_unregister);
6048
ffd19b9a
VV
6049static int
6050__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
6051 union devlink_param_value *init_val)
ec01aeb1
MS
6052{
6053 struct devlink_param_item *param_item;
6054
ffd19b9a 6055 param_item = devlink_param_find_by_id(param_list, param_id);
ec01aeb1
MS
6056 if (!param_item)
6057 return -EINVAL;
6058
6059 if (!param_item->driverinit_value_valid ||
6060 !devlink_param_cmode_is_supported(param_item->param,
6061 DEVLINK_PARAM_CMODE_DRIVERINIT))
6062 return -EOPNOTSUPP;
6063
1276534c
MS
6064 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
6065 strcpy(init_val->vstr, param_item->driverinit_value.vstr);
6066 else
6067 *init_val = param_item->driverinit_value;
ec01aeb1
MS
6068
6069 return 0;
6070}
ffd19b9a 6071
5473a7bd
VV
6072static int
6073__devlink_param_driverinit_value_set(struct devlink *devlink,
c1e5786d 6074 unsigned int port_index,
5473a7bd
VV
6075 struct list_head *param_list, u32 param_id,
6076 union devlink_param_value init_val,
6077 enum devlink_command cmd)
6078{
6079 struct devlink_param_item *param_item;
6080
6081 param_item = devlink_param_find_by_id(param_list, param_id);
6082 if (!param_item)
6083 return -EINVAL;
6084
6085 if (!devlink_param_cmode_is_supported(param_item->param,
6086 DEVLINK_PARAM_CMODE_DRIVERINIT))
6087 return -EOPNOTSUPP;
6088
6089 if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
6090 strcpy(param_item->driverinit_value.vstr, init_val.vstr);
6091 else
6092 param_item->driverinit_value = init_val;
6093 param_item->driverinit_value_valid = true;
6094
c1e5786d 6095 devlink_param_notify(devlink, port_index, param_item, cmd);
5473a7bd
VV
6096 return 0;
6097}
6098
ffd19b9a
VV
6099/**
6100 * devlink_param_driverinit_value_get - get configuration parameter
6101 * value for driver initializing
6102 *
6103 * @devlink: devlink
6104 * @param_id: parameter ID
6105 * @init_val: value of parameter in driverinit configuration mode
6106 *
6107 * This function should be used by the driver to get driverinit
6108 * configuration for initialization after reload command.
6109 */
6110int devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
6111 union devlink_param_value *init_val)
6112{
be6fe1d8 6113 if (!devlink->ops->reload)
ffd19b9a
VV
6114 return -EOPNOTSUPP;
6115
6116 return __devlink_param_driverinit_value_get(&devlink->param_list,
6117 param_id, init_val);
6118}
ec01aeb1
MS
6119EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
6120
6121/**
6122 * devlink_param_driverinit_value_set - set value of configuration
6123 * parameter for driverinit
6124 * configuration mode
6125 *
6126 * @devlink: devlink
6127 * @param_id: parameter ID
6128 * @init_val: value of parameter to set for driverinit configuration mode
6129 *
6130 * This function should be used by the driver to set driverinit
6131 * configuration mode default value.
6132 */
6133int devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
6134 union devlink_param_value init_val)
6135{
c1e5786d 6136 return __devlink_param_driverinit_value_set(devlink, 0,
5473a7bd
VV
6137 &devlink->param_list,
6138 param_id, init_val,
6139 DEVLINK_CMD_PARAM_NEW);
ec01aeb1
MS
6140}
6141EXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
6142
ffd19b9a
VV
6143/**
6144 * devlink_port_param_driverinit_value_get - get configuration parameter
6145 * value for driver initializing
6146 *
6147 * @devlink_port: devlink_port
6148 * @param_id: parameter ID
6149 * @init_val: value of parameter in driverinit configuration mode
6150 *
6151 * This function should be used by the driver to get driverinit
6152 * configuration for initialization after reload command.
6153 */
6154int devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
6155 u32 param_id,
6156 union devlink_param_value *init_val)
6157{
6158 struct devlink *devlink = devlink_port->devlink;
6159
be6fe1d8 6160 if (!devlink->ops->reload)
ffd19b9a
VV
6161 return -EOPNOTSUPP;
6162
6163 return __devlink_param_driverinit_value_get(&devlink_port->param_list,
6164 param_id, init_val);
6165}
6166EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
6167
5473a7bd
VV
6168/**
6169 * devlink_port_param_driverinit_value_set - set value of configuration
6170 * parameter for driverinit
6171 * configuration mode
6172 *
6173 * @devlink_port: devlink_port
6174 * @param_id: parameter ID
6175 * @init_val: value of parameter to set for driverinit configuration mode
6176 *
6177 * This function should be used by the driver to set driverinit
6178 * configuration mode default value.
6179 */
6180int devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
6181 u32 param_id,
6182 union devlink_param_value init_val)
6183{
6184 return __devlink_param_driverinit_value_set(devlink_port->devlink,
c1e5786d 6185 devlink_port->index,
5473a7bd 6186 &devlink_port->param_list,
c1e5786d
VV
6187 param_id, init_val,
6188 DEVLINK_CMD_PORT_PARAM_NEW);
5473a7bd
VV
6189}
6190EXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
6191
ea601e17
MS
6192/**
6193 * devlink_param_value_changed - notify devlink on a parameter's value
6194 * change. Should be called by the driver
6195 * right after the change.
6196 *
6197 * @devlink: devlink
6198 * @param_id: parameter ID
6199 *
6200 * This function should be used by the driver to notify devlink on value
6201 * change, excluding driverinit configuration mode.
6202 * For driverinit configuration mode driver should use the function
ea601e17
MS
6203 */
6204void devlink_param_value_changed(struct devlink *devlink, u32 param_id)
6205{
6206 struct devlink_param_item *param_item;
6207
6208 param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
6209 WARN_ON(!param_item);
6210
c1e5786d 6211 devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
ea601e17
MS
6212}
6213EXPORT_SYMBOL_GPL(devlink_param_value_changed);
6214
c1e5786d
VV
6215/**
6216 * devlink_port_param_value_changed - notify devlink on a parameter's value
6217 * change. Should be called by the driver
6218 * right after the change.
6219 *
6220 * @devlink_port: devlink_port
6221 * @param_id: parameter ID
6222 *
6223 * This function should be used by the driver to notify devlink on value
6224 * change, excluding driverinit configuration mode.
6225 * For driverinit configuration mode driver should use the function
6226 * devlink_port_param_driverinit_value_set() instead.
6227 */
6228void devlink_port_param_value_changed(struct devlink_port *devlink_port,
6229 u32 param_id)
6230{
6231 struct devlink_param_item *param_item;
6232
6233 param_item = devlink_param_find_by_id(&devlink_port->param_list,
6234 param_id);
6235 WARN_ON(!param_item);
6236
6237 devlink_param_notify(devlink_port->devlink, devlink_port->index,
6238 param_item, DEVLINK_CMD_PORT_PARAM_NEW);
6239}
6240EXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
6241
bde74ad1
MS
6242/**
6243 * devlink_param_value_str_fill - Safely fill-up the string preventing
6244 * from overflow of the preallocated buffer
6245 *
6246 * @dst_val: destination devlink_param_value
6247 * @src: source buffer
6248 */
6249void devlink_param_value_str_fill(union devlink_param_value *dst_val,
6250 const char *src)
6251{
6252 size_t len;
6253
6254 len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
6255 WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
6256}
6257EXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
6258
b16ebe92
AV
6259/**
6260 * devlink_region_create - create a new address region
6261 *
6262 * @devlink: devlink
6263 * @region_name: region name
6264 * @region_max_snapshots: Maximum supported number of snapshots for region
6265 * @region_size: size of region
6266 */
6267struct devlink_region *devlink_region_create(struct devlink *devlink,
6268 const char *region_name,
6269 u32 region_max_snapshots,
6270 u64 region_size)
6271{
6272 struct devlink_region *region;
6273 int err = 0;
6274
6275 mutex_lock(&devlink->lock);
6276
6277 if (devlink_region_get_by_name(devlink, region_name)) {
6278 err = -EEXIST;
6279 goto unlock;
6280 }
6281
6282 region = kzalloc(sizeof(*region), GFP_KERNEL);
6283 if (!region) {
6284 err = -ENOMEM;
6285 goto unlock;
6286 }
6287
6288 region->devlink = devlink;
6289 region->max_snapshots = region_max_snapshots;
6290 region->name = region_name;
6291 region->size = region_size;
6292 INIT_LIST_HEAD(&region->snapshot_list);
6293 list_add_tail(&region->list, &devlink->region_list);
866319bb 6294 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
b16ebe92
AV
6295
6296 mutex_unlock(&devlink->lock);
6297 return region;
6298
6299unlock:
6300 mutex_unlock(&devlink->lock);
6301 return ERR_PTR(err);
6302}
6303EXPORT_SYMBOL_GPL(devlink_region_create);
6304
6305/**
6306 * devlink_region_destroy - destroy address region
6307 *
6308 * @region: devlink region to destroy
6309 */
6310void devlink_region_destroy(struct devlink_region *region)
6311{
6312 struct devlink *devlink = region->devlink;
d7e52722 6313 struct devlink_snapshot *snapshot, *ts;
b16ebe92
AV
6314
6315 mutex_lock(&devlink->lock);
d7e52722
AV
6316
6317 /* Free all snapshots of region */
6318 list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
6319 devlink_region_snapshot_del(snapshot);
6320
b16ebe92 6321 list_del(&region->list);
866319bb
AV
6322
6323 devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
b16ebe92
AV
6324 mutex_unlock(&devlink->lock);
6325 kfree(region);
6326}
6327EXPORT_SYMBOL_GPL(devlink_region_destroy);
6328
ccadfa44
AV
6329/**
6330 * devlink_region_shapshot_id_get - get snapshot ID
6331 *
6332 * This callback should be called when adding a new snapshot,
6333 * Driver should use the same id for multiple snapshots taken
6334 * on multiple regions at the same time/by the same trigger.
6335 *
6336 * @devlink: devlink
6337 */
6338u32 devlink_region_shapshot_id_get(struct devlink *devlink)
6339{
6340 u32 id;
6341
6342 mutex_lock(&devlink->lock);
6343 id = ++devlink->snapshot_id;
6344 mutex_unlock(&devlink->lock);
6345
6346 return id;
6347}
6348EXPORT_SYMBOL_GPL(devlink_region_shapshot_id_get);
6349
d7e52722
AV
6350/**
6351 * devlink_region_snapshot_create - create a new snapshot
6352 * This will add a new snapshot of a region. The snapshot
6353 * will be stored on the region struct and can be accessed
6354 * from devlink. This is useful for future analyses of snapshots.
6355 * Multiple snapshots can be created on a region.
6356 * The @snapshot_id should be obtained using the getter function.
6357 *
eeaadd82 6358 * @region: devlink region of the snapshot
d7e52722
AV
6359 * @data_len: size of snapshot data
6360 * @data: snapshot data
6361 * @snapshot_id: snapshot id to be created
6362 * @data_destructor: pointer to destructor function to free data
6363 */
6364int devlink_region_snapshot_create(struct devlink_region *region, u64 data_len,
6365 u8 *data, u32 snapshot_id,
6366 devlink_snapshot_data_dest_t *data_destructor)
6367{
6368 struct devlink *devlink = region->devlink;
6369 struct devlink_snapshot *snapshot;
6370 int err;
6371
6372 mutex_lock(&devlink->lock);
6373
6374 /* check if region can hold one more snapshot */
6375 if (region->cur_snapshots == region->max_snapshots) {
6376 err = -ENOMEM;
6377 goto unlock;
6378 }
6379
6380 if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
6381 err = -EEXIST;
6382 goto unlock;
6383 }
6384
6385 snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
6386 if (!snapshot) {
6387 err = -ENOMEM;
6388 goto unlock;
6389 }
6390
6391 snapshot->id = snapshot_id;
6392 snapshot->region = region;
6393 snapshot->data = data;
6394 snapshot->data_len = data_len;
6395 snapshot->data_destructor = data_destructor;
6396
6397 list_add_tail(&snapshot->list, &region->snapshot_list);
6398
6399 region->cur_snapshots++;
6400
866319bb 6401 devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
d7e52722
AV
6402 mutex_unlock(&devlink->lock);
6403 return 0;
6404
6405unlock:
6406 mutex_unlock(&devlink->lock);
6407 return err;
6408}
6409EXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
6410
ddb6e99e
JK
6411static void __devlink_compat_running_version(struct devlink *devlink,
6412 char *buf, size_t len)
6413{
6414 const struct nlattr *nlattr;
6415 struct devlink_info_req req;
6416 struct sk_buff *msg;
6417 int rem, err;
6418
ddb6e99e
JK
6419 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6420 if (!msg)
6421 return;
6422
6423 req.msg = msg;
6424 err = devlink->ops->info_get(devlink, &req, NULL);
6425 if (err)
6426 goto free_msg;
6427
6428 nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
6429 const struct nlattr *kv;
6430 int rem_kv;
6431
6432 if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
6433 continue;
6434
6435 nla_for_each_nested(kv, nlattr, rem_kv) {
6436 if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
6437 continue;
6438
6439 strlcat(buf, nla_data(kv), len);
6440 strlcat(buf, " ", len);
6441 }
6442 }
6443free_msg:
6444 nlmsg_free(msg);
6445}
6446
6447void devlink_compat_running_version(struct net_device *dev,
6448 char *buf, size_t len)
6449{
ddb6e99e
JK
6450 struct devlink *devlink;
6451
1b45ff6c
JK
6452 dev_hold(dev);
6453 rtnl_unlock();
6454
b473b0d2 6455 devlink = netdev_to_devlink(dev);
be6fe1d8 6456 if (!devlink || !devlink->ops->info_get)
e0dcd386 6457 goto out;
b473b0d2
JK
6458
6459 mutex_lock(&devlink->lock);
6460 __devlink_compat_running_version(devlink, buf, len);
6461 mutex_unlock(&devlink->lock);
1b45ff6c 6462
e0dcd386 6463out:
1b45ff6c
JK
6464 rtnl_lock();
6465 dev_put(dev);
ddb6e99e
JK
6466}
6467
4eceba17
JK
6468int devlink_compat_flash_update(struct net_device *dev, const char *file_name)
6469{
4eceba17 6470 struct devlink *devlink;
e0dcd386 6471 int ret;
4eceba17 6472
1b45ff6c
JK
6473 dev_hold(dev);
6474 rtnl_unlock();
6475
b473b0d2 6476 devlink = netdev_to_devlink(dev);
e0dcd386
JP
6477 if (!devlink || !devlink->ops->flash_update) {
6478 ret = -EOPNOTSUPP;
6479 goto out;
6480 }
4eceba17 6481
b473b0d2
JK
6482 mutex_lock(&devlink->lock);
6483 ret = devlink->ops->flash_update(devlink, file_name, NULL, NULL);
6484 mutex_unlock(&devlink->lock);
1b45ff6c 6485
e0dcd386 6486out:
1b45ff6c
JK
6487 rtnl_lock();
6488 dev_put(dev);
6489
b473b0d2 6490 return ret;
4eceba17
JK
6491}
6492
af3836df
JP
6493int devlink_compat_phys_port_name_get(struct net_device *dev,
6494 char *name, size_t len)
6495{
6496 struct devlink_port *devlink_port;
6497
6498 /* RTNL mutex is held here which ensures that devlink_port
6499 * instance cannot disappear in the middle. No need to take
6500 * any devlink lock as only permanent values are accessed.
6501 */
6502 ASSERT_RTNL();
6503
6504 devlink_port = netdev_to_devlink_port(dev);
6505 if (!devlink_port)
6506 return -EOPNOTSUPP;
6507
6508 return __devlink_port_phys_port_name_get(devlink_port, name, len);
6509}
6510
f4b6bcc7 6511static int __init devlink_init(void)
bfcd3a46 6512{
489111e5 6513 return genl_register_family(&devlink_nl_family);
bfcd3a46
JP
6514}
6515
f4b6bcc7 6516subsys_initcall(devlink_init);