18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * net/core/devlink.c - Network physical/parent device Netlink interface
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Heavily inspired by net/wireless/
68c2ecf20Sopenharmony_ci * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
78c2ecf20Sopenharmony_ci * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/types.h>
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci#include <linux/gfp.h>
158c2ecf20Sopenharmony_ci#include <linux/device.h>
168c2ecf20Sopenharmony_ci#include <linux/list.h>
178c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
188c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
198c2ecf20Sopenharmony_ci#include <linux/refcount.h>
208c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
218c2ecf20Sopenharmony_ci#include <linux/u64_stats_sync.h>
228c2ecf20Sopenharmony_ci#include <linux/timekeeping.h>
238c2ecf20Sopenharmony_ci#include <rdma/ib_verbs.h>
248c2ecf20Sopenharmony_ci#include <net/netlink.h>
258c2ecf20Sopenharmony_ci#include <net/genetlink.h>
268c2ecf20Sopenharmony_ci#include <net/rtnetlink.h>
278c2ecf20Sopenharmony_ci#include <net/net_namespace.h>
288c2ecf20Sopenharmony_ci#include <net/sock.h>
298c2ecf20Sopenharmony_ci#include <net/devlink.h>
308c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS
318c2ecf20Sopenharmony_ci#include <trace/events/devlink.h>
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = {
348c2ecf20Sopenharmony_ci	{
358c2ecf20Sopenharmony_ci		.name = "destination mac",
368c2ecf20Sopenharmony_ci		.id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
378c2ecf20Sopenharmony_ci		.bitwidth = 48,
388c2ecf20Sopenharmony_ci	},
398c2ecf20Sopenharmony_ci};
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_cistruct devlink_dpipe_header devlink_dpipe_header_ethernet = {
428c2ecf20Sopenharmony_ci	.name = "ethernet",
438c2ecf20Sopenharmony_ci	.id = DEVLINK_DPIPE_HEADER_ETHERNET,
448c2ecf20Sopenharmony_ci	.fields = devlink_dpipe_fields_ethernet,
458c2ecf20Sopenharmony_ci	.fields_count = ARRAY_SIZE(devlink_dpipe_fields_ethernet),
468c2ecf20Sopenharmony_ci	.global = true,
478c2ecf20Sopenharmony_ci};
488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(devlink_dpipe_header_ethernet);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic struct devlink_dpipe_field devlink_dpipe_fields_ipv4[] = {
518c2ecf20Sopenharmony_ci	{
528c2ecf20Sopenharmony_ci		.name = "destination ip",
538c2ecf20Sopenharmony_ci		.id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
548c2ecf20Sopenharmony_ci		.bitwidth = 32,
558c2ecf20Sopenharmony_ci	},
568c2ecf20Sopenharmony_ci};
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistruct devlink_dpipe_header devlink_dpipe_header_ipv4 = {
598c2ecf20Sopenharmony_ci	.name = "ipv4",
608c2ecf20Sopenharmony_ci	.id = DEVLINK_DPIPE_HEADER_IPV4,
618c2ecf20Sopenharmony_ci	.fields = devlink_dpipe_fields_ipv4,
628c2ecf20Sopenharmony_ci	.fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv4),
638c2ecf20Sopenharmony_ci	.global = true,
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(devlink_dpipe_header_ipv4);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic struct devlink_dpipe_field devlink_dpipe_fields_ipv6[] = {
688c2ecf20Sopenharmony_ci	{
698c2ecf20Sopenharmony_ci		.name = "destination ip",
708c2ecf20Sopenharmony_ci		.id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
718c2ecf20Sopenharmony_ci		.bitwidth = 128,
728c2ecf20Sopenharmony_ci	},
738c2ecf20Sopenharmony_ci};
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistruct devlink_dpipe_header devlink_dpipe_header_ipv6 = {
768c2ecf20Sopenharmony_ci	.name = "ipv6",
778c2ecf20Sopenharmony_ci	.id = DEVLINK_DPIPE_HEADER_IPV6,
788c2ecf20Sopenharmony_ci	.fields = devlink_dpipe_fields_ipv6,
798c2ecf20Sopenharmony_ci	.fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv6),
808c2ecf20Sopenharmony_ci	.global = true,
818c2ecf20Sopenharmony_ci};
828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(devlink_dpipe_header_ipv6);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwmsg);
858c2ecf20Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL_GPL(devlink_hwerr);
868c2ecf20Sopenharmony_ciEXPORT_TRACEPOINT_SYMBOL_GPL(devlink_trap_report);
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic const struct nla_policy devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = {
898c2ecf20Sopenharmony_ci	[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR] = { .type = NLA_BINARY },
908c2ecf20Sopenharmony_ci};
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic LIST_HEAD(devlink_list);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci/* devlink_mutex
958c2ecf20Sopenharmony_ci *
968c2ecf20Sopenharmony_ci * An overall lock guarding every operation coming from userspace.
978c2ecf20Sopenharmony_ci * It also guards devlink devices list and it is taken when
988c2ecf20Sopenharmony_ci * driver registers/unregisters it.
998c2ecf20Sopenharmony_ci */
1008c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(devlink_mutex);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistruct net *devlink_net(const struct devlink *devlink)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	return read_pnet(&devlink->_net);
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_net);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic void __devlink_net_set(struct devlink *devlink, struct net *net)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	write_pnet(&devlink->_net, net);
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_civoid devlink_net_set(struct devlink *devlink, struct net *net)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	if (WARN_ON(devlink->registered))
1168c2ecf20Sopenharmony_ci		return;
1178c2ecf20Sopenharmony_ci	__devlink_net_set(devlink, net);
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_net_set);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic struct devlink *devlink_get_from_attrs(struct net *net,
1228c2ecf20Sopenharmony_ci					      struct nlattr **attrs)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	struct devlink *devlink;
1258c2ecf20Sopenharmony_ci	char *busname;
1268c2ecf20Sopenharmony_ci	char *devname;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	if (!attrs[DEVLINK_ATTR_BUS_NAME] || !attrs[DEVLINK_ATTR_DEV_NAME])
1298c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	busname = nla_data(attrs[DEVLINK_ATTR_BUS_NAME]);
1328c2ecf20Sopenharmony_ci	devname = nla_data(attrs[DEVLINK_ATTR_DEV_NAME]);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	lockdep_assert_held(&devlink_mutex);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	list_for_each_entry(devlink, &devlink_list, list) {
1378c2ecf20Sopenharmony_ci		if (strcmp(devlink->dev->bus->name, busname) == 0 &&
1388c2ecf20Sopenharmony_ci		    strcmp(dev_name(devlink->dev), devname) == 0 &&
1398c2ecf20Sopenharmony_ci		    net_eq(devlink_net(devlink), net))
1408c2ecf20Sopenharmony_ci			return devlink;
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	return ERR_PTR(-ENODEV);
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cistatic struct devlink *devlink_get_from_info(struct genl_info *info)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	return devlink_get_from_attrs(genl_info_net(info), info->attrs);
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic struct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
1528c2ecf20Sopenharmony_ci						      unsigned int port_index)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	list_for_each_entry(devlink_port, &devlink->port_list, list) {
1578c2ecf20Sopenharmony_ci		if (devlink_port->index == port_index)
1588c2ecf20Sopenharmony_ci			return devlink_port;
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci	return NULL;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic bool devlink_port_index_exists(struct devlink *devlink,
1648c2ecf20Sopenharmony_ci				      unsigned int port_index)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	return devlink_port_get_by_index(devlink, port_index);
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic struct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink,
1708c2ecf20Sopenharmony_ci							struct nlattr **attrs)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	if (attrs[DEVLINK_ATTR_PORT_INDEX]) {
1738c2ecf20Sopenharmony_ci		u32 port_index = nla_get_u32(attrs[DEVLINK_ATTR_PORT_INDEX]);
1748c2ecf20Sopenharmony_ci		struct devlink_port *devlink_port;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci		devlink_port = devlink_port_get_by_index(devlink, port_index);
1778c2ecf20Sopenharmony_ci		if (!devlink_port)
1788c2ecf20Sopenharmony_ci			return ERR_PTR(-ENODEV);
1798c2ecf20Sopenharmony_ci		return devlink_port;
1808c2ecf20Sopenharmony_ci	}
1818c2ecf20Sopenharmony_ci	return ERR_PTR(-EINVAL);
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic struct devlink_port *devlink_port_get_from_info(struct devlink *devlink,
1858c2ecf20Sopenharmony_ci						       struct genl_info *info)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	return devlink_port_get_from_attrs(devlink, info->attrs);
1888c2ecf20Sopenharmony_ci}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_cistruct devlink_sb {
1918c2ecf20Sopenharmony_ci	struct list_head list;
1928c2ecf20Sopenharmony_ci	unsigned int index;
1938c2ecf20Sopenharmony_ci	u32 size;
1948c2ecf20Sopenharmony_ci	u16 ingress_pools_count;
1958c2ecf20Sopenharmony_ci	u16 egress_pools_count;
1968c2ecf20Sopenharmony_ci	u16 ingress_tc_count;
1978c2ecf20Sopenharmony_ci	u16 egress_tc_count;
1988c2ecf20Sopenharmony_ci};
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic u16 devlink_sb_pool_count(struct devlink_sb *devlink_sb)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	return devlink_sb->ingress_pools_count + devlink_sb->egress_pools_count;
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic struct devlink_sb *devlink_sb_get_by_index(struct devlink *devlink,
2068c2ecf20Sopenharmony_ci						  unsigned int sb_index)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	struct devlink_sb *devlink_sb;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
2118c2ecf20Sopenharmony_ci		if (devlink_sb->index == sb_index)
2128c2ecf20Sopenharmony_ci			return devlink_sb;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci	return NULL;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic bool devlink_sb_index_exists(struct devlink *devlink,
2188c2ecf20Sopenharmony_ci				    unsigned int sb_index)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	return devlink_sb_get_by_index(devlink, sb_index);
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic struct devlink_sb *devlink_sb_get_from_attrs(struct devlink *devlink,
2248c2ecf20Sopenharmony_ci						    struct nlattr **attrs)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	if (attrs[DEVLINK_ATTR_SB_INDEX]) {
2278c2ecf20Sopenharmony_ci		u32 sb_index = nla_get_u32(attrs[DEVLINK_ATTR_SB_INDEX]);
2288c2ecf20Sopenharmony_ci		struct devlink_sb *devlink_sb;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci		devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
2318c2ecf20Sopenharmony_ci		if (!devlink_sb)
2328c2ecf20Sopenharmony_ci			return ERR_PTR(-ENODEV);
2338c2ecf20Sopenharmony_ci		return devlink_sb;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci	return ERR_PTR(-EINVAL);
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic struct devlink_sb *devlink_sb_get_from_info(struct devlink *devlink,
2398c2ecf20Sopenharmony_ci						   struct genl_info *info)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	return devlink_sb_get_from_attrs(devlink, info->attrs);
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic int devlink_sb_pool_index_get_from_attrs(struct devlink_sb *devlink_sb,
2458c2ecf20Sopenharmony_ci						struct nlattr **attrs,
2468c2ecf20Sopenharmony_ci						u16 *p_pool_index)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	u16 val;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (!attrs[DEVLINK_ATTR_SB_POOL_INDEX])
2518c2ecf20Sopenharmony_ci		return -EINVAL;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	val = nla_get_u16(attrs[DEVLINK_ATTR_SB_POOL_INDEX]);
2548c2ecf20Sopenharmony_ci	if (val >= devlink_sb_pool_count(devlink_sb))
2558c2ecf20Sopenharmony_ci		return -EINVAL;
2568c2ecf20Sopenharmony_ci	*p_pool_index = val;
2578c2ecf20Sopenharmony_ci	return 0;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic int devlink_sb_pool_index_get_from_info(struct devlink_sb *devlink_sb,
2618c2ecf20Sopenharmony_ci					       struct genl_info *info,
2628c2ecf20Sopenharmony_ci					       u16 *p_pool_index)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	return devlink_sb_pool_index_get_from_attrs(devlink_sb, info->attrs,
2658c2ecf20Sopenharmony_ci						    p_pool_index);
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_cistatic int
2698c2ecf20Sopenharmony_cidevlink_sb_pool_type_get_from_attrs(struct nlattr **attrs,
2708c2ecf20Sopenharmony_ci				    enum devlink_sb_pool_type *p_pool_type)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	u8 val;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	if (!attrs[DEVLINK_ATTR_SB_POOL_TYPE])
2758c2ecf20Sopenharmony_ci		return -EINVAL;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_TYPE]);
2788c2ecf20Sopenharmony_ci	if (val != DEVLINK_SB_POOL_TYPE_INGRESS &&
2798c2ecf20Sopenharmony_ci	    val != DEVLINK_SB_POOL_TYPE_EGRESS)
2808c2ecf20Sopenharmony_ci		return -EINVAL;
2818c2ecf20Sopenharmony_ci	*p_pool_type = val;
2828c2ecf20Sopenharmony_ci	return 0;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic int
2868c2ecf20Sopenharmony_cidevlink_sb_pool_type_get_from_info(struct genl_info *info,
2878c2ecf20Sopenharmony_ci				   enum devlink_sb_pool_type *p_pool_type)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	return devlink_sb_pool_type_get_from_attrs(info->attrs, p_pool_type);
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic int
2938c2ecf20Sopenharmony_cidevlink_sb_th_type_get_from_attrs(struct nlattr **attrs,
2948c2ecf20Sopenharmony_ci				  enum devlink_sb_threshold_type *p_th_type)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	u8 val;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	if (!attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
2998c2ecf20Sopenharmony_ci		return -EINVAL;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	val = nla_get_u8(attrs[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]);
3028c2ecf20Sopenharmony_ci	if (val != DEVLINK_SB_THRESHOLD_TYPE_STATIC &&
3038c2ecf20Sopenharmony_ci	    val != DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC)
3048c2ecf20Sopenharmony_ci		return -EINVAL;
3058c2ecf20Sopenharmony_ci	*p_th_type = val;
3068c2ecf20Sopenharmony_ci	return 0;
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic int
3108c2ecf20Sopenharmony_cidevlink_sb_th_type_get_from_info(struct genl_info *info,
3118c2ecf20Sopenharmony_ci				 enum devlink_sb_threshold_type *p_th_type)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	return devlink_sb_th_type_get_from_attrs(info->attrs, p_th_type);
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic int
3178c2ecf20Sopenharmony_cidevlink_sb_tc_index_get_from_attrs(struct devlink_sb *devlink_sb,
3188c2ecf20Sopenharmony_ci				   struct nlattr **attrs,
3198c2ecf20Sopenharmony_ci				   enum devlink_sb_pool_type pool_type,
3208c2ecf20Sopenharmony_ci				   u16 *p_tc_index)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	u16 val;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	if (!attrs[DEVLINK_ATTR_SB_TC_INDEX])
3258c2ecf20Sopenharmony_ci		return -EINVAL;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	val = nla_get_u16(attrs[DEVLINK_ATTR_SB_TC_INDEX]);
3288c2ecf20Sopenharmony_ci	if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS &&
3298c2ecf20Sopenharmony_ci	    val >= devlink_sb->ingress_tc_count)
3308c2ecf20Sopenharmony_ci		return -EINVAL;
3318c2ecf20Sopenharmony_ci	if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS &&
3328c2ecf20Sopenharmony_ci	    val >= devlink_sb->egress_tc_count)
3338c2ecf20Sopenharmony_ci		return -EINVAL;
3348c2ecf20Sopenharmony_ci	*p_tc_index = val;
3358c2ecf20Sopenharmony_ci	return 0;
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic int
3398c2ecf20Sopenharmony_cidevlink_sb_tc_index_get_from_info(struct devlink_sb *devlink_sb,
3408c2ecf20Sopenharmony_ci				  struct genl_info *info,
3418c2ecf20Sopenharmony_ci				  enum devlink_sb_pool_type pool_type,
3428c2ecf20Sopenharmony_ci				  u16 *p_tc_index)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	return devlink_sb_tc_index_get_from_attrs(devlink_sb, info->attrs,
3458c2ecf20Sopenharmony_ci						  pool_type, p_tc_index);
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistruct devlink_region {
3498c2ecf20Sopenharmony_ci	struct devlink *devlink;
3508c2ecf20Sopenharmony_ci	struct devlink_port *port;
3518c2ecf20Sopenharmony_ci	struct list_head list;
3528c2ecf20Sopenharmony_ci	union {
3538c2ecf20Sopenharmony_ci		const struct devlink_region_ops *ops;
3548c2ecf20Sopenharmony_ci		const struct devlink_port_region_ops *port_ops;
3558c2ecf20Sopenharmony_ci	};
3568c2ecf20Sopenharmony_ci	struct list_head snapshot_list;
3578c2ecf20Sopenharmony_ci	u32 max_snapshots;
3588c2ecf20Sopenharmony_ci	u32 cur_snapshots;
3598c2ecf20Sopenharmony_ci	u64 size;
3608c2ecf20Sopenharmony_ci};
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_cistruct devlink_snapshot {
3638c2ecf20Sopenharmony_ci	struct list_head list;
3648c2ecf20Sopenharmony_ci	struct devlink_region *region;
3658c2ecf20Sopenharmony_ci	u8 *data;
3668c2ecf20Sopenharmony_ci	u32 id;
3678c2ecf20Sopenharmony_ci};
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic struct devlink_region *
3708c2ecf20Sopenharmony_cidevlink_region_get_by_name(struct devlink *devlink, const char *region_name)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	struct devlink_region *region;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	list_for_each_entry(region, &devlink->region_list, list)
3758c2ecf20Sopenharmony_ci		if (!strcmp(region->ops->name, region_name))
3768c2ecf20Sopenharmony_ci			return region;
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	return NULL;
3798c2ecf20Sopenharmony_ci}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_cistatic struct devlink_region *
3828c2ecf20Sopenharmony_cidevlink_port_region_get_by_name(struct devlink_port *port,
3838c2ecf20Sopenharmony_ci				const char *region_name)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	struct devlink_region *region;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	list_for_each_entry(region, &port->region_list, list)
3888c2ecf20Sopenharmony_ci		if (!strcmp(region->ops->name, region_name))
3898c2ecf20Sopenharmony_ci			return region;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	return NULL;
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_cistatic struct devlink_snapshot *
3958c2ecf20Sopenharmony_cidevlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	struct devlink_snapshot *snapshot;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	list_for_each_entry(snapshot, &region->snapshot_list, list)
4008c2ecf20Sopenharmony_ci		if (snapshot->id == id)
4018c2ecf20Sopenharmony_ci			return snapshot;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	return NULL;
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci#define DEVLINK_NL_FLAG_NEED_PORT		BIT(0)
4078c2ecf20Sopenharmony_ci#define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT	BIT(1)
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci/* The per devlink instance lock is taken by default in the pre-doit
4108c2ecf20Sopenharmony_ci * operation, yet several commands do not require this. The global
4118c2ecf20Sopenharmony_ci * devlink lock is taken and protects from disruption by user-calls.
4128c2ecf20Sopenharmony_ci */
4138c2ecf20Sopenharmony_ci#define DEVLINK_NL_FLAG_NO_LOCK			BIT(2)
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cistatic int devlink_nl_pre_doit(const struct genl_ops *ops,
4168c2ecf20Sopenharmony_ci			       struct sk_buff *skb, struct genl_info *info)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port;
4198c2ecf20Sopenharmony_ci	struct devlink *devlink;
4208c2ecf20Sopenharmony_ci	int err;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
4238c2ecf20Sopenharmony_ci	devlink = devlink_get_from_info(info);
4248c2ecf20Sopenharmony_ci	if (IS_ERR(devlink)) {
4258c2ecf20Sopenharmony_ci		mutex_unlock(&devlink_mutex);
4268c2ecf20Sopenharmony_ci		return PTR_ERR(devlink);
4278c2ecf20Sopenharmony_ci	}
4288c2ecf20Sopenharmony_ci	if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
4298c2ecf20Sopenharmony_ci		mutex_lock(&devlink->lock);
4308c2ecf20Sopenharmony_ci	info->user_ptr[0] = devlink;
4318c2ecf20Sopenharmony_ci	if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_PORT) {
4328c2ecf20Sopenharmony_ci		devlink_port = devlink_port_get_from_info(devlink, info);
4338c2ecf20Sopenharmony_ci		if (IS_ERR(devlink_port)) {
4348c2ecf20Sopenharmony_ci			err = PTR_ERR(devlink_port);
4358c2ecf20Sopenharmony_ci			goto unlock;
4368c2ecf20Sopenharmony_ci		}
4378c2ecf20Sopenharmony_ci		info->user_ptr[1] = devlink_port;
4388c2ecf20Sopenharmony_ci	} else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT) {
4398c2ecf20Sopenharmony_ci		devlink_port = devlink_port_get_from_info(devlink, info);
4408c2ecf20Sopenharmony_ci		if (!IS_ERR(devlink_port))
4418c2ecf20Sopenharmony_ci			info->user_ptr[1] = devlink_port;
4428c2ecf20Sopenharmony_ci	}
4438c2ecf20Sopenharmony_ci	return 0;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ciunlock:
4468c2ecf20Sopenharmony_ci	if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
4478c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->lock);
4488c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
4498c2ecf20Sopenharmony_ci	return err;
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic void devlink_nl_post_doit(const struct genl_ops *ops,
4538c2ecf20Sopenharmony_ci				 struct sk_buff *skb, struct genl_info *info)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	struct devlink *devlink;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	devlink = info->user_ptr[0];
4588c2ecf20Sopenharmony_ci	if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK)
4598c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->lock);
4608c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_cistatic struct genl_family devlink_nl_family;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_cienum devlink_multicast_groups {
4668c2ecf20Sopenharmony_ci	DEVLINK_MCGRP_CONFIG,
4678c2ecf20Sopenharmony_ci};
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_cistatic const struct genl_multicast_group devlink_nl_mcgrps[] = {
4708c2ecf20Sopenharmony_ci	[DEVLINK_MCGRP_CONFIG] = { .name = DEVLINK_GENL_MCGRP_CONFIG_NAME },
4718c2ecf20Sopenharmony_ci};
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_cistatic int devlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name))
4768c2ecf20Sopenharmony_ci		return -EMSGSIZE;
4778c2ecf20Sopenharmony_ci	if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev)))
4788c2ecf20Sopenharmony_ci		return -EMSGSIZE;
4798c2ecf20Sopenharmony_ci	return 0;
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_cistruct devlink_reload_combination {
4838c2ecf20Sopenharmony_ci	enum devlink_reload_action action;
4848c2ecf20Sopenharmony_ci	enum devlink_reload_limit limit;
4858c2ecf20Sopenharmony_ci};
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_cistatic const struct devlink_reload_combination devlink_reload_invalid_combinations[] = {
4888c2ecf20Sopenharmony_ci	{
4898c2ecf20Sopenharmony_ci		/* can't reinitialize driver with no down time */
4908c2ecf20Sopenharmony_ci		.action = DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
4918c2ecf20Sopenharmony_ci		.limit = DEVLINK_RELOAD_LIMIT_NO_RESET,
4928c2ecf20Sopenharmony_ci	},
4938c2ecf20Sopenharmony_ci};
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_cistatic bool
4968c2ecf20Sopenharmony_cidevlink_reload_combination_is_invalid(enum devlink_reload_action action,
4978c2ecf20Sopenharmony_ci				      enum devlink_reload_limit limit)
4988c2ecf20Sopenharmony_ci{
4998c2ecf20Sopenharmony_ci	int i;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(devlink_reload_invalid_combinations); i++)
5028c2ecf20Sopenharmony_ci		if (devlink_reload_invalid_combinations[i].action == action &&
5038c2ecf20Sopenharmony_ci		    devlink_reload_invalid_combinations[i].limit == limit)
5048c2ecf20Sopenharmony_ci			return true;
5058c2ecf20Sopenharmony_ci	return false;
5068c2ecf20Sopenharmony_ci}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_cistatic bool
5098c2ecf20Sopenharmony_cidevlink_reload_action_is_supported(struct devlink *devlink, enum devlink_reload_action action)
5108c2ecf20Sopenharmony_ci{
5118c2ecf20Sopenharmony_ci	return test_bit(action, &devlink->ops->reload_actions);
5128c2ecf20Sopenharmony_ci}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_cistatic bool
5158c2ecf20Sopenharmony_cidevlink_reload_limit_is_supported(struct devlink *devlink, enum devlink_reload_limit limit)
5168c2ecf20Sopenharmony_ci{
5178c2ecf20Sopenharmony_ci	return test_bit(limit, &devlink->ops->reload_limits);
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic int devlink_reload_stat_put(struct sk_buff *msg,
5218c2ecf20Sopenharmony_ci				   enum devlink_reload_limit limit, u32 value)
5228c2ecf20Sopenharmony_ci{
5238c2ecf20Sopenharmony_ci	struct nlattr *reload_stats_entry;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	reload_stats_entry = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_STATS_ENTRY);
5268c2ecf20Sopenharmony_ci	if (!reload_stats_entry)
5278c2ecf20Sopenharmony_ci		return -EMSGSIZE;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_STATS_LIMIT, limit) ||
5308c2ecf20Sopenharmony_ci	    nla_put_u32(msg, DEVLINK_ATTR_RELOAD_STATS_VALUE, value))
5318c2ecf20Sopenharmony_ci		goto nla_put_failure;
5328c2ecf20Sopenharmony_ci	nla_nest_end(msg, reload_stats_entry);
5338c2ecf20Sopenharmony_ci	return 0;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_cinla_put_failure:
5368c2ecf20Sopenharmony_ci	nla_nest_cancel(msg, reload_stats_entry);
5378c2ecf20Sopenharmony_ci	return -EMSGSIZE;
5388c2ecf20Sopenharmony_ci}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_cistatic int devlink_reload_stats_put(struct sk_buff *msg, struct devlink *devlink, bool is_remote)
5418c2ecf20Sopenharmony_ci{
5428c2ecf20Sopenharmony_ci	struct nlattr *reload_stats_attr, *act_info, *act_stats;
5438c2ecf20Sopenharmony_ci	int i, j, stat_idx;
5448c2ecf20Sopenharmony_ci	u32 value;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	if (!is_remote)
5478c2ecf20Sopenharmony_ci		reload_stats_attr = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_STATS);
5488c2ecf20Sopenharmony_ci	else
5498c2ecf20Sopenharmony_ci		reload_stats_attr = nla_nest_start(msg, DEVLINK_ATTR_REMOTE_RELOAD_STATS);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	if (!reload_stats_attr)
5528c2ecf20Sopenharmony_ci		return -EMSGSIZE;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	for (i = 0; i <= DEVLINK_RELOAD_ACTION_MAX; i++) {
5558c2ecf20Sopenharmony_ci		if ((!is_remote &&
5568c2ecf20Sopenharmony_ci		     !devlink_reload_action_is_supported(devlink, i)) ||
5578c2ecf20Sopenharmony_ci		    i == DEVLINK_RELOAD_ACTION_UNSPEC)
5588c2ecf20Sopenharmony_ci			continue;
5598c2ecf20Sopenharmony_ci		act_info = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_ACTION_INFO);
5608c2ecf20Sopenharmony_ci		if (!act_info)
5618c2ecf20Sopenharmony_ci			goto nla_put_failure;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci		if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_ACTION, i))
5648c2ecf20Sopenharmony_ci			goto action_info_nest_cancel;
5658c2ecf20Sopenharmony_ci		act_stats = nla_nest_start(msg, DEVLINK_ATTR_RELOAD_ACTION_STATS);
5668c2ecf20Sopenharmony_ci		if (!act_stats)
5678c2ecf20Sopenharmony_ci			goto action_info_nest_cancel;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci		for (j = 0; j <= DEVLINK_RELOAD_LIMIT_MAX; j++) {
5708c2ecf20Sopenharmony_ci			/* Remote stats are shown even if not locally supported.
5718c2ecf20Sopenharmony_ci			 * Stats of actions with unspecified limit are shown
5728c2ecf20Sopenharmony_ci			 * though drivers don't need to register unspecified
5738c2ecf20Sopenharmony_ci			 * limit.
5748c2ecf20Sopenharmony_ci			 */
5758c2ecf20Sopenharmony_ci			if ((!is_remote && j != DEVLINK_RELOAD_LIMIT_UNSPEC &&
5768c2ecf20Sopenharmony_ci			     !devlink_reload_limit_is_supported(devlink, j)) ||
5778c2ecf20Sopenharmony_ci			    devlink_reload_combination_is_invalid(i, j))
5788c2ecf20Sopenharmony_ci				continue;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci			stat_idx = j * __DEVLINK_RELOAD_ACTION_MAX + i;
5818c2ecf20Sopenharmony_ci			if (!is_remote)
5828c2ecf20Sopenharmony_ci				value = devlink->stats.reload_stats[stat_idx];
5838c2ecf20Sopenharmony_ci			else
5848c2ecf20Sopenharmony_ci				value = devlink->stats.remote_reload_stats[stat_idx];
5858c2ecf20Sopenharmony_ci			if (devlink_reload_stat_put(msg, j, value))
5868c2ecf20Sopenharmony_ci				goto action_stats_nest_cancel;
5878c2ecf20Sopenharmony_ci		}
5888c2ecf20Sopenharmony_ci		nla_nest_end(msg, act_stats);
5898c2ecf20Sopenharmony_ci		nla_nest_end(msg, act_info);
5908c2ecf20Sopenharmony_ci	}
5918c2ecf20Sopenharmony_ci	nla_nest_end(msg, reload_stats_attr);
5928c2ecf20Sopenharmony_ci	return 0;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ciaction_stats_nest_cancel:
5958c2ecf20Sopenharmony_ci	nla_nest_cancel(msg, act_stats);
5968c2ecf20Sopenharmony_ciaction_info_nest_cancel:
5978c2ecf20Sopenharmony_ci	nla_nest_cancel(msg, act_info);
5988c2ecf20Sopenharmony_cinla_put_failure:
5998c2ecf20Sopenharmony_ci	nla_nest_cancel(msg, reload_stats_attr);
6008c2ecf20Sopenharmony_ci	return -EMSGSIZE;
6018c2ecf20Sopenharmony_ci}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_cistatic int devlink_nl_fill(struct sk_buff *msg, struct devlink *devlink,
6048c2ecf20Sopenharmony_ci			   enum devlink_command cmd, u32 portid,
6058c2ecf20Sopenharmony_ci			   u32 seq, int flags)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	struct nlattr *dev_stats;
6088c2ecf20Sopenharmony_ci	void *hdr;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
6118c2ecf20Sopenharmony_ci	if (!hdr)
6128c2ecf20Sopenharmony_ci		return -EMSGSIZE;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(msg, devlink))
6158c2ecf20Sopenharmony_ci		goto nla_put_failure;
6168c2ecf20Sopenharmony_ci	if (nla_put_u8(msg, DEVLINK_ATTR_RELOAD_FAILED, devlink->reload_failed))
6178c2ecf20Sopenharmony_ci		goto nla_put_failure;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	dev_stats = nla_nest_start(msg, DEVLINK_ATTR_DEV_STATS);
6208c2ecf20Sopenharmony_ci	if (!dev_stats)
6218c2ecf20Sopenharmony_ci		goto nla_put_failure;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	if (devlink_reload_stats_put(msg, devlink, false))
6248c2ecf20Sopenharmony_ci		goto dev_stats_nest_cancel;
6258c2ecf20Sopenharmony_ci	if (devlink_reload_stats_put(msg, devlink, true))
6268c2ecf20Sopenharmony_ci		goto dev_stats_nest_cancel;
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	nla_nest_end(msg, dev_stats);
6298c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
6308c2ecf20Sopenharmony_ci	return 0;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_cidev_stats_nest_cancel:
6338c2ecf20Sopenharmony_ci	nla_nest_cancel(msg, dev_stats);
6348c2ecf20Sopenharmony_cinla_put_failure:
6358c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
6368c2ecf20Sopenharmony_ci	return -EMSGSIZE;
6378c2ecf20Sopenharmony_ci}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_cistatic void devlink_notify(struct devlink *devlink, enum devlink_command cmd)
6408c2ecf20Sopenharmony_ci{
6418c2ecf20Sopenharmony_ci	struct sk_buff *msg;
6428c2ecf20Sopenharmony_ci	int err;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	WARN_ON(cmd != DEVLINK_CMD_NEW && cmd != DEVLINK_CMD_DEL);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
6478c2ecf20Sopenharmony_ci	if (!msg)
6488c2ecf20Sopenharmony_ci		return;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	err = devlink_nl_fill(msg, devlink, cmd, 0, 0, 0);
6518c2ecf20Sopenharmony_ci	if (err) {
6528c2ecf20Sopenharmony_ci		nlmsg_free(msg);
6538c2ecf20Sopenharmony_ci		return;
6548c2ecf20Sopenharmony_ci	}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
6578c2ecf20Sopenharmony_ci				msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cistatic int devlink_nl_port_attrs_put(struct sk_buff *msg,
6618c2ecf20Sopenharmony_ci				     struct devlink_port *devlink_port)
6628c2ecf20Sopenharmony_ci{
6638c2ecf20Sopenharmony_ci	struct devlink_port_attrs *attrs = &devlink_port->attrs;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	if (!devlink_port->attrs_set)
6668c2ecf20Sopenharmony_ci		return 0;
6678c2ecf20Sopenharmony_ci	if (attrs->lanes) {
6688c2ecf20Sopenharmony_ci		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_LANES, attrs->lanes))
6698c2ecf20Sopenharmony_ci			return -EMSGSIZE;
6708c2ecf20Sopenharmony_ci	}
6718c2ecf20Sopenharmony_ci	if (nla_put_u8(msg, DEVLINK_ATTR_PORT_SPLITTABLE, attrs->splittable))
6728c2ecf20Sopenharmony_ci		return -EMSGSIZE;
6738c2ecf20Sopenharmony_ci	if (nla_put_u16(msg, DEVLINK_ATTR_PORT_FLAVOUR, attrs->flavour))
6748c2ecf20Sopenharmony_ci		return -EMSGSIZE;
6758c2ecf20Sopenharmony_ci	switch (devlink_port->attrs.flavour) {
6768c2ecf20Sopenharmony_ci	case DEVLINK_PORT_FLAVOUR_PCI_PF:
6778c2ecf20Sopenharmony_ci		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER,
6788c2ecf20Sopenharmony_ci				attrs->pci_pf.controller) ||
6798c2ecf20Sopenharmony_ci		    nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, attrs->pci_pf.pf))
6808c2ecf20Sopenharmony_ci			return -EMSGSIZE;
6818c2ecf20Sopenharmony_ci		if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_pf.external))
6828c2ecf20Sopenharmony_ci			return -EMSGSIZE;
6838c2ecf20Sopenharmony_ci		break;
6848c2ecf20Sopenharmony_ci	case DEVLINK_PORT_FLAVOUR_PCI_VF:
6858c2ecf20Sopenharmony_ci		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_CONTROLLER_NUMBER,
6868c2ecf20Sopenharmony_ci				attrs->pci_vf.controller) ||
6878c2ecf20Sopenharmony_ci		    nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_PF_NUMBER, attrs->pci_vf.pf) ||
6888c2ecf20Sopenharmony_ci		    nla_put_u16(msg, DEVLINK_ATTR_PORT_PCI_VF_NUMBER, attrs->pci_vf.vf))
6898c2ecf20Sopenharmony_ci			return -EMSGSIZE;
6908c2ecf20Sopenharmony_ci		if (nla_put_u8(msg, DEVLINK_ATTR_PORT_EXTERNAL, attrs->pci_vf.external))
6918c2ecf20Sopenharmony_ci			return -EMSGSIZE;
6928c2ecf20Sopenharmony_ci		break;
6938c2ecf20Sopenharmony_ci	case DEVLINK_PORT_FLAVOUR_PHYSICAL:
6948c2ecf20Sopenharmony_ci	case DEVLINK_PORT_FLAVOUR_CPU:
6958c2ecf20Sopenharmony_ci	case DEVLINK_PORT_FLAVOUR_DSA:
6968c2ecf20Sopenharmony_ci		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_NUMBER,
6978c2ecf20Sopenharmony_ci				attrs->phys.port_number))
6988c2ecf20Sopenharmony_ci			return -EMSGSIZE;
6998c2ecf20Sopenharmony_ci		if (!attrs->split)
7008c2ecf20Sopenharmony_ci			return 0;
7018c2ecf20Sopenharmony_ci		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_GROUP,
7028c2ecf20Sopenharmony_ci				attrs->phys.port_number))
7038c2ecf20Sopenharmony_ci			return -EMSGSIZE;
7048c2ecf20Sopenharmony_ci		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_SPLIT_SUBPORT_NUMBER,
7058c2ecf20Sopenharmony_ci				attrs->phys.split_subport_number))
7068c2ecf20Sopenharmony_ci			return -EMSGSIZE;
7078c2ecf20Sopenharmony_ci		break;
7088c2ecf20Sopenharmony_ci	default:
7098c2ecf20Sopenharmony_ci		break;
7108c2ecf20Sopenharmony_ci	}
7118c2ecf20Sopenharmony_ci	return 0;
7128c2ecf20Sopenharmony_ci}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_cistatic int
7158c2ecf20Sopenharmony_cidevlink_nl_port_function_attrs_put(struct sk_buff *msg, struct devlink_port *port,
7168c2ecf20Sopenharmony_ci				   struct netlink_ext_ack *extack)
7178c2ecf20Sopenharmony_ci{
7188c2ecf20Sopenharmony_ci	struct devlink *devlink = port->devlink;
7198c2ecf20Sopenharmony_ci	const struct devlink_ops *ops;
7208c2ecf20Sopenharmony_ci	struct nlattr *function_attr;
7218c2ecf20Sopenharmony_ci	bool empty_nest = true;
7228c2ecf20Sopenharmony_ci	int err = 0;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	function_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PORT_FUNCTION);
7258c2ecf20Sopenharmony_ci	if (!function_attr)
7268c2ecf20Sopenharmony_ci		return -EMSGSIZE;
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	ops = devlink->ops;
7298c2ecf20Sopenharmony_ci	if (ops->port_function_hw_addr_get) {
7308c2ecf20Sopenharmony_ci		int hw_addr_len;
7318c2ecf20Sopenharmony_ci		u8 hw_addr[MAX_ADDR_LEN];
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci		err = ops->port_function_hw_addr_get(devlink, port, hw_addr, &hw_addr_len, extack);
7348c2ecf20Sopenharmony_ci		if (err == -EOPNOTSUPP) {
7358c2ecf20Sopenharmony_ci			/* Port function attributes are optional for a port. If port doesn't
7368c2ecf20Sopenharmony_ci			 * support function attribute, returning -EOPNOTSUPP is not an error.
7378c2ecf20Sopenharmony_ci			 */
7388c2ecf20Sopenharmony_ci			err = 0;
7398c2ecf20Sopenharmony_ci			goto out;
7408c2ecf20Sopenharmony_ci		} else if (err) {
7418c2ecf20Sopenharmony_ci			goto out;
7428c2ecf20Sopenharmony_ci		}
7438c2ecf20Sopenharmony_ci		err = nla_put(msg, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR, hw_addr_len, hw_addr);
7448c2ecf20Sopenharmony_ci		if (err)
7458c2ecf20Sopenharmony_ci			goto out;
7468c2ecf20Sopenharmony_ci		empty_nest = false;
7478c2ecf20Sopenharmony_ci	}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ciout:
7508c2ecf20Sopenharmony_ci	if (err || empty_nest)
7518c2ecf20Sopenharmony_ci		nla_nest_cancel(msg, function_attr);
7528c2ecf20Sopenharmony_ci	else
7538c2ecf20Sopenharmony_ci		nla_nest_end(msg, function_attr);
7548c2ecf20Sopenharmony_ci	return err;
7558c2ecf20Sopenharmony_ci}
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_cistatic int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink,
7588c2ecf20Sopenharmony_ci				struct devlink_port *devlink_port,
7598c2ecf20Sopenharmony_ci				enum devlink_command cmd, u32 portid,
7608c2ecf20Sopenharmony_ci				u32 seq, int flags,
7618c2ecf20Sopenharmony_ci				struct netlink_ext_ack *extack)
7628c2ecf20Sopenharmony_ci{
7638c2ecf20Sopenharmony_ci	void *hdr;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
7668c2ecf20Sopenharmony_ci	if (!hdr)
7678c2ecf20Sopenharmony_ci		return -EMSGSIZE;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(msg, devlink))
7708c2ecf20Sopenharmony_ci		goto nla_put_failure;
7718c2ecf20Sopenharmony_ci	if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
7728c2ecf20Sopenharmony_ci		goto nla_put_failure;
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	/* Hold rtnl lock while accessing port's netdev attributes. */
7758c2ecf20Sopenharmony_ci	rtnl_lock();
7768c2ecf20Sopenharmony_ci	spin_lock_bh(&devlink_port->type_lock);
7778c2ecf20Sopenharmony_ci	if (nla_put_u16(msg, DEVLINK_ATTR_PORT_TYPE, devlink_port->type))
7788c2ecf20Sopenharmony_ci		goto nla_put_failure_type_locked;
7798c2ecf20Sopenharmony_ci	if (devlink_port->desired_type != DEVLINK_PORT_TYPE_NOTSET &&
7808c2ecf20Sopenharmony_ci	    nla_put_u16(msg, DEVLINK_ATTR_PORT_DESIRED_TYPE,
7818c2ecf20Sopenharmony_ci			devlink_port->desired_type))
7828c2ecf20Sopenharmony_ci		goto nla_put_failure_type_locked;
7838c2ecf20Sopenharmony_ci	if (devlink_port->type == DEVLINK_PORT_TYPE_ETH) {
7848c2ecf20Sopenharmony_ci		struct net *net = devlink_net(devlink_port->devlink);
7858c2ecf20Sopenharmony_ci		struct net_device *netdev = devlink_port->type_dev;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci		if (netdev && net_eq(net, dev_net(netdev)) &&
7888c2ecf20Sopenharmony_ci		    (nla_put_u32(msg, DEVLINK_ATTR_PORT_NETDEV_IFINDEX,
7898c2ecf20Sopenharmony_ci				 netdev->ifindex) ||
7908c2ecf20Sopenharmony_ci		     nla_put_string(msg, DEVLINK_ATTR_PORT_NETDEV_NAME,
7918c2ecf20Sopenharmony_ci				    netdev->name)))
7928c2ecf20Sopenharmony_ci			goto nla_put_failure_type_locked;
7938c2ecf20Sopenharmony_ci	}
7948c2ecf20Sopenharmony_ci	if (devlink_port->type == DEVLINK_PORT_TYPE_IB) {
7958c2ecf20Sopenharmony_ci		struct ib_device *ibdev = devlink_port->type_dev;
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci		if (ibdev &&
7988c2ecf20Sopenharmony_ci		    nla_put_string(msg, DEVLINK_ATTR_PORT_IBDEV_NAME,
7998c2ecf20Sopenharmony_ci				   ibdev->name))
8008c2ecf20Sopenharmony_ci			goto nla_put_failure_type_locked;
8018c2ecf20Sopenharmony_ci	}
8028c2ecf20Sopenharmony_ci	spin_unlock_bh(&devlink_port->type_lock);
8038c2ecf20Sopenharmony_ci	rtnl_unlock();
8048c2ecf20Sopenharmony_ci	if (devlink_nl_port_attrs_put(msg, devlink_port))
8058c2ecf20Sopenharmony_ci		goto nla_put_failure;
8068c2ecf20Sopenharmony_ci	if (devlink_nl_port_function_attrs_put(msg, devlink_port, extack))
8078c2ecf20Sopenharmony_ci		goto nla_put_failure;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
8108c2ecf20Sopenharmony_ci	return 0;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_cinla_put_failure_type_locked:
8138c2ecf20Sopenharmony_ci	spin_unlock_bh(&devlink_port->type_lock);
8148c2ecf20Sopenharmony_ci	rtnl_unlock();
8158c2ecf20Sopenharmony_cinla_put_failure:
8168c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
8178c2ecf20Sopenharmony_ci	return -EMSGSIZE;
8188c2ecf20Sopenharmony_ci}
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_cistatic void devlink_port_notify(struct devlink_port *devlink_port,
8218c2ecf20Sopenharmony_ci				enum devlink_command cmd)
8228c2ecf20Sopenharmony_ci{
8238c2ecf20Sopenharmony_ci	struct devlink *devlink = devlink_port->devlink;
8248c2ecf20Sopenharmony_ci	struct sk_buff *msg;
8258c2ecf20Sopenharmony_ci	int err;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	if (!devlink_port->registered)
8288c2ecf20Sopenharmony_ci		return;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	WARN_ON(cmd != DEVLINK_CMD_PORT_NEW && cmd != DEVLINK_CMD_PORT_DEL);
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
8338c2ecf20Sopenharmony_ci	if (!msg)
8348c2ecf20Sopenharmony_ci		return;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	err = devlink_nl_port_fill(msg, devlink, devlink_port, cmd, 0, 0, 0,
8378c2ecf20Sopenharmony_ci				   NULL);
8388c2ecf20Sopenharmony_ci	if (err) {
8398c2ecf20Sopenharmony_ci		nlmsg_free(msg);
8408c2ecf20Sopenharmony_ci		return;
8418c2ecf20Sopenharmony_ci	}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
8448c2ecf20Sopenharmony_ci				msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
8488c2ecf20Sopenharmony_ci{
8498c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
8508c2ecf20Sopenharmony_ci	struct sk_buff *msg;
8518c2ecf20Sopenharmony_ci	int err;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
8548c2ecf20Sopenharmony_ci	if (!msg)
8558c2ecf20Sopenharmony_ci		return -ENOMEM;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
8588c2ecf20Sopenharmony_ci			      info->snd_portid, info->snd_seq, 0);
8598c2ecf20Sopenharmony_ci	if (err) {
8608c2ecf20Sopenharmony_ci		nlmsg_free(msg);
8618c2ecf20Sopenharmony_ci		return err;
8628c2ecf20Sopenharmony_ci	}
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	return genlmsg_reply(msg, info);
8658c2ecf20Sopenharmony_ci}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_get_dumpit(struct sk_buff *msg,
8688c2ecf20Sopenharmony_ci				     struct netlink_callback *cb)
8698c2ecf20Sopenharmony_ci{
8708c2ecf20Sopenharmony_ci	struct devlink *devlink;
8718c2ecf20Sopenharmony_ci	int start = cb->args[0];
8728c2ecf20Sopenharmony_ci	int idx = 0;
8738c2ecf20Sopenharmony_ci	int err;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
8768c2ecf20Sopenharmony_ci	list_for_each_entry(devlink, &devlink_list, list) {
8778c2ecf20Sopenharmony_ci		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
8788c2ecf20Sopenharmony_ci			continue;
8798c2ecf20Sopenharmony_ci		if (idx < start) {
8808c2ecf20Sopenharmony_ci			idx++;
8818c2ecf20Sopenharmony_ci			continue;
8828c2ecf20Sopenharmony_ci		}
8838c2ecf20Sopenharmony_ci		err = devlink_nl_fill(msg, devlink, DEVLINK_CMD_NEW,
8848c2ecf20Sopenharmony_ci				      NETLINK_CB(cb->skb).portid,
8858c2ecf20Sopenharmony_ci				      cb->nlh->nlmsg_seq, NLM_F_MULTI);
8868c2ecf20Sopenharmony_ci		if (err)
8878c2ecf20Sopenharmony_ci			goto out;
8888c2ecf20Sopenharmony_ci		idx++;
8898c2ecf20Sopenharmony_ci	}
8908c2ecf20Sopenharmony_ciout:
8918c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	cb->args[0] = idx;
8948c2ecf20Sopenharmony_ci	return msg->len;
8958c2ecf20Sopenharmony_ci}
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_port_get_doit(struct sk_buff *skb,
8988c2ecf20Sopenharmony_ci					struct genl_info *info)
8998c2ecf20Sopenharmony_ci{
9008c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port = info->user_ptr[1];
9018c2ecf20Sopenharmony_ci	struct devlink *devlink = devlink_port->devlink;
9028c2ecf20Sopenharmony_ci	struct sk_buff *msg;
9038c2ecf20Sopenharmony_ci	int err;
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
9068c2ecf20Sopenharmony_ci	if (!msg)
9078c2ecf20Sopenharmony_ci		return -ENOMEM;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	err = devlink_nl_port_fill(msg, devlink, devlink_port,
9108c2ecf20Sopenharmony_ci				   DEVLINK_CMD_PORT_NEW,
9118c2ecf20Sopenharmony_ci				   info->snd_portid, info->snd_seq, 0,
9128c2ecf20Sopenharmony_ci				   info->extack);
9138c2ecf20Sopenharmony_ci	if (err) {
9148c2ecf20Sopenharmony_ci		nlmsg_free(msg);
9158c2ecf20Sopenharmony_ci		return err;
9168c2ecf20Sopenharmony_ci	}
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	return genlmsg_reply(msg, info);
9198c2ecf20Sopenharmony_ci}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_port_get_dumpit(struct sk_buff *msg,
9228c2ecf20Sopenharmony_ci					  struct netlink_callback *cb)
9238c2ecf20Sopenharmony_ci{
9248c2ecf20Sopenharmony_ci	struct devlink *devlink;
9258c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port;
9268c2ecf20Sopenharmony_ci	int start = cb->args[0];
9278c2ecf20Sopenharmony_ci	int idx = 0;
9288c2ecf20Sopenharmony_ci	int err;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
9318c2ecf20Sopenharmony_ci	list_for_each_entry(devlink, &devlink_list, list) {
9328c2ecf20Sopenharmony_ci		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
9338c2ecf20Sopenharmony_ci			continue;
9348c2ecf20Sopenharmony_ci		mutex_lock(&devlink->lock);
9358c2ecf20Sopenharmony_ci		list_for_each_entry(devlink_port, &devlink->port_list, list) {
9368c2ecf20Sopenharmony_ci			if (idx < start) {
9378c2ecf20Sopenharmony_ci				idx++;
9388c2ecf20Sopenharmony_ci				continue;
9398c2ecf20Sopenharmony_ci			}
9408c2ecf20Sopenharmony_ci			err = devlink_nl_port_fill(msg, devlink, devlink_port,
9418c2ecf20Sopenharmony_ci						   DEVLINK_CMD_NEW,
9428c2ecf20Sopenharmony_ci						   NETLINK_CB(cb->skb).portid,
9438c2ecf20Sopenharmony_ci						   cb->nlh->nlmsg_seq,
9448c2ecf20Sopenharmony_ci						   NLM_F_MULTI,
9458c2ecf20Sopenharmony_ci						   cb->extack);
9468c2ecf20Sopenharmony_ci			if (err) {
9478c2ecf20Sopenharmony_ci				mutex_unlock(&devlink->lock);
9488c2ecf20Sopenharmony_ci				goto out;
9498c2ecf20Sopenharmony_ci			}
9508c2ecf20Sopenharmony_ci			idx++;
9518c2ecf20Sopenharmony_ci		}
9528c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->lock);
9538c2ecf20Sopenharmony_ci	}
9548c2ecf20Sopenharmony_ciout:
9558c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	cb->args[0] = idx;
9588c2ecf20Sopenharmony_ci	return msg->len;
9598c2ecf20Sopenharmony_ci}
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_cistatic int devlink_port_type_set(struct devlink *devlink,
9628c2ecf20Sopenharmony_ci				 struct devlink_port *devlink_port,
9638c2ecf20Sopenharmony_ci				 enum devlink_port_type port_type)
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci{
9668c2ecf20Sopenharmony_ci	int err;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	if (devlink->ops->port_type_set) {
9698c2ecf20Sopenharmony_ci		if (port_type == devlink_port->type)
9708c2ecf20Sopenharmony_ci			return 0;
9718c2ecf20Sopenharmony_ci		err = devlink->ops->port_type_set(devlink_port, port_type);
9728c2ecf20Sopenharmony_ci		if (err)
9738c2ecf20Sopenharmony_ci			return err;
9748c2ecf20Sopenharmony_ci		devlink_port->desired_type = port_type;
9758c2ecf20Sopenharmony_ci		devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
9768c2ecf20Sopenharmony_ci		return 0;
9778c2ecf20Sopenharmony_ci	}
9788c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
9798c2ecf20Sopenharmony_ci}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_cistatic int
9828c2ecf20Sopenharmony_cidevlink_port_function_hw_addr_set(struct devlink *devlink, struct devlink_port *port,
9838c2ecf20Sopenharmony_ci				  const struct nlattr *attr, struct netlink_ext_ack *extack)
9848c2ecf20Sopenharmony_ci{
9858c2ecf20Sopenharmony_ci	const struct devlink_ops *ops;
9868c2ecf20Sopenharmony_ci	const u8 *hw_addr;
9878c2ecf20Sopenharmony_ci	int hw_addr_len;
9888c2ecf20Sopenharmony_ci	int err;
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	hw_addr = nla_data(attr);
9918c2ecf20Sopenharmony_ci	hw_addr_len = nla_len(attr);
9928c2ecf20Sopenharmony_ci	if (hw_addr_len > MAX_ADDR_LEN) {
9938c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Port function hardware address too long");
9948c2ecf20Sopenharmony_ci		return -EINVAL;
9958c2ecf20Sopenharmony_ci	}
9968c2ecf20Sopenharmony_ci	if (port->type == DEVLINK_PORT_TYPE_ETH) {
9978c2ecf20Sopenharmony_ci		if (hw_addr_len != ETH_ALEN) {
9988c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Address must be 6 bytes for Ethernet device");
9998c2ecf20Sopenharmony_ci			return -EINVAL;
10008c2ecf20Sopenharmony_ci		}
10018c2ecf20Sopenharmony_ci		if (!is_unicast_ether_addr(hw_addr)) {
10028c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Non-unicast hardware address unsupported");
10038c2ecf20Sopenharmony_ci			return -EINVAL;
10048c2ecf20Sopenharmony_ci		}
10058c2ecf20Sopenharmony_ci	}
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	ops = devlink->ops;
10088c2ecf20Sopenharmony_ci	if (!ops->port_function_hw_addr_set) {
10098c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Port doesn't support function attributes");
10108c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
10118c2ecf20Sopenharmony_ci	}
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	err = ops->port_function_hw_addr_set(devlink, port, hw_addr, hw_addr_len, extack);
10148c2ecf20Sopenharmony_ci	if (err)
10158c2ecf20Sopenharmony_ci		return err;
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	devlink_port_notify(port, DEVLINK_CMD_PORT_NEW);
10188c2ecf20Sopenharmony_ci	return 0;
10198c2ecf20Sopenharmony_ci}
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_cistatic int
10228c2ecf20Sopenharmony_cidevlink_port_function_set(struct devlink *devlink, struct devlink_port *port,
10238c2ecf20Sopenharmony_ci			  const struct nlattr *attr, struct netlink_ext_ack *extack)
10248c2ecf20Sopenharmony_ci{
10258c2ecf20Sopenharmony_ci	struct nlattr *tb[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1];
10268c2ecf20Sopenharmony_ci	int err;
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	err = nla_parse_nested(tb, DEVLINK_PORT_FUNCTION_ATTR_MAX, attr,
10298c2ecf20Sopenharmony_ci			       devlink_function_nl_policy, extack);
10308c2ecf20Sopenharmony_ci	if (err < 0) {
10318c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Fail to parse port function attributes");
10328c2ecf20Sopenharmony_ci		return err;
10338c2ecf20Sopenharmony_ci	}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci	attr = tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR];
10368c2ecf20Sopenharmony_ci	if (attr)
10378c2ecf20Sopenharmony_ci		err = devlink_port_function_hw_addr_set(devlink, port, attr, extack);
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	return err;
10408c2ecf20Sopenharmony_ci}
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_port_set_doit(struct sk_buff *skb,
10438c2ecf20Sopenharmony_ci					struct genl_info *info)
10448c2ecf20Sopenharmony_ci{
10458c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port = info->user_ptr[1];
10468c2ecf20Sopenharmony_ci	struct devlink *devlink = devlink_port->devlink;
10478c2ecf20Sopenharmony_ci	int err;
10488c2ecf20Sopenharmony_ci
10498c2ecf20Sopenharmony_ci	if (info->attrs[DEVLINK_ATTR_PORT_TYPE]) {
10508c2ecf20Sopenharmony_ci		enum devlink_port_type port_type;
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci		port_type = nla_get_u16(info->attrs[DEVLINK_ATTR_PORT_TYPE]);
10538c2ecf20Sopenharmony_ci		err = devlink_port_type_set(devlink, devlink_port, port_type);
10548c2ecf20Sopenharmony_ci		if (err)
10558c2ecf20Sopenharmony_ci			return err;
10568c2ecf20Sopenharmony_ci	}
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	if (info->attrs[DEVLINK_ATTR_PORT_FUNCTION]) {
10598c2ecf20Sopenharmony_ci		struct nlattr *attr = info->attrs[DEVLINK_ATTR_PORT_FUNCTION];
10608c2ecf20Sopenharmony_ci		struct netlink_ext_ack *extack = info->extack;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci		err = devlink_port_function_set(devlink, devlink_port, attr, extack);
10638c2ecf20Sopenharmony_ci		if (err)
10648c2ecf20Sopenharmony_ci			return err;
10658c2ecf20Sopenharmony_ci	}
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	return 0;
10688c2ecf20Sopenharmony_ci}
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_cistatic int devlink_port_split(struct devlink *devlink, u32 port_index,
10718c2ecf20Sopenharmony_ci			      u32 count, struct netlink_ext_ack *extack)
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci{
10748c2ecf20Sopenharmony_ci	if (devlink->ops->port_split)
10758c2ecf20Sopenharmony_ci		return devlink->ops->port_split(devlink, port_index, count,
10768c2ecf20Sopenharmony_ci						extack);
10778c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
10788c2ecf20Sopenharmony_ci}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_port_split_doit(struct sk_buff *skb,
10818c2ecf20Sopenharmony_ci					  struct genl_info *info)
10828c2ecf20Sopenharmony_ci{
10838c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
10848c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port;
10858c2ecf20Sopenharmony_ci	u32 port_index;
10868c2ecf20Sopenharmony_ci	u32 count;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_PORT_INDEX] ||
10898c2ecf20Sopenharmony_ci	    !info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT])
10908c2ecf20Sopenharmony_ci		return -EINVAL;
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	devlink_port = devlink_port_get_from_info(devlink, info);
10938c2ecf20Sopenharmony_ci	port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
10948c2ecf20Sopenharmony_ci	count = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_SPLIT_COUNT]);
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	if (IS_ERR(devlink_port))
10978c2ecf20Sopenharmony_ci		return -EINVAL;
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	if (!devlink_port->attrs.splittable) {
11008c2ecf20Sopenharmony_ci		/* Split ports cannot be split. */
11018c2ecf20Sopenharmony_ci		if (devlink_port->attrs.split)
11028c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(info->extack, "Port cannot be split further");
11038c2ecf20Sopenharmony_ci		else
11048c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(info->extack, "Port cannot be split");
11058c2ecf20Sopenharmony_ci		return -EINVAL;
11068c2ecf20Sopenharmony_ci	}
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	if (count < 2 || !is_power_of_2(count) || count > devlink_port->attrs.lanes) {
11098c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(info->extack, "Invalid split count");
11108c2ecf20Sopenharmony_ci		return -EINVAL;
11118c2ecf20Sopenharmony_ci	}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	return devlink_port_split(devlink, port_index, count, info->extack);
11148c2ecf20Sopenharmony_ci}
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_cistatic int devlink_port_unsplit(struct devlink *devlink, u32 port_index,
11178c2ecf20Sopenharmony_ci				struct netlink_ext_ack *extack)
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci{
11208c2ecf20Sopenharmony_ci	if (devlink->ops->port_unsplit)
11218c2ecf20Sopenharmony_ci		return devlink->ops->port_unsplit(devlink, port_index, extack);
11228c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
11238c2ecf20Sopenharmony_ci}
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
11268c2ecf20Sopenharmony_ci					    struct genl_info *info)
11278c2ecf20Sopenharmony_ci{
11288c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
11298c2ecf20Sopenharmony_ci	u32 port_index;
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_PORT_INDEX])
11328c2ecf20Sopenharmony_ci		return -EINVAL;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	port_index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
11358c2ecf20Sopenharmony_ci	return devlink_port_unsplit(devlink, port_index, info->extack);
11368c2ecf20Sopenharmony_ci}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_cistatic int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
11398c2ecf20Sopenharmony_ci			      struct devlink_sb *devlink_sb,
11408c2ecf20Sopenharmony_ci			      enum devlink_command cmd, u32 portid,
11418c2ecf20Sopenharmony_ci			      u32 seq, int flags)
11428c2ecf20Sopenharmony_ci{
11438c2ecf20Sopenharmony_ci	void *hdr;
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
11468c2ecf20Sopenharmony_ci	if (!hdr)
11478c2ecf20Sopenharmony_ci		return -EMSGSIZE;
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(msg, devlink))
11508c2ecf20Sopenharmony_ci		goto nla_put_failure;
11518c2ecf20Sopenharmony_ci	if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
11528c2ecf20Sopenharmony_ci		goto nla_put_failure;
11538c2ecf20Sopenharmony_ci	if (nla_put_u32(msg, DEVLINK_ATTR_SB_SIZE, devlink_sb->size))
11548c2ecf20Sopenharmony_ci		goto nla_put_failure;
11558c2ecf20Sopenharmony_ci	if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_POOL_COUNT,
11568c2ecf20Sopenharmony_ci			devlink_sb->ingress_pools_count))
11578c2ecf20Sopenharmony_ci		goto nla_put_failure;
11588c2ecf20Sopenharmony_ci	if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_POOL_COUNT,
11598c2ecf20Sopenharmony_ci			devlink_sb->egress_pools_count))
11608c2ecf20Sopenharmony_ci		goto nla_put_failure;
11618c2ecf20Sopenharmony_ci	if (nla_put_u16(msg, DEVLINK_ATTR_SB_INGRESS_TC_COUNT,
11628c2ecf20Sopenharmony_ci			devlink_sb->ingress_tc_count))
11638c2ecf20Sopenharmony_ci		goto nla_put_failure;
11648c2ecf20Sopenharmony_ci	if (nla_put_u16(msg, DEVLINK_ATTR_SB_EGRESS_TC_COUNT,
11658c2ecf20Sopenharmony_ci			devlink_sb->egress_tc_count))
11668c2ecf20Sopenharmony_ci		goto nla_put_failure;
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
11698c2ecf20Sopenharmony_ci	return 0;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_cinla_put_failure:
11728c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
11738c2ecf20Sopenharmony_ci	return -EMSGSIZE;
11748c2ecf20Sopenharmony_ci}
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_get_doit(struct sk_buff *skb,
11778c2ecf20Sopenharmony_ci				      struct genl_info *info)
11788c2ecf20Sopenharmony_ci{
11798c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
11808c2ecf20Sopenharmony_ci	struct devlink_sb *devlink_sb;
11818c2ecf20Sopenharmony_ci	struct sk_buff *msg;
11828c2ecf20Sopenharmony_ci	int err;
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	devlink_sb = devlink_sb_get_from_info(devlink, info);
11858c2ecf20Sopenharmony_ci	if (IS_ERR(devlink_sb))
11868c2ecf20Sopenharmony_ci		return PTR_ERR(devlink_sb);
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
11898c2ecf20Sopenharmony_ci	if (!msg)
11908c2ecf20Sopenharmony_ci		return -ENOMEM;
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci	err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
11938c2ecf20Sopenharmony_ci				 DEVLINK_CMD_SB_NEW,
11948c2ecf20Sopenharmony_ci				 info->snd_portid, info->snd_seq, 0);
11958c2ecf20Sopenharmony_ci	if (err) {
11968c2ecf20Sopenharmony_ci		nlmsg_free(msg);
11978c2ecf20Sopenharmony_ci		return err;
11988c2ecf20Sopenharmony_ci	}
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	return genlmsg_reply(msg, info);
12018c2ecf20Sopenharmony_ci}
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_get_dumpit(struct sk_buff *msg,
12048c2ecf20Sopenharmony_ci					struct netlink_callback *cb)
12058c2ecf20Sopenharmony_ci{
12068c2ecf20Sopenharmony_ci	struct devlink *devlink;
12078c2ecf20Sopenharmony_ci	struct devlink_sb *devlink_sb;
12088c2ecf20Sopenharmony_ci	int start = cb->args[0];
12098c2ecf20Sopenharmony_ci	int idx = 0;
12108c2ecf20Sopenharmony_ci	int err;
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
12138c2ecf20Sopenharmony_ci	list_for_each_entry(devlink, &devlink_list, list) {
12148c2ecf20Sopenharmony_ci		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
12158c2ecf20Sopenharmony_ci			continue;
12168c2ecf20Sopenharmony_ci		mutex_lock(&devlink->lock);
12178c2ecf20Sopenharmony_ci		list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
12188c2ecf20Sopenharmony_ci			if (idx < start) {
12198c2ecf20Sopenharmony_ci				idx++;
12208c2ecf20Sopenharmony_ci				continue;
12218c2ecf20Sopenharmony_ci			}
12228c2ecf20Sopenharmony_ci			err = devlink_nl_sb_fill(msg, devlink, devlink_sb,
12238c2ecf20Sopenharmony_ci						 DEVLINK_CMD_SB_NEW,
12248c2ecf20Sopenharmony_ci						 NETLINK_CB(cb->skb).portid,
12258c2ecf20Sopenharmony_ci						 cb->nlh->nlmsg_seq,
12268c2ecf20Sopenharmony_ci						 NLM_F_MULTI);
12278c2ecf20Sopenharmony_ci			if (err) {
12288c2ecf20Sopenharmony_ci				mutex_unlock(&devlink->lock);
12298c2ecf20Sopenharmony_ci				goto out;
12308c2ecf20Sopenharmony_ci			}
12318c2ecf20Sopenharmony_ci			idx++;
12328c2ecf20Sopenharmony_ci		}
12338c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->lock);
12348c2ecf20Sopenharmony_ci	}
12358c2ecf20Sopenharmony_ciout:
12368c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	cb->args[0] = idx;
12398c2ecf20Sopenharmony_ci	return msg->len;
12408c2ecf20Sopenharmony_ci}
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_cistatic int devlink_nl_sb_pool_fill(struct sk_buff *msg, struct devlink *devlink,
12438c2ecf20Sopenharmony_ci				   struct devlink_sb *devlink_sb,
12448c2ecf20Sopenharmony_ci				   u16 pool_index, enum devlink_command cmd,
12458c2ecf20Sopenharmony_ci				   u32 portid, u32 seq, int flags)
12468c2ecf20Sopenharmony_ci{
12478c2ecf20Sopenharmony_ci	struct devlink_sb_pool_info pool_info;
12488c2ecf20Sopenharmony_ci	void *hdr;
12498c2ecf20Sopenharmony_ci	int err;
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	err = devlink->ops->sb_pool_get(devlink, devlink_sb->index,
12528c2ecf20Sopenharmony_ci					pool_index, &pool_info);
12538c2ecf20Sopenharmony_ci	if (err)
12548c2ecf20Sopenharmony_ci		return err;
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
12578c2ecf20Sopenharmony_ci	if (!hdr)
12588c2ecf20Sopenharmony_ci		return -EMSGSIZE;
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(msg, devlink))
12618c2ecf20Sopenharmony_ci		goto nla_put_failure;
12628c2ecf20Sopenharmony_ci	if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
12638c2ecf20Sopenharmony_ci		goto nla_put_failure;
12648c2ecf20Sopenharmony_ci	if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
12658c2ecf20Sopenharmony_ci		goto nla_put_failure;
12668c2ecf20Sopenharmony_ci	if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_info.pool_type))
12678c2ecf20Sopenharmony_ci		goto nla_put_failure;
12688c2ecf20Sopenharmony_ci	if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_SIZE, pool_info.size))
12698c2ecf20Sopenharmony_ci		goto nla_put_failure;
12708c2ecf20Sopenharmony_ci	if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
12718c2ecf20Sopenharmony_ci		       pool_info.threshold_type))
12728c2ecf20Sopenharmony_ci		goto nla_put_failure;
12738c2ecf20Sopenharmony_ci	if (nla_put_u32(msg, DEVLINK_ATTR_SB_POOL_CELL_SIZE,
12748c2ecf20Sopenharmony_ci			pool_info.cell_size))
12758c2ecf20Sopenharmony_ci		goto nla_put_failure;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
12788c2ecf20Sopenharmony_ci	return 0;
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_cinla_put_failure:
12818c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
12828c2ecf20Sopenharmony_ci	return -EMSGSIZE;
12838c2ecf20Sopenharmony_ci}
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_pool_get_doit(struct sk_buff *skb,
12868c2ecf20Sopenharmony_ci					   struct genl_info *info)
12878c2ecf20Sopenharmony_ci{
12888c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
12898c2ecf20Sopenharmony_ci	struct devlink_sb *devlink_sb;
12908c2ecf20Sopenharmony_ci	struct sk_buff *msg;
12918c2ecf20Sopenharmony_ci	u16 pool_index;
12928c2ecf20Sopenharmony_ci	int err;
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	devlink_sb = devlink_sb_get_from_info(devlink, info);
12958c2ecf20Sopenharmony_ci	if (IS_ERR(devlink_sb))
12968c2ecf20Sopenharmony_ci		return PTR_ERR(devlink_sb);
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
12998c2ecf20Sopenharmony_ci						  &pool_index);
13008c2ecf20Sopenharmony_ci	if (err)
13018c2ecf20Sopenharmony_ci		return err;
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	if (!devlink->ops->sb_pool_get)
13048c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
13078c2ecf20Sopenharmony_ci	if (!msg)
13088c2ecf20Sopenharmony_ci		return -ENOMEM;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	err = devlink_nl_sb_pool_fill(msg, devlink, devlink_sb, pool_index,
13118c2ecf20Sopenharmony_ci				      DEVLINK_CMD_SB_POOL_NEW,
13128c2ecf20Sopenharmony_ci				      info->snd_portid, info->snd_seq, 0);
13138c2ecf20Sopenharmony_ci	if (err) {
13148c2ecf20Sopenharmony_ci		nlmsg_free(msg);
13158c2ecf20Sopenharmony_ci		return err;
13168c2ecf20Sopenharmony_ci	}
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci	return genlmsg_reply(msg, info);
13198c2ecf20Sopenharmony_ci}
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_cistatic int __sb_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
13228c2ecf20Sopenharmony_ci				struct devlink *devlink,
13238c2ecf20Sopenharmony_ci				struct devlink_sb *devlink_sb,
13248c2ecf20Sopenharmony_ci				u32 portid, u32 seq)
13258c2ecf20Sopenharmony_ci{
13268c2ecf20Sopenharmony_ci	u16 pool_count = devlink_sb_pool_count(devlink_sb);
13278c2ecf20Sopenharmony_ci	u16 pool_index;
13288c2ecf20Sopenharmony_ci	int err;
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	for (pool_index = 0; pool_index < pool_count; pool_index++) {
13318c2ecf20Sopenharmony_ci		if (*p_idx < start) {
13328c2ecf20Sopenharmony_ci			(*p_idx)++;
13338c2ecf20Sopenharmony_ci			continue;
13348c2ecf20Sopenharmony_ci		}
13358c2ecf20Sopenharmony_ci		err = devlink_nl_sb_pool_fill(msg, devlink,
13368c2ecf20Sopenharmony_ci					      devlink_sb,
13378c2ecf20Sopenharmony_ci					      pool_index,
13388c2ecf20Sopenharmony_ci					      DEVLINK_CMD_SB_POOL_NEW,
13398c2ecf20Sopenharmony_ci					      portid, seq, NLM_F_MULTI);
13408c2ecf20Sopenharmony_ci		if (err)
13418c2ecf20Sopenharmony_ci			return err;
13428c2ecf20Sopenharmony_ci		(*p_idx)++;
13438c2ecf20Sopenharmony_ci	}
13448c2ecf20Sopenharmony_ci	return 0;
13458c2ecf20Sopenharmony_ci}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_pool_get_dumpit(struct sk_buff *msg,
13488c2ecf20Sopenharmony_ci					     struct netlink_callback *cb)
13498c2ecf20Sopenharmony_ci{
13508c2ecf20Sopenharmony_ci	struct devlink *devlink;
13518c2ecf20Sopenharmony_ci	struct devlink_sb *devlink_sb;
13528c2ecf20Sopenharmony_ci	int start = cb->args[0];
13538c2ecf20Sopenharmony_ci	int idx = 0;
13548c2ecf20Sopenharmony_ci	int err = 0;
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
13578c2ecf20Sopenharmony_ci	list_for_each_entry(devlink, &devlink_list, list) {
13588c2ecf20Sopenharmony_ci		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
13598c2ecf20Sopenharmony_ci		    !devlink->ops->sb_pool_get)
13608c2ecf20Sopenharmony_ci			continue;
13618c2ecf20Sopenharmony_ci		mutex_lock(&devlink->lock);
13628c2ecf20Sopenharmony_ci		list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
13638c2ecf20Sopenharmony_ci			err = __sb_pool_get_dumpit(msg, start, &idx, devlink,
13648c2ecf20Sopenharmony_ci						   devlink_sb,
13658c2ecf20Sopenharmony_ci						   NETLINK_CB(cb->skb).portid,
13668c2ecf20Sopenharmony_ci						   cb->nlh->nlmsg_seq);
13678c2ecf20Sopenharmony_ci			if (err == -EOPNOTSUPP) {
13688c2ecf20Sopenharmony_ci				err = 0;
13698c2ecf20Sopenharmony_ci			} else if (err) {
13708c2ecf20Sopenharmony_ci				mutex_unlock(&devlink->lock);
13718c2ecf20Sopenharmony_ci				goto out;
13728c2ecf20Sopenharmony_ci			}
13738c2ecf20Sopenharmony_ci		}
13748c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->lock);
13758c2ecf20Sopenharmony_ci	}
13768c2ecf20Sopenharmony_ciout:
13778c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	if (err != -EMSGSIZE)
13808c2ecf20Sopenharmony_ci		return err;
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	cb->args[0] = idx;
13838c2ecf20Sopenharmony_ci	return msg->len;
13848c2ecf20Sopenharmony_ci}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_cistatic int devlink_sb_pool_set(struct devlink *devlink, unsigned int sb_index,
13878c2ecf20Sopenharmony_ci			       u16 pool_index, u32 size,
13888c2ecf20Sopenharmony_ci			       enum devlink_sb_threshold_type threshold_type,
13898c2ecf20Sopenharmony_ci			       struct netlink_ext_ack *extack)
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci{
13928c2ecf20Sopenharmony_ci	const struct devlink_ops *ops = devlink->ops;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	if (ops->sb_pool_set)
13958c2ecf20Sopenharmony_ci		return ops->sb_pool_set(devlink, sb_index, pool_index,
13968c2ecf20Sopenharmony_ci					size, threshold_type, extack);
13978c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
13988c2ecf20Sopenharmony_ci}
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb,
14018c2ecf20Sopenharmony_ci					   struct genl_info *info)
14028c2ecf20Sopenharmony_ci{
14038c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
14048c2ecf20Sopenharmony_ci	enum devlink_sb_threshold_type threshold_type;
14058c2ecf20Sopenharmony_ci	struct devlink_sb *devlink_sb;
14068c2ecf20Sopenharmony_ci	u16 pool_index;
14078c2ecf20Sopenharmony_ci	u32 size;
14088c2ecf20Sopenharmony_ci	int err;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	devlink_sb = devlink_sb_get_from_info(devlink, info);
14118c2ecf20Sopenharmony_ci	if (IS_ERR(devlink_sb))
14128c2ecf20Sopenharmony_ci		return PTR_ERR(devlink_sb);
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci	err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
14158c2ecf20Sopenharmony_ci						  &pool_index);
14168c2ecf20Sopenharmony_ci	if (err)
14178c2ecf20Sopenharmony_ci		return err;
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci	err = devlink_sb_th_type_get_from_info(info, &threshold_type);
14208c2ecf20Sopenharmony_ci	if (err)
14218c2ecf20Sopenharmony_ci		return err;
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_SB_POOL_SIZE])
14248c2ecf20Sopenharmony_ci		return -EINVAL;
14258c2ecf20Sopenharmony_ci
14268c2ecf20Sopenharmony_ci	size = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_POOL_SIZE]);
14278c2ecf20Sopenharmony_ci	return devlink_sb_pool_set(devlink, devlink_sb->index,
14288c2ecf20Sopenharmony_ci				   pool_index, size, threshold_type,
14298c2ecf20Sopenharmony_ci				   info->extack);
14308c2ecf20Sopenharmony_ci}
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_cistatic int devlink_nl_sb_port_pool_fill(struct sk_buff *msg,
14338c2ecf20Sopenharmony_ci					struct devlink *devlink,
14348c2ecf20Sopenharmony_ci					struct devlink_port *devlink_port,
14358c2ecf20Sopenharmony_ci					struct devlink_sb *devlink_sb,
14368c2ecf20Sopenharmony_ci					u16 pool_index,
14378c2ecf20Sopenharmony_ci					enum devlink_command cmd,
14388c2ecf20Sopenharmony_ci					u32 portid, u32 seq, int flags)
14398c2ecf20Sopenharmony_ci{
14408c2ecf20Sopenharmony_ci	const struct devlink_ops *ops = devlink->ops;
14418c2ecf20Sopenharmony_ci	u32 threshold;
14428c2ecf20Sopenharmony_ci	void *hdr;
14438c2ecf20Sopenharmony_ci	int err;
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci	err = ops->sb_port_pool_get(devlink_port, devlink_sb->index,
14468c2ecf20Sopenharmony_ci				    pool_index, &threshold);
14478c2ecf20Sopenharmony_ci	if (err)
14488c2ecf20Sopenharmony_ci		return err;
14498c2ecf20Sopenharmony_ci
14508c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
14518c2ecf20Sopenharmony_ci	if (!hdr)
14528c2ecf20Sopenharmony_ci		return -EMSGSIZE;
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(msg, devlink))
14558c2ecf20Sopenharmony_ci		goto nla_put_failure;
14568c2ecf20Sopenharmony_ci	if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
14578c2ecf20Sopenharmony_ci		goto nla_put_failure;
14588c2ecf20Sopenharmony_ci	if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
14598c2ecf20Sopenharmony_ci		goto nla_put_failure;
14608c2ecf20Sopenharmony_ci	if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
14618c2ecf20Sopenharmony_ci		goto nla_put_failure;
14628c2ecf20Sopenharmony_ci	if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
14638c2ecf20Sopenharmony_ci		goto nla_put_failure;
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	if (ops->sb_occ_port_pool_get) {
14668c2ecf20Sopenharmony_ci		u32 cur;
14678c2ecf20Sopenharmony_ci		u32 max;
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci		err = ops->sb_occ_port_pool_get(devlink_port, devlink_sb->index,
14708c2ecf20Sopenharmony_ci						pool_index, &cur, &max);
14718c2ecf20Sopenharmony_ci		if (err && err != -EOPNOTSUPP)
14728c2ecf20Sopenharmony_ci			goto sb_occ_get_failure;
14738c2ecf20Sopenharmony_ci		if (!err) {
14748c2ecf20Sopenharmony_ci			if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
14758c2ecf20Sopenharmony_ci				goto nla_put_failure;
14768c2ecf20Sopenharmony_ci			if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
14778c2ecf20Sopenharmony_ci				goto nla_put_failure;
14788c2ecf20Sopenharmony_ci		}
14798c2ecf20Sopenharmony_ci	}
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
14828c2ecf20Sopenharmony_ci	return 0;
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_cinla_put_failure:
14858c2ecf20Sopenharmony_ci	err = -EMSGSIZE;
14868c2ecf20Sopenharmony_cisb_occ_get_failure:
14878c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
14888c2ecf20Sopenharmony_ci	return err;
14898c2ecf20Sopenharmony_ci}
14908c2ecf20Sopenharmony_ci
14918c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_port_pool_get_doit(struct sk_buff *skb,
14928c2ecf20Sopenharmony_ci						struct genl_info *info)
14938c2ecf20Sopenharmony_ci{
14948c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port = info->user_ptr[1];
14958c2ecf20Sopenharmony_ci	struct devlink *devlink = devlink_port->devlink;
14968c2ecf20Sopenharmony_ci	struct devlink_sb *devlink_sb;
14978c2ecf20Sopenharmony_ci	struct sk_buff *msg;
14988c2ecf20Sopenharmony_ci	u16 pool_index;
14998c2ecf20Sopenharmony_ci	int err;
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	devlink_sb = devlink_sb_get_from_info(devlink, info);
15028c2ecf20Sopenharmony_ci	if (IS_ERR(devlink_sb))
15038c2ecf20Sopenharmony_ci		return PTR_ERR(devlink_sb);
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
15068c2ecf20Sopenharmony_ci						  &pool_index);
15078c2ecf20Sopenharmony_ci	if (err)
15088c2ecf20Sopenharmony_ci		return err;
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	if (!devlink->ops->sb_port_pool_get)
15118c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
15128c2ecf20Sopenharmony_ci
15138c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
15148c2ecf20Sopenharmony_ci	if (!msg)
15158c2ecf20Sopenharmony_ci		return -ENOMEM;
15168c2ecf20Sopenharmony_ci
15178c2ecf20Sopenharmony_ci	err = devlink_nl_sb_port_pool_fill(msg, devlink, devlink_port,
15188c2ecf20Sopenharmony_ci					   devlink_sb, pool_index,
15198c2ecf20Sopenharmony_ci					   DEVLINK_CMD_SB_PORT_POOL_NEW,
15208c2ecf20Sopenharmony_ci					   info->snd_portid, info->snd_seq, 0);
15218c2ecf20Sopenharmony_ci	if (err) {
15228c2ecf20Sopenharmony_ci		nlmsg_free(msg);
15238c2ecf20Sopenharmony_ci		return err;
15248c2ecf20Sopenharmony_ci	}
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci	return genlmsg_reply(msg, info);
15278c2ecf20Sopenharmony_ci}
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_cistatic int __sb_port_pool_get_dumpit(struct sk_buff *msg, int start, int *p_idx,
15308c2ecf20Sopenharmony_ci				     struct devlink *devlink,
15318c2ecf20Sopenharmony_ci				     struct devlink_sb *devlink_sb,
15328c2ecf20Sopenharmony_ci				     u32 portid, u32 seq)
15338c2ecf20Sopenharmony_ci{
15348c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port;
15358c2ecf20Sopenharmony_ci	u16 pool_count = devlink_sb_pool_count(devlink_sb);
15368c2ecf20Sopenharmony_ci	u16 pool_index;
15378c2ecf20Sopenharmony_ci	int err;
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	list_for_each_entry(devlink_port, &devlink->port_list, list) {
15408c2ecf20Sopenharmony_ci		for (pool_index = 0; pool_index < pool_count; pool_index++) {
15418c2ecf20Sopenharmony_ci			if (*p_idx < start) {
15428c2ecf20Sopenharmony_ci				(*p_idx)++;
15438c2ecf20Sopenharmony_ci				continue;
15448c2ecf20Sopenharmony_ci			}
15458c2ecf20Sopenharmony_ci			err = devlink_nl_sb_port_pool_fill(msg, devlink,
15468c2ecf20Sopenharmony_ci							   devlink_port,
15478c2ecf20Sopenharmony_ci							   devlink_sb,
15488c2ecf20Sopenharmony_ci							   pool_index,
15498c2ecf20Sopenharmony_ci							   DEVLINK_CMD_SB_PORT_POOL_NEW,
15508c2ecf20Sopenharmony_ci							   portid, seq,
15518c2ecf20Sopenharmony_ci							   NLM_F_MULTI);
15528c2ecf20Sopenharmony_ci			if (err)
15538c2ecf20Sopenharmony_ci				return err;
15548c2ecf20Sopenharmony_ci			(*p_idx)++;
15558c2ecf20Sopenharmony_ci		}
15568c2ecf20Sopenharmony_ci	}
15578c2ecf20Sopenharmony_ci	return 0;
15588c2ecf20Sopenharmony_ci}
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_port_pool_get_dumpit(struct sk_buff *msg,
15618c2ecf20Sopenharmony_ci						  struct netlink_callback *cb)
15628c2ecf20Sopenharmony_ci{
15638c2ecf20Sopenharmony_ci	struct devlink *devlink;
15648c2ecf20Sopenharmony_ci	struct devlink_sb *devlink_sb;
15658c2ecf20Sopenharmony_ci	int start = cb->args[0];
15668c2ecf20Sopenharmony_ci	int idx = 0;
15678c2ecf20Sopenharmony_ci	int err = 0;
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
15708c2ecf20Sopenharmony_ci	list_for_each_entry(devlink, &devlink_list, list) {
15718c2ecf20Sopenharmony_ci		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
15728c2ecf20Sopenharmony_ci		    !devlink->ops->sb_port_pool_get)
15738c2ecf20Sopenharmony_ci			continue;
15748c2ecf20Sopenharmony_ci		mutex_lock(&devlink->lock);
15758c2ecf20Sopenharmony_ci		list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
15768c2ecf20Sopenharmony_ci			err = __sb_port_pool_get_dumpit(msg, start, &idx,
15778c2ecf20Sopenharmony_ci							devlink, devlink_sb,
15788c2ecf20Sopenharmony_ci							NETLINK_CB(cb->skb).portid,
15798c2ecf20Sopenharmony_ci							cb->nlh->nlmsg_seq);
15808c2ecf20Sopenharmony_ci			if (err == -EOPNOTSUPP) {
15818c2ecf20Sopenharmony_ci				err = 0;
15828c2ecf20Sopenharmony_ci			} else if (err) {
15838c2ecf20Sopenharmony_ci				mutex_unlock(&devlink->lock);
15848c2ecf20Sopenharmony_ci				goto out;
15858c2ecf20Sopenharmony_ci			}
15868c2ecf20Sopenharmony_ci		}
15878c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->lock);
15888c2ecf20Sopenharmony_ci	}
15898c2ecf20Sopenharmony_ciout:
15908c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci	if (err != -EMSGSIZE)
15938c2ecf20Sopenharmony_ci		return err;
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	cb->args[0] = idx;
15968c2ecf20Sopenharmony_ci	return msg->len;
15978c2ecf20Sopenharmony_ci}
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_cistatic int devlink_sb_port_pool_set(struct devlink_port *devlink_port,
16008c2ecf20Sopenharmony_ci				    unsigned int sb_index, u16 pool_index,
16018c2ecf20Sopenharmony_ci				    u32 threshold,
16028c2ecf20Sopenharmony_ci				    struct netlink_ext_ack *extack)
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci{
16058c2ecf20Sopenharmony_ci	const struct devlink_ops *ops = devlink_port->devlink->ops;
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	if (ops->sb_port_pool_set)
16088c2ecf20Sopenharmony_ci		return ops->sb_port_pool_set(devlink_port, sb_index,
16098c2ecf20Sopenharmony_ci					     pool_index, threshold, extack);
16108c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
16118c2ecf20Sopenharmony_ci}
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb,
16148c2ecf20Sopenharmony_ci						struct genl_info *info)
16158c2ecf20Sopenharmony_ci{
16168c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port = info->user_ptr[1];
16178c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
16188c2ecf20Sopenharmony_ci	struct devlink_sb *devlink_sb;
16198c2ecf20Sopenharmony_ci	u16 pool_index;
16208c2ecf20Sopenharmony_ci	u32 threshold;
16218c2ecf20Sopenharmony_ci	int err;
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	devlink_sb = devlink_sb_get_from_info(devlink, info);
16248c2ecf20Sopenharmony_ci	if (IS_ERR(devlink_sb))
16258c2ecf20Sopenharmony_ci		return PTR_ERR(devlink_sb);
16268c2ecf20Sopenharmony_ci
16278c2ecf20Sopenharmony_ci	err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
16288c2ecf20Sopenharmony_ci						  &pool_index);
16298c2ecf20Sopenharmony_ci	if (err)
16308c2ecf20Sopenharmony_ci		return err;
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
16338c2ecf20Sopenharmony_ci		return -EINVAL;
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
16368c2ecf20Sopenharmony_ci	return devlink_sb_port_pool_set(devlink_port, devlink_sb->index,
16378c2ecf20Sopenharmony_ci					pool_index, threshold, info->extack);
16388c2ecf20Sopenharmony_ci}
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_cistatic int
16418c2ecf20Sopenharmony_cidevlink_nl_sb_tc_pool_bind_fill(struct sk_buff *msg, struct devlink *devlink,
16428c2ecf20Sopenharmony_ci				struct devlink_port *devlink_port,
16438c2ecf20Sopenharmony_ci				struct devlink_sb *devlink_sb, u16 tc_index,
16448c2ecf20Sopenharmony_ci				enum devlink_sb_pool_type pool_type,
16458c2ecf20Sopenharmony_ci				enum devlink_command cmd,
16468c2ecf20Sopenharmony_ci				u32 portid, u32 seq, int flags)
16478c2ecf20Sopenharmony_ci{
16488c2ecf20Sopenharmony_ci	const struct devlink_ops *ops = devlink->ops;
16498c2ecf20Sopenharmony_ci	u16 pool_index;
16508c2ecf20Sopenharmony_ci	u32 threshold;
16518c2ecf20Sopenharmony_ci	void *hdr;
16528c2ecf20Sopenharmony_ci	int err;
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci	err = ops->sb_tc_pool_bind_get(devlink_port, devlink_sb->index,
16558c2ecf20Sopenharmony_ci				       tc_index, pool_type,
16568c2ecf20Sopenharmony_ci				       &pool_index, &threshold);
16578c2ecf20Sopenharmony_ci	if (err)
16588c2ecf20Sopenharmony_ci		return err;
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
16618c2ecf20Sopenharmony_ci	if (!hdr)
16628c2ecf20Sopenharmony_ci		return -EMSGSIZE;
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(msg, devlink))
16658c2ecf20Sopenharmony_ci		goto nla_put_failure;
16668c2ecf20Sopenharmony_ci	if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_port->index))
16678c2ecf20Sopenharmony_ci		goto nla_put_failure;
16688c2ecf20Sopenharmony_ci	if (nla_put_u32(msg, DEVLINK_ATTR_SB_INDEX, devlink_sb->index))
16698c2ecf20Sopenharmony_ci		goto nla_put_failure;
16708c2ecf20Sopenharmony_ci	if (nla_put_u16(msg, DEVLINK_ATTR_SB_TC_INDEX, tc_index))
16718c2ecf20Sopenharmony_ci		goto nla_put_failure;
16728c2ecf20Sopenharmony_ci	if (nla_put_u8(msg, DEVLINK_ATTR_SB_POOL_TYPE, pool_type))
16738c2ecf20Sopenharmony_ci		goto nla_put_failure;
16748c2ecf20Sopenharmony_ci	if (nla_put_u16(msg, DEVLINK_ATTR_SB_POOL_INDEX, pool_index))
16758c2ecf20Sopenharmony_ci		goto nla_put_failure;
16768c2ecf20Sopenharmony_ci	if (nla_put_u32(msg, DEVLINK_ATTR_SB_THRESHOLD, threshold))
16778c2ecf20Sopenharmony_ci		goto nla_put_failure;
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci	if (ops->sb_occ_tc_port_bind_get) {
16808c2ecf20Sopenharmony_ci		u32 cur;
16818c2ecf20Sopenharmony_ci		u32 max;
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci		err = ops->sb_occ_tc_port_bind_get(devlink_port,
16848c2ecf20Sopenharmony_ci						   devlink_sb->index,
16858c2ecf20Sopenharmony_ci						   tc_index, pool_type,
16868c2ecf20Sopenharmony_ci						   &cur, &max);
16878c2ecf20Sopenharmony_ci		if (err && err != -EOPNOTSUPP)
16888c2ecf20Sopenharmony_ci			return err;
16898c2ecf20Sopenharmony_ci		if (!err) {
16908c2ecf20Sopenharmony_ci			if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_CUR, cur))
16918c2ecf20Sopenharmony_ci				goto nla_put_failure;
16928c2ecf20Sopenharmony_ci			if (nla_put_u32(msg, DEVLINK_ATTR_SB_OCC_MAX, max))
16938c2ecf20Sopenharmony_ci				goto nla_put_failure;
16948c2ecf20Sopenharmony_ci		}
16958c2ecf20Sopenharmony_ci	}
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
16988c2ecf20Sopenharmony_ci	return 0;
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_cinla_put_failure:
17018c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
17028c2ecf20Sopenharmony_ci	return -EMSGSIZE;
17038c2ecf20Sopenharmony_ci}
17048c2ecf20Sopenharmony_ci
17058c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_tc_pool_bind_get_doit(struct sk_buff *skb,
17068c2ecf20Sopenharmony_ci						   struct genl_info *info)
17078c2ecf20Sopenharmony_ci{
17088c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port = info->user_ptr[1];
17098c2ecf20Sopenharmony_ci	struct devlink *devlink = devlink_port->devlink;
17108c2ecf20Sopenharmony_ci	struct devlink_sb *devlink_sb;
17118c2ecf20Sopenharmony_ci	struct sk_buff *msg;
17128c2ecf20Sopenharmony_ci	enum devlink_sb_pool_type pool_type;
17138c2ecf20Sopenharmony_ci	u16 tc_index;
17148c2ecf20Sopenharmony_ci	int err;
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci	devlink_sb = devlink_sb_get_from_info(devlink, info);
17178c2ecf20Sopenharmony_ci	if (IS_ERR(devlink_sb))
17188c2ecf20Sopenharmony_ci		return PTR_ERR(devlink_sb);
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci	err = devlink_sb_pool_type_get_from_info(info, &pool_type);
17218c2ecf20Sopenharmony_ci	if (err)
17228c2ecf20Sopenharmony_ci		return err;
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
17258c2ecf20Sopenharmony_ci						pool_type, &tc_index);
17268c2ecf20Sopenharmony_ci	if (err)
17278c2ecf20Sopenharmony_ci		return err;
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci	if (!devlink->ops->sb_tc_pool_bind_get)
17308c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
17318c2ecf20Sopenharmony_ci
17328c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
17338c2ecf20Sopenharmony_ci	if (!msg)
17348c2ecf20Sopenharmony_ci		return -ENOMEM;
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_ci	err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink, devlink_port,
17378c2ecf20Sopenharmony_ci					      devlink_sb, tc_index, pool_type,
17388c2ecf20Sopenharmony_ci					      DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
17398c2ecf20Sopenharmony_ci					      info->snd_portid,
17408c2ecf20Sopenharmony_ci					      info->snd_seq, 0);
17418c2ecf20Sopenharmony_ci	if (err) {
17428c2ecf20Sopenharmony_ci		nlmsg_free(msg);
17438c2ecf20Sopenharmony_ci		return err;
17448c2ecf20Sopenharmony_ci	}
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ci	return genlmsg_reply(msg, info);
17478c2ecf20Sopenharmony_ci}
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_cistatic int __sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
17508c2ecf20Sopenharmony_ci					int start, int *p_idx,
17518c2ecf20Sopenharmony_ci					struct devlink *devlink,
17528c2ecf20Sopenharmony_ci					struct devlink_sb *devlink_sb,
17538c2ecf20Sopenharmony_ci					u32 portid, u32 seq)
17548c2ecf20Sopenharmony_ci{
17558c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port;
17568c2ecf20Sopenharmony_ci	u16 tc_index;
17578c2ecf20Sopenharmony_ci	int err;
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	list_for_each_entry(devlink_port, &devlink->port_list, list) {
17608c2ecf20Sopenharmony_ci		for (tc_index = 0;
17618c2ecf20Sopenharmony_ci		     tc_index < devlink_sb->ingress_tc_count; tc_index++) {
17628c2ecf20Sopenharmony_ci			if (*p_idx < start) {
17638c2ecf20Sopenharmony_ci				(*p_idx)++;
17648c2ecf20Sopenharmony_ci				continue;
17658c2ecf20Sopenharmony_ci			}
17668c2ecf20Sopenharmony_ci			err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
17678c2ecf20Sopenharmony_ci							      devlink_port,
17688c2ecf20Sopenharmony_ci							      devlink_sb,
17698c2ecf20Sopenharmony_ci							      tc_index,
17708c2ecf20Sopenharmony_ci							      DEVLINK_SB_POOL_TYPE_INGRESS,
17718c2ecf20Sopenharmony_ci							      DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
17728c2ecf20Sopenharmony_ci							      portid, seq,
17738c2ecf20Sopenharmony_ci							      NLM_F_MULTI);
17748c2ecf20Sopenharmony_ci			if (err)
17758c2ecf20Sopenharmony_ci				return err;
17768c2ecf20Sopenharmony_ci			(*p_idx)++;
17778c2ecf20Sopenharmony_ci		}
17788c2ecf20Sopenharmony_ci		for (tc_index = 0;
17798c2ecf20Sopenharmony_ci		     tc_index < devlink_sb->egress_tc_count; tc_index++) {
17808c2ecf20Sopenharmony_ci			if (*p_idx < start) {
17818c2ecf20Sopenharmony_ci				(*p_idx)++;
17828c2ecf20Sopenharmony_ci				continue;
17838c2ecf20Sopenharmony_ci			}
17848c2ecf20Sopenharmony_ci			err = devlink_nl_sb_tc_pool_bind_fill(msg, devlink,
17858c2ecf20Sopenharmony_ci							      devlink_port,
17868c2ecf20Sopenharmony_ci							      devlink_sb,
17878c2ecf20Sopenharmony_ci							      tc_index,
17888c2ecf20Sopenharmony_ci							      DEVLINK_SB_POOL_TYPE_EGRESS,
17898c2ecf20Sopenharmony_ci							      DEVLINK_CMD_SB_TC_POOL_BIND_NEW,
17908c2ecf20Sopenharmony_ci							      portid, seq,
17918c2ecf20Sopenharmony_ci							      NLM_F_MULTI);
17928c2ecf20Sopenharmony_ci			if (err)
17938c2ecf20Sopenharmony_ci				return err;
17948c2ecf20Sopenharmony_ci			(*p_idx)++;
17958c2ecf20Sopenharmony_ci		}
17968c2ecf20Sopenharmony_ci	}
17978c2ecf20Sopenharmony_ci	return 0;
17988c2ecf20Sopenharmony_ci}
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_cistatic int
18018c2ecf20Sopenharmony_cidevlink_nl_cmd_sb_tc_pool_bind_get_dumpit(struct sk_buff *msg,
18028c2ecf20Sopenharmony_ci					  struct netlink_callback *cb)
18038c2ecf20Sopenharmony_ci{
18048c2ecf20Sopenharmony_ci	struct devlink *devlink;
18058c2ecf20Sopenharmony_ci	struct devlink_sb *devlink_sb;
18068c2ecf20Sopenharmony_ci	int start = cb->args[0];
18078c2ecf20Sopenharmony_ci	int idx = 0;
18088c2ecf20Sopenharmony_ci	int err = 0;
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
18118c2ecf20Sopenharmony_ci	list_for_each_entry(devlink, &devlink_list, list) {
18128c2ecf20Sopenharmony_ci		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)) ||
18138c2ecf20Sopenharmony_ci		    !devlink->ops->sb_tc_pool_bind_get)
18148c2ecf20Sopenharmony_ci			continue;
18158c2ecf20Sopenharmony_ci
18168c2ecf20Sopenharmony_ci		mutex_lock(&devlink->lock);
18178c2ecf20Sopenharmony_ci		list_for_each_entry(devlink_sb, &devlink->sb_list, list) {
18188c2ecf20Sopenharmony_ci			err = __sb_tc_pool_bind_get_dumpit(msg, start, &idx,
18198c2ecf20Sopenharmony_ci							   devlink,
18208c2ecf20Sopenharmony_ci							   devlink_sb,
18218c2ecf20Sopenharmony_ci							   NETLINK_CB(cb->skb).portid,
18228c2ecf20Sopenharmony_ci							   cb->nlh->nlmsg_seq);
18238c2ecf20Sopenharmony_ci			if (err == -EOPNOTSUPP) {
18248c2ecf20Sopenharmony_ci				err = 0;
18258c2ecf20Sopenharmony_ci			} else if (err) {
18268c2ecf20Sopenharmony_ci				mutex_unlock(&devlink->lock);
18278c2ecf20Sopenharmony_ci				goto out;
18288c2ecf20Sopenharmony_ci			}
18298c2ecf20Sopenharmony_ci		}
18308c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->lock);
18318c2ecf20Sopenharmony_ci	}
18328c2ecf20Sopenharmony_ciout:
18338c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
18348c2ecf20Sopenharmony_ci
18358c2ecf20Sopenharmony_ci	if (err != -EMSGSIZE)
18368c2ecf20Sopenharmony_ci		return err;
18378c2ecf20Sopenharmony_ci
18388c2ecf20Sopenharmony_ci	cb->args[0] = idx;
18398c2ecf20Sopenharmony_ci	return msg->len;
18408c2ecf20Sopenharmony_ci}
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_cistatic int devlink_sb_tc_pool_bind_set(struct devlink_port *devlink_port,
18438c2ecf20Sopenharmony_ci				       unsigned int sb_index, u16 tc_index,
18448c2ecf20Sopenharmony_ci				       enum devlink_sb_pool_type pool_type,
18458c2ecf20Sopenharmony_ci				       u16 pool_index, u32 threshold,
18468c2ecf20Sopenharmony_ci				       struct netlink_ext_ack *extack)
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_ci{
18498c2ecf20Sopenharmony_ci	const struct devlink_ops *ops = devlink_port->devlink->ops;
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	if (ops->sb_tc_pool_bind_set)
18528c2ecf20Sopenharmony_ci		return ops->sb_tc_pool_bind_set(devlink_port, sb_index,
18538c2ecf20Sopenharmony_ci						tc_index, pool_type,
18548c2ecf20Sopenharmony_ci						pool_index, threshold, extack);
18558c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
18568c2ecf20Sopenharmony_ci}
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
18598c2ecf20Sopenharmony_ci						   struct genl_info *info)
18608c2ecf20Sopenharmony_ci{
18618c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port = info->user_ptr[1];
18628c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
18638c2ecf20Sopenharmony_ci	enum devlink_sb_pool_type pool_type;
18648c2ecf20Sopenharmony_ci	struct devlink_sb *devlink_sb;
18658c2ecf20Sopenharmony_ci	u16 tc_index;
18668c2ecf20Sopenharmony_ci	u16 pool_index;
18678c2ecf20Sopenharmony_ci	u32 threshold;
18688c2ecf20Sopenharmony_ci	int err;
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci	devlink_sb = devlink_sb_get_from_info(devlink, info);
18718c2ecf20Sopenharmony_ci	if (IS_ERR(devlink_sb))
18728c2ecf20Sopenharmony_ci		return PTR_ERR(devlink_sb);
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_ci	err = devlink_sb_pool_type_get_from_info(info, &pool_type);
18758c2ecf20Sopenharmony_ci	if (err)
18768c2ecf20Sopenharmony_ci		return err;
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci	err = devlink_sb_tc_index_get_from_info(devlink_sb, info,
18798c2ecf20Sopenharmony_ci						pool_type, &tc_index);
18808c2ecf20Sopenharmony_ci	if (err)
18818c2ecf20Sopenharmony_ci		return err;
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci	err = devlink_sb_pool_index_get_from_info(devlink_sb, info,
18848c2ecf20Sopenharmony_ci						  &pool_index);
18858c2ecf20Sopenharmony_ci	if (err)
18868c2ecf20Sopenharmony_ci		return err;
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_SB_THRESHOLD])
18898c2ecf20Sopenharmony_ci		return -EINVAL;
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci	threshold = nla_get_u32(info->attrs[DEVLINK_ATTR_SB_THRESHOLD]);
18928c2ecf20Sopenharmony_ci	return devlink_sb_tc_pool_bind_set(devlink_port, devlink_sb->index,
18938c2ecf20Sopenharmony_ci					   tc_index, pool_type,
18948c2ecf20Sopenharmony_ci					   pool_index, threshold, info->extack);
18958c2ecf20Sopenharmony_ci}
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
18988c2ecf20Sopenharmony_ci					       struct genl_info *info)
18998c2ecf20Sopenharmony_ci{
19008c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
19018c2ecf20Sopenharmony_ci	const struct devlink_ops *ops = devlink->ops;
19028c2ecf20Sopenharmony_ci	struct devlink_sb *devlink_sb;
19038c2ecf20Sopenharmony_ci
19048c2ecf20Sopenharmony_ci	devlink_sb = devlink_sb_get_from_info(devlink, info);
19058c2ecf20Sopenharmony_ci	if (IS_ERR(devlink_sb))
19068c2ecf20Sopenharmony_ci		return PTR_ERR(devlink_sb);
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_ci	if (ops->sb_occ_snapshot)
19098c2ecf20Sopenharmony_ci		return ops->sb_occ_snapshot(devlink, devlink_sb->index);
19108c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
19118c2ecf20Sopenharmony_ci}
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb,
19148c2ecf20Sopenharmony_ci						struct genl_info *info)
19158c2ecf20Sopenharmony_ci{
19168c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
19178c2ecf20Sopenharmony_ci	const struct devlink_ops *ops = devlink->ops;
19188c2ecf20Sopenharmony_ci	struct devlink_sb *devlink_sb;
19198c2ecf20Sopenharmony_ci
19208c2ecf20Sopenharmony_ci	devlink_sb = devlink_sb_get_from_info(devlink, info);
19218c2ecf20Sopenharmony_ci	if (IS_ERR(devlink_sb))
19228c2ecf20Sopenharmony_ci		return PTR_ERR(devlink_sb);
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci	if (ops->sb_occ_max_clear)
19258c2ecf20Sopenharmony_ci		return ops->sb_occ_max_clear(devlink, devlink_sb->index);
19268c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
19278c2ecf20Sopenharmony_ci}
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_cistatic int devlink_nl_eswitch_fill(struct sk_buff *msg, struct devlink *devlink,
19308c2ecf20Sopenharmony_ci				   enum devlink_command cmd, u32 portid,
19318c2ecf20Sopenharmony_ci				   u32 seq, int flags)
19328c2ecf20Sopenharmony_ci{
19338c2ecf20Sopenharmony_ci	const struct devlink_ops *ops = devlink->ops;
19348c2ecf20Sopenharmony_ci	enum devlink_eswitch_encap_mode encap_mode;
19358c2ecf20Sopenharmony_ci	u8 inline_mode;
19368c2ecf20Sopenharmony_ci	void *hdr;
19378c2ecf20Sopenharmony_ci	int err = 0;
19388c2ecf20Sopenharmony_ci	u16 mode;
19398c2ecf20Sopenharmony_ci
19408c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
19418c2ecf20Sopenharmony_ci	if (!hdr)
19428c2ecf20Sopenharmony_ci		return -EMSGSIZE;
19438c2ecf20Sopenharmony_ci
19448c2ecf20Sopenharmony_ci	err = devlink_nl_put_handle(msg, devlink);
19458c2ecf20Sopenharmony_ci	if (err)
19468c2ecf20Sopenharmony_ci		goto nla_put_failure;
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci	if (ops->eswitch_mode_get) {
19498c2ecf20Sopenharmony_ci		err = ops->eswitch_mode_get(devlink, &mode);
19508c2ecf20Sopenharmony_ci		if (err)
19518c2ecf20Sopenharmony_ci			goto nla_put_failure;
19528c2ecf20Sopenharmony_ci		err = nla_put_u16(msg, DEVLINK_ATTR_ESWITCH_MODE, mode);
19538c2ecf20Sopenharmony_ci		if (err)
19548c2ecf20Sopenharmony_ci			goto nla_put_failure;
19558c2ecf20Sopenharmony_ci	}
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_ci	if (ops->eswitch_inline_mode_get) {
19588c2ecf20Sopenharmony_ci		err = ops->eswitch_inline_mode_get(devlink, &inline_mode);
19598c2ecf20Sopenharmony_ci		if (err)
19608c2ecf20Sopenharmony_ci			goto nla_put_failure;
19618c2ecf20Sopenharmony_ci		err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
19628c2ecf20Sopenharmony_ci				 inline_mode);
19638c2ecf20Sopenharmony_ci		if (err)
19648c2ecf20Sopenharmony_ci			goto nla_put_failure;
19658c2ecf20Sopenharmony_ci	}
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_ci	if (ops->eswitch_encap_mode_get) {
19688c2ecf20Sopenharmony_ci		err = ops->eswitch_encap_mode_get(devlink, &encap_mode);
19698c2ecf20Sopenharmony_ci		if (err)
19708c2ecf20Sopenharmony_ci			goto nla_put_failure;
19718c2ecf20Sopenharmony_ci		err = nla_put_u8(msg, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, encap_mode);
19728c2ecf20Sopenharmony_ci		if (err)
19738c2ecf20Sopenharmony_ci			goto nla_put_failure;
19748c2ecf20Sopenharmony_ci	}
19758c2ecf20Sopenharmony_ci
19768c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
19778c2ecf20Sopenharmony_ci	return 0;
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_cinla_put_failure:
19808c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
19818c2ecf20Sopenharmony_ci	return err;
19828c2ecf20Sopenharmony_ci}
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb,
19858c2ecf20Sopenharmony_ci					   struct genl_info *info)
19868c2ecf20Sopenharmony_ci{
19878c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
19888c2ecf20Sopenharmony_ci	struct sk_buff *msg;
19898c2ecf20Sopenharmony_ci	int err;
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
19928c2ecf20Sopenharmony_ci	if (!msg)
19938c2ecf20Sopenharmony_ci		return -ENOMEM;
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci	err = devlink_nl_eswitch_fill(msg, devlink, DEVLINK_CMD_ESWITCH_GET,
19968c2ecf20Sopenharmony_ci				      info->snd_portid, info->snd_seq, 0);
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci	if (err) {
19998c2ecf20Sopenharmony_ci		nlmsg_free(msg);
20008c2ecf20Sopenharmony_ci		return err;
20018c2ecf20Sopenharmony_ci	}
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci	return genlmsg_reply(msg, info);
20048c2ecf20Sopenharmony_ci}
20058c2ecf20Sopenharmony_ci
20068c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb,
20078c2ecf20Sopenharmony_ci					   struct genl_info *info)
20088c2ecf20Sopenharmony_ci{
20098c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
20108c2ecf20Sopenharmony_ci	const struct devlink_ops *ops = devlink->ops;
20118c2ecf20Sopenharmony_ci	enum devlink_eswitch_encap_mode encap_mode;
20128c2ecf20Sopenharmony_ci	u8 inline_mode;
20138c2ecf20Sopenharmony_ci	int err = 0;
20148c2ecf20Sopenharmony_ci	u16 mode;
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	if (info->attrs[DEVLINK_ATTR_ESWITCH_MODE]) {
20178c2ecf20Sopenharmony_ci		if (!ops->eswitch_mode_set)
20188c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
20198c2ecf20Sopenharmony_ci		mode = nla_get_u16(info->attrs[DEVLINK_ATTR_ESWITCH_MODE]);
20208c2ecf20Sopenharmony_ci		err = ops->eswitch_mode_set(devlink, mode, info->extack);
20218c2ecf20Sopenharmony_ci		if (err)
20228c2ecf20Sopenharmony_ci			return err;
20238c2ecf20Sopenharmony_ci	}
20248c2ecf20Sopenharmony_ci
20258c2ecf20Sopenharmony_ci	if (info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
20268c2ecf20Sopenharmony_ci		if (!ops->eswitch_inline_mode_set)
20278c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
20288c2ecf20Sopenharmony_ci		inline_mode = nla_get_u8(
20298c2ecf20Sopenharmony_ci				info->attrs[DEVLINK_ATTR_ESWITCH_INLINE_MODE]);
20308c2ecf20Sopenharmony_ci		err = ops->eswitch_inline_mode_set(devlink, inline_mode,
20318c2ecf20Sopenharmony_ci						   info->extack);
20328c2ecf20Sopenharmony_ci		if (err)
20338c2ecf20Sopenharmony_ci			return err;
20348c2ecf20Sopenharmony_ci	}
20358c2ecf20Sopenharmony_ci
20368c2ecf20Sopenharmony_ci	if (info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
20378c2ecf20Sopenharmony_ci		if (!ops->eswitch_encap_mode_set)
20388c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
20398c2ecf20Sopenharmony_ci		encap_mode = nla_get_u8(info->attrs[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
20408c2ecf20Sopenharmony_ci		err = ops->eswitch_encap_mode_set(devlink, encap_mode,
20418c2ecf20Sopenharmony_ci						  info->extack);
20428c2ecf20Sopenharmony_ci		if (err)
20438c2ecf20Sopenharmony_ci			return err;
20448c2ecf20Sopenharmony_ci	}
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci	return 0;
20478c2ecf20Sopenharmony_ci}
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_ciint devlink_dpipe_match_put(struct sk_buff *skb,
20508c2ecf20Sopenharmony_ci			    struct devlink_dpipe_match *match)
20518c2ecf20Sopenharmony_ci{
20528c2ecf20Sopenharmony_ci	struct devlink_dpipe_header *header = match->header;
20538c2ecf20Sopenharmony_ci	struct devlink_dpipe_field *field = &header->fields[match->field_id];
20548c2ecf20Sopenharmony_ci	struct nlattr *match_attr;
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_ci	match_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_MATCH);
20578c2ecf20Sopenharmony_ci	if (!match_attr)
20588c2ecf20Sopenharmony_ci		return -EMSGSIZE;
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
20618c2ecf20Sopenharmony_ci	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
20628c2ecf20Sopenharmony_ci	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
20638c2ecf20Sopenharmony_ci	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
20648c2ecf20Sopenharmony_ci	    nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
20658c2ecf20Sopenharmony_ci		goto nla_put_failure;
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_ci	nla_nest_end(skb, match_attr);
20688c2ecf20Sopenharmony_ci	return 0;
20698c2ecf20Sopenharmony_ci
20708c2ecf20Sopenharmony_cinla_put_failure:
20718c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, match_attr);
20728c2ecf20Sopenharmony_ci	return -EMSGSIZE;
20738c2ecf20Sopenharmony_ci}
20748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
20758c2ecf20Sopenharmony_ci
20768c2ecf20Sopenharmony_cistatic int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
20778c2ecf20Sopenharmony_ci				     struct sk_buff *skb)
20788c2ecf20Sopenharmony_ci{
20798c2ecf20Sopenharmony_ci	struct nlattr *matches_attr;
20808c2ecf20Sopenharmony_ci
20818c2ecf20Sopenharmony_ci	matches_attr = nla_nest_start_noflag(skb,
20828c2ecf20Sopenharmony_ci					     DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
20838c2ecf20Sopenharmony_ci	if (!matches_attr)
20848c2ecf20Sopenharmony_ci		return -EMSGSIZE;
20858c2ecf20Sopenharmony_ci
20868c2ecf20Sopenharmony_ci	if (table->table_ops->matches_dump(table->priv, skb))
20878c2ecf20Sopenharmony_ci		goto nla_put_failure;
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci	nla_nest_end(skb, matches_attr);
20908c2ecf20Sopenharmony_ci	return 0;
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_cinla_put_failure:
20938c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, matches_attr);
20948c2ecf20Sopenharmony_ci	return -EMSGSIZE;
20958c2ecf20Sopenharmony_ci}
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ciint devlink_dpipe_action_put(struct sk_buff *skb,
20988c2ecf20Sopenharmony_ci			     struct devlink_dpipe_action *action)
20998c2ecf20Sopenharmony_ci{
21008c2ecf20Sopenharmony_ci	struct devlink_dpipe_header *header = action->header;
21018c2ecf20Sopenharmony_ci	struct devlink_dpipe_field *field = &header->fields[action->field_id];
21028c2ecf20Sopenharmony_ci	struct nlattr *action_attr;
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci	action_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ACTION);
21058c2ecf20Sopenharmony_ci	if (!action_attr)
21068c2ecf20Sopenharmony_ci		return -EMSGSIZE;
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci	if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
21098c2ecf20Sopenharmony_ci	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
21108c2ecf20Sopenharmony_ci	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
21118c2ecf20Sopenharmony_ci	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
21128c2ecf20Sopenharmony_ci	    nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
21138c2ecf20Sopenharmony_ci		goto nla_put_failure;
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_ci	nla_nest_end(skb, action_attr);
21168c2ecf20Sopenharmony_ci	return 0;
21178c2ecf20Sopenharmony_ci
21188c2ecf20Sopenharmony_cinla_put_failure:
21198c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, action_attr);
21208c2ecf20Sopenharmony_ci	return -EMSGSIZE;
21218c2ecf20Sopenharmony_ci}
21228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_cistatic int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
21258c2ecf20Sopenharmony_ci				     struct sk_buff *skb)
21268c2ecf20Sopenharmony_ci{
21278c2ecf20Sopenharmony_ci	struct nlattr *actions_attr;
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci	actions_attr = nla_nest_start_noflag(skb,
21308c2ecf20Sopenharmony_ci					     DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
21318c2ecf20Sopenharmony_ci	if (!actions_attr)
21328c2ecf20Sopenharmony_ci		return -EMSGSIZE;
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci	if (table->table_ops->actions_dump(table->priv, skb))
21358c2ecf20Sopenharmony_ci		goto nla_put_failure;
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci	nla_nest_end(skb, actions_attr);
21388c2ecf20Sopenharmony_ci	return 0;
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_cinla_put_failure:
21418c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, actions_attr);
21428c2ecf20Sopenharmony_ci	return -EMSGSIZE;
21438c2ecf20Sopenharmony_ci}
21448c2ecf20Sopenharmony_ci
21458c2ecf20Sopenharmony_cistatic int devlink_dpipe_table_put(struct sk_buff *skb,
21468c2ecf20Sopenharmony_ci				   struct devlink_dpipe_table *table)
21478c2ecf20Sopenharmony_ci{
21488c2ecf20Sopenharmony_ci	struct nlattr *table_attr;
21498c2ecf20Sopenharmony_ci	u64 table_size;
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_ci	table_size = table->table_ops->size_get(table->priv);
21528c2ecf20Sopenharmony_ci	table_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLE);
21538c2ecf20Sopenharmony_ci	if (!table_attr)
21548c2ecf20Sopenharmony_ci		return -EMSGSIZE;
21558c2ecf20Sopenharmony_ci
21568c2ecf20Sopenharmony_ci	if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
21578c2ecf20Sopenharmony_ci	    nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size,
21588c2ecf20Sopenharmony_ci			      DEVLINK_ATTR_PAD))
21598c2ecf20Sopenharmony_ci		goto nla_put_failure;
21608c2ecf20Sopenharmony_ci	if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
21618c2ecf20Sopenharmony_ci		       table->counters_enabled))
21628c2ecf20Sopenharmony_ci		goto nla_put_failure;
21638c2ecf20Sopenharmony_ci
21648c2ecf20Sopenharmony_ci	if (table->resource_valid) {
21658c2ecf20Sopenharmony_ci		if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
21668c2ecf20Sopenharmony_ci				      table->resource_id, DEVLINK_ATTR_PAD) ||
21678c2ecf20Sopenharmony_ci		    nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
21688c2ecf20Sopenharmony_ci				      table->resource_units, DEVLINK_ATTR_PAD))
21698c2ecf20Sopenharmony_ci			goto nla_put_failure;
21708c2ecf20Sopenharmony_ci	}
21718c2ecf20Sopenharmony_ci	if (devlink_dpipe_matches_put(table, skb))
21728c2ecf20Sopenharmony_ci		goto nla_put_failure;
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci	if (devlink_dpipe_actions_put(table, skb))
21758c2ecf20Sopenharmony_ci		goto nla_put_failure;
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci	nla_nest_end(skb, table_attr);
21788c2ecf20Sopenharmony_ci	return 0;
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_cinla_put_failure:
21818c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, table_attr);
21828c2ecf20Sopenharmony_ci	return -EMSGSIZE;
21838c2ecf20Sopenharmony_ci}
21848c2ecf20Sopenharmony_ci
21858c2ecf20Sopenharmony_cistatic int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
21868c2ecf20Sopenharmony_ci					    struct genl_info *info)
21878c2ecf20Sopenharmony_ci{
21888c2ecf20Sopenharmony_ci	int err;
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ci	if (*pskb) {
21918c2ecf20Sopenharmony_ci		err = genlmsg_reply(*pskb, info);
21928c2ecf20Sopenharmony_ci		if (err)
21938c2ecf20Sopenharmony_ci			return err;
21948c2ecf20Sopenharmony_ci	}
21958c2ecf20Sopenharmony_ci	*pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
21968c2ecf20Sopenharmony_ci	if (!*pskb)
21978c2ecf20Sopenharmony_ci		return -ENOMEM;
21988c2ecf20Sopenharmony_ci	return 0;
21998c2ecf20Sopenharmony_ci}
22008c2ecf20Sopenharmony_ci
22018c2ecf20Sopenharmony_cistatic int devlink_dpipe_tables_fill(struct genl_info *info,
22028c2ecf20Sopenharmony_ci				     enum devlink_command cmd, int flags,
22038c2ecf20Sopenharmony_ci				     struct list_head *dpipe_tables,
22048c2ecf20Sopenharmony_ci				     const char *table_name)
22058c2ecf20Sopenharmony_ci{
22068c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
22078c2ecf20Sopenharmony_ci	struct devlink_dpipe_table *table;
22088c2ecf20Sopenharmony_ci	struct nlattr *tables_attr;
22098c2ecf20Sopenharmony_ci	struct sk_buff *skb = NULL;
22108c2ecf20Sopenharmony_ci	struct nlmsghdr *nlh;
22118c2ecf20Sopenharmony_ci	bool incomplete;
22128c2ecf20Sopenharmony_ci	void *hdr;
22138c2ecf20Sopenharmony_ci	int i;
22148c2ecf20Sopenharmony_ci	int err;
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci	table = list_first_entry(dpipe_tables,
22178c2ecf20Sopenharmony_ci				 struct devlink_dpipe_table, list);
22188c2ecf20Sopenharmony_cistart_again:
22198c2ecf20Sopenharmony_ci	err = devlink_dpipe_send_and_alloc_skb(&skb, info);
22208c2ecf20Sopenharmony_ci	if (err)
22218c2ecf20Sopenharmony_ci		return err;
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_ci	hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
22248c2ecf20Sopenharmony_ci			  &devlink_nl_family, NLM_F_MULTI, cmd);
22258c2ecf20Sopenharmony_ci	if (!hdr) {
22268c2ecf20Sopenharmony_ci		nlmsg_free(skb);
22278c2ecf20Sopenharmony_ci		return -EMSGSIZE;
22288c2ecf20Sopenharmony_ci	}
22298c2ecf20Sopenharmony_ci
22308c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(skb, devlink))
22318c2ecf20Sopenharmony_ci		goto nla_put_failure;
22328c2ecf20Sopenharmony_ci	tables_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLES);
22338c2ecf20Sopenharmony_ci	if (!tables_attr)
22348c2ecf20Sopenharmony_ci		goto nla_put_failure;
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_ci	i = 0;
22378c2ecf20Sopenharmony_ci	incomplete = false;
22388c2ecf20Sopenharmony_ci	list_for_each_entry_from(table, dpipe_tables, list) {
22398c2ecf20Sopenharmony_ci		if (!table_name) {
22408c2ecf20Sopenharmony_ci			err = devlink_dpipe_table_put(skb, table);
22418c2ecf20Sopenharmony_ci			if (err) {
22428c2ecf20Sopenharmony_ci				if (!i)
22438c2ecf20Sopenharmony_ci					goto err_table_put;
22448c2ecf20Sopenharmony_ci				incomplete = true;
22458c2ecf20Sopenharmony_ci				break;
22468c2ecf20Sopenharmony_ci			}
22478c2ecf20Sopenharmony_ci		} else {
22488c2ecf20Sopenharmony_ci			if (!strcmp(table->name, table_name)) {
22498c2ecf20Sopenharmony_ci				err = devlink_dpipe_table_put(skb, table);
22508c2ecf20Sopenharmony_ci				if (err)
22518c2ecf20Sopenharmony_ci					break;
22528c2ecf20Sopenharmony_ci			}
22538c2ecf20Sopenharmony_ci		}
22548c2ecf20Sopenharmony_ci		i++;
22558c2ecf20Sopenharmony_ci	}
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci	nla_nest_end(skb, tables_attr);
22588c2ecf20Sopenharmony_ci	genlmsg_end(skb, hdr);
22598c2ecf20Sopenharmony_ci	if (incomplete)
22608c2ecf20Sopenharmony_ci		goto start_again;
22618c2ecf20Sopenharmony_ci
22628c2ecf20Sopenharmony_cisend_done:
22638c2ecf20Sopenharmony_ci	nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
22648c2ecf20Sopenharmony_ci			NLMSG_DONE, 0, flags | NLM_F_MULTI);
22658c2ecf20Sopenharmony_ci	if (!nlh) {
22668c2ecf20Sopenharmony_ci		err = devlink_dpipe_send_and_alloc_skb(&skb, info);
22678c2ecf20Sopenharmony_ci		if (err)
22688c2ecf20Sopenharmony_ci			return err;
22698c2ecf20Sopenharmony_ci		goto send_done;
22708c2ecf20Sopenharmony_ci	}
22718c2ecf20Sopenharmony_ci
22728c2ecf20Sopenharmony_ci	return genlmsg_reply(skb, info);
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_cinla_put_failure:
22758c2ecf20Sopenharmony_ci	err = -EMSGSIZE;
22768c2ecf20Sopenharmony_cierr_table_put:
22778c2ecf20Sopenharmony_ci	nlmsg_free(skb);
22788c2ecf20Sopenharmony_ci	return err;
22798c2ecf20Sopenharmony_ci}
22808c2ecf20Sopenharmony_ci
22818c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb,
22828c2ecf20Sopenharmony_ci					  struct genl_info *info)
22838c2ecf20Sopenharmony_ci{
22848c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
22858c2ecf20Sopenharmony_ci	const char *table_name =  NULL;
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_ci	if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
22888c2ecf20Sopenharmony_ci		table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
22898c2ecf20Sopenharmony_ci
22908c2ecf20Sopenharmony_ci	return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
22918c2ecf20Sopenharmony_ci					 &devlink->dpipe_table_list,
22928c2ecf20Sopenharmony_ci					 table_name);
22938c2ecf20Sopenharmony_ci}
22948c2ecf20Sopenharmony_ci
22958c2ecf20Sopenharmony_cistatic int devlink_dpipe_value_put(struct sk_buff *skb,
22968c2ecf20Sopenharmony_ci				   struct devlink_dpipe_value *value)
22978c2ecf20Sopenharmony_ci{
22988c2ecf20Sopenharmony_ci	if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
22998c2ecf20Sopenharmony_ci		    value->value_size, value->value))
23008c2ecf20Sopenharmony_ci		return -EMSGSIZE;
23018c2ecf20Sopenharmony_ci	if (value->mask)
23028c2ecf20Sopenharmony_ci		if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
23038c2ecf20Sopenharmony_ci			    value->value_size, value->mask))
23048c2ecf20Sopenharmony_ci			return -EMSGSIZE;
23058c2ecf20Sopenharmony_ci	if (value->mapping_valid)
23068c2ecf20Sopenharmony_ci		if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
23078c2ecf20Sopenharmony_ci				value->mapping_value))
23088c2ecf20Sopenharmony_ci			return -EMSGSIZE;
23098c2ecf20Sopenharmony_ci	return 0;
23108c2ecf20Sopenharmony_ci}
23118c2ecf20Sopenharmony_ci
23128c2ecf20Sopenharmony_cistatic int devlink_dpipe_action_value_put(struct sk_buff *skb,
23138c2ecf20Sopenharmony_ci					  struct devlink_dpipe_value *value)
23148c2ecf20Sopenharmony_ci{
23158c2ecf20Sopenharmony_ci	if (!value->action)
23168c2ecf20Sopenharmony_ci		return -EINVAL;
23178c2ecf20Sopenharmony_ci	if (devlink_dpipe_action_put(skb, value->action))
23188c2ecf20Sopenharmony_ci		return -EMSGSIZE;
23198c2ecf20Sopenharmony_ci	if (devlink_dpipe_value_put(skb, value))
23208c2ecf20Sopenharmony_ci		return -EMSGSIZE;
23218c2ecf20Sopenharmony_ci	return 0;
23228c2ecf20Sopenharmony_ci}
23238c2ecf20Sopenharmony_ci
23248c2ecf20Sopenharmony_cistatic int devlink_dpipe_action_values_put(struct sk_buff *skb,
23258c2ecf20Sopenharmony_ci					   struct devlink_dpipe_value *values,
23268c2ecf20Sopenharmony_ci					   unsigned int values_count)
23278c2ecf20Sopenharmony_ci{
23288c2ecf20Sopenharmony_ci	struct nlattr *action_attr;
23298c2ecf20Sopenharmony_ci	int i;
23308c2ecf20Sopenharmony_ci	int err;
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_ci	for (i = 0; i < values_count; i++) {
23338c2ecf20Sopenharmony_ci		action_attr = nla_nest_start_noflag(skb,
23348c2ecf20Sopenharmony_ci						    DEVLINK_ATTR_DPIPE_ACTION_VALUE);
23358c2ecf20Sopenharmony_ci		if (!action_attr)
23368c2ecf20Sopenharmony_ci			return -EMSGSIZE;
23378c2ecf20Sopenharmony_ci		err = devlink_dpipe_action_value_put(skb, &values[i]);
23388c2ecf20Sopenharmony_ci		if (err)
23398c2ecf20Sopenharmony_ci			goto err_action_value_put;
23408c2ecf20Sopenharmony_ci		nla_nest_end(skb, action_attr);
23418c2ecf20Sopenharmony_ci	}
23428c2ecf20Sopenharmony_ci	return 0;
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_cierr_action_value_put:
23458c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, action_attr);
23468c2ecf20Sopenharmony_ci	return err;
23478c2ecf20Sopenharmony_ci}
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_cistatic int devlink_dpipe_match_value_put(struct sk_buff *skb,
23508c2ecf20Sopenharmony_ci					 struct devlink_dpipe_value *value)
23518c2ecf20Sopenharmony_ci{
23528c2ecf20Sopenharmony_ci	if (!value->match)
23538c2ecf20Sopenharmony_ci		return -EINVAL;
23548c2ecf20Sopenharmony_ci	if (devlink_dpipe_match_put(skb, value->match))
23558c2ecf20Sopenharmony_ci		return -EMSGSIZE;
23568c2ecf20Sopenharmony_ci	if (devlink_dpipe_value_put(skb, value))
23578c2ecf20Sopenharmony_ci		return -EMSGSIZE;
23588c2ecf20Sopenharmony_ci	return 0;
23598c2ecf20Sopenharmony_ci}
23608c2ecf20Sopenharmony_ci
23618c2ecf20Sopenharmony_cistatic int devlink_dpipe_match_values_put(struct sk_buff *skb,
23628c2ecf20Sopenharmony_ci					  struct devlink_dpipe_value *values,
23638c2ecf20Sopenharmony_ci					  unsigned int values_count)
23648c2ecf20Sopenharmony_ci{
23658c2ecf20Sopenharmony_ci	struct nlattr *match_attr;
23668c2ecf20Sopenharmony_ci	int i;
23678c2ecf20Sopenharmony_ci	int err;
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci	for (i = 0; i < values_count; i++) {
23708c2ecf20Sopenharmony_ci		match_attr = nla_nest_start_noflag(skb,
23718c2ecf20Sopenharmony_ci						   DEVLINK_ATTR_DPIPE_MATCH_VALUE);
23728c2ecf20Sopenharmony_ci		if (!match_attr)
23738c2ecf20Sopenharmony_ci			return -EMSGSIZE;
23748c2ecf20Sopenharmony_ci		err = devlink_dpipe_match_value_put(skb, &values[i]);
23758c2ecf20Sopenharmony_ci		if (err)
23768c2ecf20Sopenharmony_ci			goto err_match_value_put;
23778c2ecf20Sopenharmony_ci		nla_nest_end(skb, match_attr);
23788c2ecf20Sopenharmony_ci	}
23798c2ecf20Sopenharmony_ci	return 0;
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_cierr_match_value_put:
23828c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, match_attr);
23838c2ecf20Sopenharmony_ci	return err;
23848c2ecf20Sopenharmony_ci}
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_cistatic int devlink_dpipe_entry_put(struct sk_buff *skb,
23878c2ecf20Sopenharmony_ci				   struct devlink_dpipe_entry *entry)
23888c2ecf20Sopenharmony_ci{
23898c2ecf20Sopenharmony_ci	struct nlattr *entry_attr, *matches_attr, *actions_attr;
23908c2ecf20Sopenharmony_ci	int err;
23918c2ecf20Sopenharmony_ci
23928c2ecf20Sopenharmony_ci	entry_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ENTRY);
23938c2ecf20Sopenharmony_ci	if (!entry_attr)
23948c2ecf20Sopenharmony_ci		return  -EMSGSIZE;
23958c2ecf20Sopenharmony_ci
23968c2ecf20Sopenharmony_ci	if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index,
23978c2ecf20Sopenharmony_ci			      DEVLINK_ATTR_PAD))
23988c2ecf20Sopenharmony_ci		goto nla_put_failure;
23998c2ecf20Sopenharmony_ci	if (entry->counter_valid)
24008c2ecf20Sopenharmony_ci		if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
24018c2ecf20Sopenharmony_ci				      entry->counter, DEVLINK_ATTR_PAD))
24028c2ecf20Sopenharmony_ci			goto nla_put_failure;
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci	matches_attr = nla_nest_start_noflag(skb,
24058c2ecf20Sopenharmony_ci					     DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
24068c2ecf20Sopenharmony_ci	if (!matches_attr)
24078c2ecf20Sopenharmony_ci		goto nla_put_failure;
24088c2ecf20Sopenharmony_ci
24098c2ecf20Sopenharmony_ci	err = devlink_dpipe_match_values_put(skb, entry->match_values,
24108c2ecf20Sopenharmony_ci					     entry->match_values_count);
24118c2ecf20Sopenharmony_ci	if (err) {
24128c2ecf20Sopenharmony_ci		nla_nest_cancel(skb, matches_attr);
24138c2ecf20Sopenharmony_ci		goto err_match_values_put;
24148c2ecf20Sopenharmony_ci	}
24158c2ecf20Sopenharmony_ci	nla_nest_end(skb, matches_attr);
24168c2ecf20Sopenharmony_ci
24178c2ecf20Sopenharmony_ci	actions_attr = nla_nest_start_noflag(skb,
24188c2ecf20Sopenharmony_ci					     DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
24198c2ecf20Sopenharmony_ci	if (!actions_attr)
24208c2ecf20Sopenharmony_ci		goto nla_put_failure;
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_ci	err = devlink_dpipe_action_values_put(skb, entry->action_values,
24238c2ecf20Sopenharmony_ci					      entry->action_values_count);
24248c2ecf20Sopenharmony_ci	if (err) {
24258c2ecf20Sopenharmony_ci		nla_nest_cancel(skb, actions_attr);
24268c2ecf20Sopenharmony_ci		goto err_action_values_put;
24278c2ecf20Sopenharmony_ci	}
24288c2ecf20Sopenharmony_ci	nla_nest_end(skb, actions_attr);
24298c2ecf20Sopenharmony_ci
24308c2ecf20Sopenharmony_ci	nla_nest_end(skb, entry_attr);
24318c2ecf20Sopenharmony_ci	return 0;
24328c2ecf20Sopenharmony_ci
24338c2ecf20Sopenharmony_cinla_put_failure:
24348c2ecf20Sopenharmony_ci	err = -EMSGSIZE;
24358c2ecf20Sopenharmony_cierr_match_values_put:
24368c2ecf20Sopenharmony_cierr_action_values_put:
24378c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, entry_attr);
24388c2ecf20Sopenharmony_ci	return err;
24398c2ecf20Sopenharmony_ci}
24408c2ecf20Sopenharmony_ci
24418c2ecf20Sopenharmony_cistatic struct devlink_dpipe_table *
24428c2ecf20Sopenharmony_cidevlink_dpipe_table_find(struct list_head *dpipe_tables,
24438c2ecf20Sopenharmony_ci			 const char *table_name, struct devlink *devlink)
24448c2ecf20Sopenharmony_ci{
24458c2ecf20Sopenharmony_ci	struct devlink_dpipe_table *table;
24468c2ecf20Sopenharmony_ci	list_for_each_entry_rcu(table, dpipe_tables, list,
24478c2ecf20Sopenharmony_ci				lockdep_is_held(&devlink->lock)) {
24488c2ecf20Sopenharmony_ci		if (!strcmp(table->name, table_name))
24498c2ecf20Sopenharmony_ci			return table;
24508c2ecf20Sopenharmony_ci	}
24518c2ecf20Sopenharmony_ci	return NULL;
24528c2ecf20Sopenharmony_ci}
24538c2ecf20Sopenharmony_ci
24548c2ecf20Sopenharmony_ciint devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
24558c2ecf20Sopenharmony_ci{
24568c2ecf20Sopenharmony_ci	struct devlink *devlink;
24578c2ecf20Sopenharmony_ci	int err;
24588c2ecf20Sopenharmony_ci
24598c2ecf20Sopenharmony_ci	err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
24608c2ecf20Sopenharmony_ci					       dump_ctx->info);
24618c2ecf20Sopenharmony_ci	if (err)
24628c2ecf20Sopenharmony_ci		return err;
24638c2ecf20Sopenharmony_ci
24648c2ecf20Sopenharmony_ci	dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
24658c2ecf20Sopenharmony_ci				    dump_ctx->info->snd_portid,
24668c2ecf20Sopenharmony_ci				    dump_ctx->info->snd_seq,
24678c2ecf20Sopenharmony_ci				    &devlink_nl_family, NLM_F_MULTI,
24688c2ecf20Sopenharmony_ci				    dump_ctx->cmd);
24698c2ecf20Sopenharmony_ci	if (!dump_ctx->hdr)
24708c2ecf20Sopenharmony_ci		goto nla_put_failure;
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_ci	devlink = dump_ctx->info->user_ptr[0];
24738c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(dump_ctx->skb, devlink))
24748c2ecf20Sopenharmony_ci		goto nla_put_failure;
24758c2ecf20Sopenharmony_ci	dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb,
24768c2ecf20Sopenharmony_ci					       DEVLINK_ATTR_DPIPE_ENTRIES);
24778c2ecf20Sopenharmony_ci	if (!dump_ctx->nest)
24788c2ecf20Sopenharmony_ci		goto nla_put_failure;
24798c2ecf20Sopenharmony_ci	return 0;
24808c2ecf20Sopenharmony_ci
24818c2ecf20Sopenharmony_cinla_put_failure:
24828c2ecf20Sopenharmony_ci	nlmsg_free(dump_ctx->skb);
24838c2ecf20Sopenharmony_ci	return -EMSGSIZE;
24848c2ecf20Sopenharmony_ci}
24858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_ciint devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
24888c2ecf20Sopenharmony_ci				   struct devlink_dpipe_entry *entry)
24898c2ecf20Sopenharmony_ci{
24908c2ecf20Sopenharmony_ci	return devlink_dpipe_entry_put(dump_ctx->skb, entry);
24918c2ecf20Sopenharmony_ci}
24928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ciint devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
24958c2ecf20Sopenharmony_ci{
24968c2ecf20Sopenharmony_ci	nla_nest_end(dump_ctx->skb, dump_ctx->nest);
24978c2ecf20Sopenharmony_ci	genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
24988c2ecf20Sopenharmony_ci	return 0;
24998c2ecf20Sopenharmony_ci}
25008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
25018c2ecf20Sopenharmony_ci
25028c2ecf20Sopenharmony_civoid devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
25038c2ecf20Sopenharmony_ci
25048c2ecf20Sopenharmony_ci{
25058c2ecf20Sopenharmony_ci	unsigned int value_count, value_index;
25068c2ecf20Sopenharmony_ci	struct devlink_dpipe_value *value;
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_ci	value = entry->action_values;
25098c2ecf20Sopenharmony_ci	value_count = entry->action_values_count;
25108c2ecf20Sopenharmony_ci	for (value_index = 0; value_index < value_count; value_index++) {
25118c2ecf20Sopenharmony_ci		kfree(value[value_index].value);
25128c2ecf20Sopenharmony_ci		kfree(value[value_index].mask);
25138c2ecf20Sopenharmony_ci	}
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci	value = entry->match_values;
25168c2ecf20Sopenharmony_ci	value_count = entry->match_values_count;
25178c2ecf20Sopenharmony_ci	for (value_index = 0; value_index < value_count; value_index++) {
25188c2ecf20Sopenharmony_ci		kfree(value[value_index].value);
25198c2ecf20Sopenharmony_ci		kfree(value[value_index].mask);
25208c2ecf20Sopenharmony_ci	}
25218c2ecf20Sopenharmony_ci}
25228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(devlink_dpipe_entry_clear);
25238c2ecf20Sopenharmony_ci
25248c2ecf20Sopenharmony_cistatic int devlink_dpipe_entries_fill(struct genl_info *info,
25258c2ecf20Sopenharmony_ci				      enum devlink_command cmd, int flags,
25268c2ecf20Sopenharmony_ci				      struct devlink_dpipe_table *table)
25278c2ecf20Sopenharmony_ci{
25288c2ecf20Sopenharmony_ci	struct devlink_dpipe_dump_ctx dump_ctx;
25298c2ecf20Sopenharmony_ci	struct nlmsghdr *nlh;
25308c2ecf20Sopenharmony_ci	int err;
25318c2ecf20Sopenharmony_ci
25328c2ecf20Sopenharmony_ci	dump_ctx.skb = NULL;
25338c2ecf20Sopenharmony_ci	dump_ctx.cmd = cmd;
25348c2ecf20Sopenharmony_ci	dump_ctx.info = info;
25358c2ecf20Sopenharmony_ci
25368c2ecf20Sopenharmony_ci	err = table->table_ops->entries_dump(table->priv,
25378c2ecf20Sopenharmony_ci					     table->counters_enabled,
25388c2ecf20Sopenharmony_ci					     &dump_ctx);
25398c2ecf20Sopenharmony_ci	if (err)
25408c2ecf20Sopenharmony_ci		return err;
25418c2ecf20Sopenharmony_ci
25428c2ecf20Sopenharmony_cisend_done:
25438c2ecf20Sopenharmony_ci	nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
25448c2ecf20Sopenharmony_ci			NLMSG_DONE, 0, flags | NLM_F_MULTI);
25458c2ecf20Sopenharmony_ci	if (!nlh) {
25468c2ecf20Sopenharmony_ci		err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
25478c2ecf20Sopenharmony_ci		if (err)
25488c2ecf20Sopenharmony_ci			return err;
25498c2ecf20Sopenharmony_ci		goto send_done;
25508c2ecf20Sopenharmony_ci	}
25518c2ecf20Sopenharmony_ci	return genlmsg_reply(dump_ctx.skb, info);
25528c2ecf20Sopenharmony_ci}
25538c2ecf20Sopenharmony_ci
25548c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
25558c2ecf20Sopenharmony_ci					    struct genl_info *info)
25568c2ecf20Sopenharmony_ci{
25578c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
25588c2ecf20Sopenharmony_ci	struct devlink_dpipe_table *table;
25598c2ecf20Sopenharmony_ci	const char *table_name;
25608c2ecf20Sopenharmony_ci
25618c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
25628c2ecf20Sopenharmony_ci		return -EINVAL;
25638c2ecf20Sopenharmony_ci
25648c2ecf20Sopenharmony_ci	table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
25658c2ecf20Sopenharmony_ci	table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
25668c2ecf20Sopenharmony_ci					 table_name, devlink);
25678c2ecf20Sopenharmony_ci	if (!table)
25688c2ecf20Sopenharmony_ci		return -EINVAL;
25698c2ecf20Sopenharmony_ci
25708c2ecf20Sopenharmony_ci	if (!table->table_ops->entries_dump)
25718c2ecf20Sopenharmony_ci		return -EINVAL;
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci	return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
25748c2ecf20Sopenharmony_ci					  0, table);
25758c2ecf20Sopenharmony_ci}
25768c2ecf20Sopenharmony_ci
25778c2ecf20Sopenharmony_cistatic int devlink_dpipe_fields_put(struct sk_buff *skb,
25788c2ecf20Sopenharmony_ci				    const struct devlink_dpipe_header *header)
25798c2ecf20Sopenharmony_ci{
25808c2ecf20Sopenharmony_ci	struct devlink_dpipe_field *field;
25818c2ecf20Sopenharmony_ci	struct nlattr *field_attr;
25828c2ecf20Sopenharmony_ci	int i;
25838c2ecf20Sopenharmony_ci
25848c2ecf20Sopenharmony_ci	for (i = 0; i < header->fields_count; i++) {
25858c2ecf20Sopenharmony_ci		field = &header->fields[i];
25868c2ecf20Sopenharmony_ci		field_attr = nla_nest_start_noflag(skb,
25878c2ecf20Sopenharmony_ci						   DEVLINK_ATTR_DPIPE_FIELD);
25888c2ecf20Sopenharmony_ci		if (!field_attr)
25898c2ecf20Sopenharmony_ci			return -EMSGSIZE;
25908c2ecf20Sopenharmony_ci		if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
25918c2ecf20Sopenharmony_ci		    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
25928c2ecf20Sopenharmony_ci		    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
25938c2ecf20Sopenharmony_ci		    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
25948c2ecf20Sopenharmony_ci			goto nla_put_failure;
25958c2ecf20Sopenharmony_ci		nla_nest_end(skb, field_attr);
25968c2ecf20Sopenharmony_ci	}
25978c2ecf20Sopenharmony_ci	return 0;
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_cinla_put_failure:
26008c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, field_attr);
26018c2ecf20Sopenharmony_ci	return -EMSGSIZE;
26028c2ecf20Sopenharmony_ci}
26038c2ecf20Sopenharmony_ci
26048c2ecf20Sopenharmony_cistatic int devlink_dpipe_header_put(struct sk_buff *skb,
26058c2ecf20Sopenharmony_ci				    struct devlink_dpipe_header *header)
26068c2ecf20Sopenharmony_ci{
26078c2ecf20Sopenharmony_ci	struct nlattr *fields_attr, *header_attr;
26088c2ecf20Sopenharmony_ci	int err;
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ci	header_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADER);
26118c2ecf20Sopenharmony_ci	if (!header_attr)
26128c2ecf20Sopenharmony_ci		return -EMSGSIZE;
26138c2ecf20Sopenharmony_ci
26148c2ecf20Sopenharmony_ci	if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
26158c2ecf20Sopenharmony_ci	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
26168c2ecf20Sopenharmony_ci	    nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
26178c2ecf20Sopenharmony_ci		goto nla_put_failure;
26188c2ecf20Sopenharmony_ci
26198c2ecf20Sopenharmony_ci	fields_attr = nla_nest_start_noflag(skb,
26208c2ecf20Sopenharmony_ci					    DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
26218c2ecf20Sopenharmony_ci	if (!fields_attr)
26228c2ecf20Sopenharmony_ci		goto nla_put_failure;
26238c2ecf20Sopenharmony_ci
26248c2ecf20Sopenharmony_ci	err = devlink_dpipe_fields_put(skb, header);
26258c2ecf20Sopenharmony_ci	if (err) {
26268c2ecf20Sopenharmony_ci		nla_nest_cancel(skb, fields_attr);
26278c2ecf20Sopenharmony_ci		goto nla_put_failure;
26288c2ecf20Sopenharmony_ci	}
26298c2ecf20Sopenharmony_ci	nla_nest_end(skb, fields_attr);
26308c2ecf20Sopenharmony_ci	nla_nest_end(skb, header_attr);
26318c2ecf20Sopenharmony_ci	return 0;
26328c2ecf20Sopenharmony_ci
26338c2ecf20Sopenharmony_cinla_put_failure:
26348c2ecf20Sopenharmony_ci	err = -EMSGSIZE;
26358c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, header_attr);
26368c2ecf20Sopenharmony_ci	return err;
26378c2ecf20Sopenharmony_ci}
26388c2ecf20Sopenharmony_ci
26398c2ecf20Sopenharmony_cistatic int devlink_dpipe_headers_fill(struct genl_info *info,
26408c2ecf20Sopenharmony_ci				      enum devlink_command cmd, int flags,
26418c2ecf20Sopenharmony_ci				      struct devlink_dpipe_headers *
26428c2ecf20Sopenharmony_ci				      dpipe_headers)
26438c2ecf20Sopenharmony_ci{
26448c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
26458c2ecf20Sopenharmony_ci	struct nlattr *headers_attr;
26468c2ecf20Sopenharmony_ci	struct sk_buff *skb = NULL;
26478c2ecf20Sopenharmony_ci	struct nlmsghdr *nlh;
26488c2ecf20Sopenharmony_ci	void *hdr;
26498c2ecf20Sopenharmony_ci	int i, j;
26508c2ecf20Sopenharmony_ci	int err;
26518c2ecf20Sopenharmony_ci
26528c2ecf20Sopenharmony_ci	i = 0;
26538c2ecf20Sopenharmony_cistart_again:
26548c2ecf20Sopenharmony_ci	err = devlink_dpipe_send_and_alloc_skb(&skb, info);
26558c2ecf20Sopenharmony_ci	if (err)
26568c2ecf20Sopenharmony_ci		return err;
26578c2ecf20Sopenharmony_ci
26588c2ecf20Sopenharmony_ci	hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
26598c2ecf20Sopenharmony_ci			  &devlink_nl_family, NLM_F_MULTI, cmd);
26608c2ecf20Sopenharmony_ci	if (!hdr) {
26618c2ecf20Sopenharmony_ci		nlmsg_free(skb);
26628c2ecf20Sopenharmony_ci		return -EMSGSIZE;
26638c2ecf20Sopenharmony_ci	}
26648c2ecf20Sopenharmony_ci
26658c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(skb, devlink))
26668c2ecf20Sopenharmony_ci		goto nla_put_failure;
26678c2ecf20Sopenharmony_ci	headers_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADERS);
26688c2ecf20Sopenharmony_ci	if (!headers_attr)
26698c2ecf20Sopenharmony_ci		goto nla_put_failure;
26708c2ecf20Sopenharmony_ci
26718c2ecf20Sopenharmony_ci	j = 0;
26728c2ecf20Sopenharmony_ci	for (; i < dpipe_headers->headers_count; i++) {
26738c2ecf20Sopenharmony_ci		err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
26748c2ecf20Sopenharmony_ci		if (err) {
26758c2ecf20Sopenharmony_ci			if (!j)
26768c2ecf20Sopenharmony_ci				goto err_table_put;
26778c2ecf20Sopenharmony_ci			break;
26788c2ecf20Sopenharmony_ci		}
26798c2ecf20Sopenharmony_ci		j++;
26808c2ecf20Sopenharmony_ci	}
26818c2ecf20Sopenharmony_ci	nla_nest_end(skb, headers_attr);
26828c2ecf20Sopenharmony_ci	genlmsg_end(skb, hdr);
26838c2ecf20Sopenharmony_ci	if (i != dpipe_headers->headers_count)
26848c2ecf20Sopenharmony_ci		goto start_again;
26858c2ecf20Sopenharmony_ci
26868c2ecf20Sopenharmony_cisend_done:
26878c2ecf20Sopenharmony_ci	nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
26888c2ecf20Sopenharmony_ci			NLMSG_DONE, 0, flags | NLM_F_MULTI);
26898c2ecf20Sopenharmony_ci	if (!nlh) {
26908c2ecf20Sopenharmony_ci		err = devlink_dpipe_send_and_alloc_skb(&skb, info);
26918c2ecf20Sopenharmony_ci		if (err)
26928c2ecf20Sopenharmony_ci			return err;
26938c2ecf20Sopenharmony_ci		goto send_done;
26948c2ecf20Sopenharmony_ci	}
26958c2ecf20Sopenharmony_ci	return genlmsg_reply(skb, info);
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_cinla_put_failure:
26988c2ecf20Sopenharmony_ci	err = -EMSGSIZE;
26998c2ecf20Sopenharmony_cierr_table_put:
27008c2ecf20Sopenharmony_ci	nlmsg_free(skb);
27018c2ecf20Sopenharmony_ci	return err;
27028c2ecf20Sopenharmony_ci}
27038c2ecf20Sopenharmony_ci
27048c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb,
27058c2ecf20Sopenharmony_ci					    struct genl_info *info)
27068c2ecf20Sopenharmony_ci{
27078c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
27088c2ecf20Sopenharmony_ci
27098c2ecf20Sopenharmony_ci	if (!devlink->dpipe_headers)
27108c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
27118c2ecf20Sopenharmony_ci	return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
27128c2ecf20Sopenharmony_ci					  0, devlink->dpipe_headers);
27138c2ecf20Sopenharmony_ci}
27148c2ecf20Sopenharmony_ci
27158c2ecf20Sopenharmony_cistatic int devlink_dpipe_table_counters_set(struct devlink *devlink,
27168c2ecf20Sopenharmony_ci					    const char *table_name,
27178c2ecf20Sopenharmony_ci					    bool enable)
27188c2ecf20Sopenharmony_ci{
27198c2ecf20Sopenharmony_ci	struct devlink_dpipe_table *table;
27208c2ecf20Sopenharmony_ci
27218c2ecf20Sopenharmony_ci	table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
27228c2ecf20Sopenharmony_ci					 table_name, devlink);
27238c2ecf20Sopenharmony_ci	if (!table)
27248c2ecf20Sopenharmony_ci		return -EINVAL;
27258c2ecf20Sopenharmony_ci
27268c2ecf20Sopenharmony_ci	if (table->counter_control_extern)
27278c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
27288c2ecf20Sopenharmony_ci
27298c2ecf20Sopenharmony_ci	if (!(table->counters_enabled ^ enable))
27308c2ecf20Sopenharmony_ci		return 0;
27318c2ecf20Sopenharmony_ci
27328c2ecf20Sopenharmony_ci	table->counters_enabled = enable;
27338c2ecf20Sopenharmony_ci	if (table->table_ops->counters_set_update)
27348c2ecf20Sopenharmony_ci		table->table_ops->counters_set_update(table->priv, enable);
27358c2ecf20Sopenharmony_ci	return 0;
27368c2ecf20Sopenharmony_ci}
27378c2ecf20Sopenharmony_ci
27388c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb,
27398c2ecf20Sopenharmony_ci						   struct genl_info *info)
27408c2ecf20Sopenharmony_ci{
27418c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
27428c2ecf20Sopenharmony_ci	const char *table_name;
27438c2ecf20Sopenharmony_ci	bool counters_enable;
27448c2ecf20Sopenharmony_ci
27458c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
27468c2ecf20Sopenharmony_ci	    !info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED])
27478c2ecf20Sopenharmony_ci		return -EINVAL;
27488c2ecf20Sopenharmony_ci
27498c2ecf20Sopenharmony_ci	table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
27508c2ecf20Sopenharmony_ci	counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
27518c2ecf20Sopenharmony_ci
27528c2ecf20Sopenharmony_ci	return devlink_dpipe_table_counters_set(devlink, table_name,
27538c2ecf20Sopenharmony_ci						counters_enable);
27548c2ecf20Sopenharmony_ci}
27558c2ecf20Sopenharmony_ci
27568c2ecf20Sopenharmony_cistatic struct devlink_resource *
27578c2ecf20Sopenharmony_cidevlink_resource_find(struct devlink *devlink,
27588c2ecf20Sopenharmony_ci		      struct devlink_resource *resource, u64 resource_id)
27598c2ecf20Sopenharmony_ci{
27608c2ecf20Sopenharmony_ci	struct list_head *resource_list;
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_ci	if (resource)
27638c2ecf20Sopenharmony_ci		resource_list = &resource->resource_list;
27648c2ecf20Sopenharmony_ci	else
27658c2ecf20Sopenharmony_ci		resource_list = &devlink->resource_list;
27668c2ecf20Sopenharmony_ci
27678c2ecf20Sopenharmony_ci	list_for_each_entry(resource, resource_list, list) {
27688c2ecf20Sopenharmony_ci		struct devlink_resource *child_resource;
27698c2ecf20Sopenharmony_ci
27708c2ecf20Sopenharmony_ci		if (resource->id == resource_id)
27718c2ecf20Sopenharmony_ci			return resource;
27728c2ecf20Sopenharmony_ci
27738c2ecf20Sopenharmony_ci		child_resource = devlink_resource_find(devlink, resource,
27748c2ecf20Sopenharmony_ci						       resource_id);
27758c2ecf20Sopenharmony_ci		if (child_resource)
27768c2ecf20Sopenharmony_ci			return child_resource;
27778c2ecf20Sopenharmony_ci	}
27788c2ecf20Sopenharmony_ci	return NULL;
27798c2ecf20Sopenharmony_ci}
27808c2ecf20Sopenharmony_ci
27818c2ecf20Sopenharmony_cistatic void
27828c2ecf20Sopenharmony_cidevlink_resource_validate_children(struct devlink_resource *resource)
27838c2ecf20Sopenharmony_ci{
27848c2ecf20Sopenharmony_ci	struct devlink_resource *child_resource;
27858c2ecf20Sopenharmony_ci	bool size_valid = true;
27868c2ecf20Sopenharmony_ci	u64 parts_size = 0;
27878c2ecf20Sopenharmony_ci
27888c2ecf20Sopenharmony_ci	if (list_empty(&resource->resource_list))
27898c2ecf20Sopenharmony_ci		goto out;
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	list_for_each_entry(child_resource, &resource->resource_list, list)
27928c2ecf20Sopenharmony_ci		parts_size += child_resource->size_new;
27938c2ecf20Sopenharmony_ci
27948c2ecf20Sopenharmony_ci	if (parts_size > resource->size_new)
27958c2ecf20Sopenharmony_ci		size_valid = false;
27968c2ecf20Sopenharmony_ciout:
27978c2ecf20Sopenharmony_ci	resource->size_valid = size_valid;
27988c2ecf20Sopenharmony_ci}
27998c2ecf20Sopenharmony_ci
28008c2ecf20Sopenharmony_cistatic int
28018c2ecf20Sopenharmony_cidevlink_resource_validate_size(struct devlink_resource *resource, u64 size,
28028c2ecf20Sopenharmony_ci			       struct netlink_ext_ack *extack)
28038c2ecf20Sopenharmony_ci{
28048c2ecf20Sopenharmony_ci	u64 reminder;
28058c2ecf20Sopenharmony_ci	int err = 0;
28068c2ecf20Sopenharmony_ci
28078c2ecf20Sopenharmony_ci	if (size > resource->size_params.size_max) {
28088c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Size larger than maximum");
28098c2ecf20Sopenharmony_ci		err = -EINVAL;
28108c2ecf20Sopenharmony_ci	}
28118c2ecf20Sopenharmony_ci
28128c2ecf20Sopenharmony_ci	if (size < resource->size_params.size_min) {
28138c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Size smaller than minimum");
28148c2ecf20Sopenharmony_ci		err = -EINVAL;
28158c2ecf20Sopenharmony_ci	}
28168c2ecf20Sopenharmony_ci
28178c2ecf20Sopenharmony_ci	div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
28188c2ecf20Sopenharmony_ci	if (reminder) {
28198c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Wrong granularity");
28208c2ecf20Sopenharmony_ci		err = -EINVAL;
28218c2ecf20Sopenharmony_ci	}
28228c2ecf20Sopenharmony_ci
28238c2ecf20Sopenharmony_ci	return err;
28248c2ecf20Sopenharmony_ci}
28258c2ecf20Sopenharmony_ci
28268c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_resource_set(struct sk_buff *skb,
28278c2ecf20Sopenharmony_ci				       struct genl_info *info)
28288c2ecf20Sopenharmony_ci{
28298c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
28308c2ecf20Sopenharmony_ci	struct devlink_resource *resource;
28318c2ecf20Sopenharmony_ci	u64 resource_id;
28328c2ecf20Sopenharmony_ci	u64 size;
28338c2ecf20Sopenharmony_ci	int err;
28348c2ecf20Sopenharmony_ci
28358c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_RESOURCE_ID] ||
28368c2ecf20Sopenharmony_ci	    !info->attrs[DEVLINK_ATTR_RESOURCE_SIZE])
28378c2ecf20Sopenharmony_ci		return -EINVAL;
28388c2ecf20Sopenharmony_ci	resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
28398c2ecf20Sopenharmony_ci
28408c2ecf20Sopenharmony_ci	resource = devlink_resource_find(devlink, NULL, resource_id);
28418c2ecf20Sopenharmony_ci	if (!resource)
28428c2ecf20Sopenharmony_ci		return -EINVAL;
28438c2ecf20Sopenharmony_ci
28448c2ecf20Sopenharmony_ci	size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
28458c2ecf20Sopenharmony_ci	err = devlink_resource_validate_size(resource, size, info->extack);
28468c2ecf20Sopenharmony_ci	if (err)
28478c2ecf20Sopenharmony_ci		return err;
28488c2ecf20Sopenharmony_ci
28498c2ecf20Sopenharmony_ci	resource->size_new = size;
28508c2ecf20Sopenharmony_ci	devlink_resource_validate_children(resource);
28518c2ecf20Sopenharmony_ci	if (resource->parent)
28528c2ecf20Sopenharmony_ci		devlink_resource_validate_children(resource->parent);
28538c2ecf20Sopenharmony_ci	return 0;
28548c2ecf20Sopenharmony_ci}
28558c2ecf20Sopenharmony_ci
28568c2ecf20Sopenharmony_cistatic int
28578c2ecf20Sopenharmony_cidevlink_resource_size_params_put(struct devlink_resource *resource,
28588c2ecf20Sopenharmony_ci				 struct sk_buff *skb)
28598c2ecf20Sopenharmony_ci{
28608c2ecf20Sopenharmony_ci	struct devlink_resource_size_params *size_params;
28618c2ecf20Sopenharmony_ci
28628c2ecf20Sopenharmony_ci	size_params = &resource->size_params;
28638c2ecf20Sopenharmony_ci	if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
28648c2ecf20Sopenharmony_ci			      size_params->size_granularity, DEVLINK_ATTR_PAD) ||
28658c2ecf20Sopenharmony_ci	    nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
28668c2ecf20Sopenharmony_ci			      size_params->size_max, DEVLINK_ATTR_PAD) ||
28678c2ecf20Sopenharmony_ci	    nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
28688c2ecf20Sopenharmony_ci			      size_params->size_min, DEVLINK_ATTR_PAD) ||
28698c2ecf20Sopenharmony_ci	    nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
28708c2ecf20Sopenharmony_ci		return -EMSGSIZE;
28718c2ecf20Sopenharmony_ci	return 0;
28728c2ecf20Sopenharmony_ci}
28738c2ecf20Sopenharmony_ci
28748c2ecf20Sopenharmony_cistatic int devlink_resource_occ_put(struct devlink_resource *resource,
28758c2ecf20Sopenharmony_ci				    struct sk_buff *skb)
28768c2ecf20Sopenharmony_ci{
28778c2ecf20Sopenharmony_ci	if (!resource->occ_get)
28788c2ecf20Sopenharmony_ci		return 0;
28798c2ecf20Sopenharmony_ci	return nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
28808c2ecf20Sopenharmony_ci				 resource->occ_get(resource->occ_get_priv),
28818c2ecf20Sopenharmony_ci				 DEVLINK_ATTR_PAD);
28828c2ecf20Sopenharmony_ci}
28838c2ecf20Sopenharmony_ci
28848c2ecf20Sopenharmony_cistatic int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
28858c2ecf20Sopenharmony_ci				struct devlink_resource *resource)
28868c2ecf20Sopenharmony_ci{
28878c2ecf20Sopenharmony_ci	struct devlink_resource *child_resource;
28888c2ecf20Sopenharmony_ci	struct nlattr *child_resource_attr;
28898c2ecf20Sopenharmony_ci	struct nlattr *resource_attr;
28908c2ecf20Sopenharmony_ci
28918c2ecf20Sopenharmony_ci	resource_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE);
28928c2ecf20Sopenharmony_ci	if (!resource_attr)
28938c2ecf20Sopenharmony_ci		return -EMSGSIZE;
28948c2ecf20Sopenharmony_ci
28958c2ecf20Sopenharmony_ci	if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
28968c2ecf20Sopenharmony_ci	    nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size,
28978c2ecf20Sopenharmony_ci			      DEVLINK_ATTR_PAD) ||
28988c2ecf20Sopenharmony_ci	    nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id,
28998c2ecf20Sopenharmony_ci			      DEVLINK_ATTR_PAD))
29008c2ecf20Sopenharmony_ci		goto nla_put_failure;
29018c2ecf20Sopenharmony_ci	if (resource->size != resource->size_new)
29028c2ecf20Sopenharmony_ci		nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
29038c2ecf20Sopenharmony_ci				  resource->size_new, DEVLINK_ATTR_PAD);
29048c2ecf20Sopenharmony_ci	if (devlink_resource_occ_put(resource, skb))
29058c2ecf20Sopenharmony_ci		goto nla_put_failure;
29068c2ecf20Sopenharmony_ci	if (devlink_resource_size_params_put(resource, skb))
29078c2ecf20Sopenharmony_ci		goto nla_put_failure;
29088c2ecf20Sopenharmony_ci	if (list_empty(&resource->resource_list))
29098c2ecf20Sopenharmony_ci		goto out;
29108c2ecf20Sopenharmony_ci
29118c2ecf20Sopenharmony_ci	if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
29128c2ecf20Sopenharmony_ci		       resource->size_valid))
29138c2ecf20Sopenharmony_ci		goto nla_put_failure;
29148c2ecf20Sopenharmony_ci
29158c2ecf20Sopenharmony_ci	child_resource_attr = nla_nest_start_noflag(skb,
29168c2ecf20Sopenharmony_ci						    DEVLINK_ATTR_RESOURCE_LIST);
29178c2ecf20Sopenharmony_ci	if (!child_resource_attr)
29188c2ecf20Sopenharmony_ci		goto nla_put_failure;
29198c2ecf20Sopenharmony_ci
29208c2ecf20Sopenharmony_ci	list_for_each_entry(child_resource, &resource->resource_list, list) {
29218c2ecf20Sopenharmony_ci		if (devlink_resource_put(devlink, skb, child_resource))
29228c2ecf20Sopenharmony_ci			goto resource_put_failure;
29238c2ecf20Sopenharmony_ci	}
29248c2ecf20Sopenharmony_ci
29258c2ecf20Sopenharmony_ci	nla_nest_end(skb, child_resource_attr);
29268c2ecf20Sopenharmony_ciout:
29278c2ecf20Sopenharmony_ci	nla_nest_end(skb, resource_attr);
29288c2ecf20Sopenharmony_ci	return 0;
29298c2ecf20Sopenharmony_ci
29308c2ecf20Sopenharmony_ciresource_put_failure:
29318c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, child_resource_attr);
29328c2ecf20Sopenharmony_cinla_put_failure:
29338c2ecf20Sopenharmony_ci	nla_nest_cancel(skb, resource_attr);
29348c2ecf20Sopenharmony_ci	return -EMSGSIZE;
29358c2ecf20Sopenharmony_ci}
29368c2ecf20Sopenharmony_ci
29378c2ecf20Sopenharmony_cistatic int devlink_resource_fill(struct genl_info *info,
29388c2ecf20Sopenharmony_ci				 enum devlink_command cmd, int flags)
29398c2ecf20Sopenharmony_ci{
29408c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
29418c2ecf20Sopenharmony_ci	struct devlink_resource *resource;
29428c2ecf20Sopenharmony_ci	struct nlattr *resources_attr;
29438c2ecf20Sopenharmony_ci	struct sk_buff *skb = NULL;
29448c2ecf20Sopenharmony_ci	struct nlmsghdr *nlh;
29458c2ecf20Sopenharmony_ci	bool incomplete;
29468c2ecf20Sopenharmony_ci	void *hdr;
29478c2ecf20Sopenharmony_ci	int i;
29488c2ecf20Sopenharmony_ci	int err;
29498c2ecf20Sopenharmony_ci
29508c2ecf20Sopenharmony_ci	resource = list_first_entry(&devlink->resource_list,
29518c2ecf20Sopenharmony_ci				    struct devlink_resource, list);
29528c2ecf20Sopenharmony_cistart_again:
29538c2ecf20Sopenharmony_ci	err = devlink_dpipe_send_and_alloc_skb(&skb, info);
29548c2ecf20Sopenharmony_ci	if (err)
29558c2ecf20Sopenharmony_ci		return err;
29568c2ecf20Sopenharmony_ci
29578c2ecf20Sopenharmony_ci	hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
29588c2ecf20Sopenharmony_ci			  &devlink_nl_family, NLM_F_MULTI, cmd);
29598c2ecf20Sopenharmony_ci	if (!hdr) {
29608c2ecf20Sopenharmony_ci		nlmsg_free(skb);
29618c2ecf20Sopenharmony_ci		return -EMSGSIZE;
29628c2ecf20Sopenharmony_ci	}
29638c2ecf20Sopenharmony_ci
29648c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(skb, devlink))
29658c2ecf20Sopenharmony_ci		goto nla_put_failure;
29668c2ecf20Sopenharmony_ci
29678c2ecf20Sopenharmony_ci	resources_attr = nla_nest_start_noflag(skb,
29688c2ecf20Sopenharmony_ci					       DEVLINK_ATTR_RESOURCE_LIST);
29698c2ecf20Sopenharmony_ci	if (!resources_attr)
29708c2ecf20Sopenharmony_ci		goto nla_put_failure;
29718c2ecf20Sopenharmony_ci
29728c2ecf20Sopenharmony_ci	incomplete = false;
29738c2ecf20Sopenharmony_ci	i = 0;
29748c2ecf20Sopenharmony_ci	list_for_each_entry_from(resource, &devlink->resource_list, list) {
29758c2ecf20Sopenharmony_ci		err = devlink_resource_put(devlink, skb, resource);
29768c2ecf20Sopenharmony_ci		if (err) {
29778c2ecf20Sopenharmony_ci			if (!i)
29788c2ecf20Sopenharmony_ci				goto err_resource_put;
29798c2ecf20Sopenharmony_ci			incomplete = true;
29808c2ecf20Sopenharmony_ci			break;
29818c2ecf20Sopenharmony_ci		}
29828c2ecf20Sopenharmony_ci		i++;
29838c2ecf20Sopenharmony_ci	}
29848c2ecf20Sopenharmony_ci	nla_nest_end(skb, resources_attr);
29858c2ecf20Sopenharmony_ci	genlmsg_end(skb, hdr);
29868c2ecf20Sopenharmony_ci	if (incomplete)
29878c2ecf20Sopenharmony_ci		goto start_again;
29888c2ecf20Sopenharmony_cisend_done:
29898c2ecf20Sopenharmony_ci	nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
29908c2ecf20Sopenharmony_ci			NLMSG_DONE, 0, flags | NLM_F_MULTI);
29918c2ecf20Sopenharmony_ci	if (!nlh) {
29928c2ecf20Sopenharmony_ci		err = devlink_dpipe_send_and_alloc_skb(&skb, info);
29938c2ecf20Sopenharmony_ci		if (err)
29948c2ecf20Sopenharmony_ci			return err;
29958c2ecf20Sopenharmony_ci		goto send_done;
29968c2ecf20Sopenharmony_ci	}
29978c2ecf20Sopenharmony_ci	return genlmsg_reply(skb, info);
29988c2ecf20Sopenharmony_ci
29998c2ecf20Sopenharmony_cinla_put_failure:
30008c2ecf20Sopenharmony_ci	err = -EMSGSIZE;
30018c2ecf20Sopenharmony_cierr_resource_put:
30028c2ecf20Sopenharmony_ci	nlmsg_free(skb);
30038c2ecf20Sopenharmony_ci	return err;
30048c2ecf20Sopenharmony_ci}
30058c2ecf20Sopenharmony_ci
30068c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_resource_dump(struct sk_buff *skb,
30078c2ecf20Sopenharmony_ci					struct genl_info *info)
30088c2ecf20Sopenharmony_ci{
30098c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
30108c2ecf20Sopenharmony_ci
30118c2ecf20Sopenharmony_ci	if (list_empty(&devlink->resource_list))
30128c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
30138c2ecf20Sopenharmony_ci
30148c2ecf20Sopenharmony_ci	return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
30158c2ecf20Sopenharmony_ci}
30168c2ecf20Sopenharmony_ci
30178c2ecf20Sopenharmony_cistatic int
30188c2ecf20Sopenharmony_cidevlink_resources_validate(struct devlink *devlink,
30198c2ecf20Sopenharmony_ci			   struct devlink_resource *resource,
30208c2ecf20Sopenharmony_ci			   struct genl_info *info)
30218c2ecf20Sopenharmony_ci{
30228c2ecf20Sopenharmony_ci	struct list_head *resource_list;
30238c2ecf20Sopenharmony_ci	int err = 0;
30248c2ecf20Sopenharmony_ci
30258c2ecf20Sopenharmony_ci	if (resource)
30268c2ecf20Sopenharmony_ci		resource_list = &resource->resource_list;
30278c2ecf20Sopenharmony_ci	else
30288c2ecf20Sopenharmony_ci		resource_list = &devlink->resource_list;
30298c2ecf20Sopenharmony_ci
30308c2ecf20Sopenharmony_ci	list_for_each_entry(resource, resource_list, list) {
30318c2ecf20Sopenharmony_ci		if (!resource->size_valid)
30328c2ecf20Sopenharmony_ci			return -EINVAL;
30338c2ecf20Sopenharmony_ci		err = devlink_resources_validate(devlink, resource, info);
30348c2ecf20Sopenharmony_ci		if (err)
30358c2ecf20Sopenharmony_ci			return err;
30368c2ecf20Sopenharmony_ci	}
30378c2ecf20Sopenharmony_ci	return err;
30388c2ecf20Sopenharmony_ci}
30398c2ecf20Sopenharmony_ci
30408c2ecf20Sopenharmony_cistatic struct net *devlink_netns_get(struct sk_buff *skb,
30418c2ecf20Sopenharmony_ci				     struct genl_info *info)
30428c2ecf20Sopenharmony_ci{
30438c2ecf20Sopenharmony_ci	struct nlattr *netns_pid_attr = info->attrs[DEVLINK_ATTR_NETNS_PID];
30448c2ecf20Sopenharmony_ci	struct nlattr *netns_fd_attr = info->attrs[DEVLINK_ATTR_NETNS_FD];
30458c2ecf20Sopenharmony_ci	struct nlattr *netns_id_attr = info->attrs[DEVLINK_ATTR_NETNS_ID];
30468c2ecf20Sopenharmony_ci	struct net *net;
30478c2ecf20Sopenharmony_ci
30488c2ecf20Sopenharmony_ci	if (!!netns_pid_attr + !!netns_fd_attr + !!netns_id_attr > 1) {
30498c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(info->extack, "multiple netns identifying attributes specified");
30508c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
30518c2ecf20Sopenharmony_ci	}
30528c2ecf20Sopenharmony_ci
30538c2ecf20Sopenharmony_ci	if (netns_pid_attr) {
30548c2ecf20Sopenharmony_ci		net = get_net_ns_by_pid(nla_get_u32(netns_pid_attr));
30558c2ecf20Sopenharmony_ci	} else if (netns_fd_attr) {
30568c2ecf20Sopenharmony_ci		net = get_net_ns_by_fd(nla_get_u32(netns_fd_attr));
30578c2ecf20Sopenharmony_ci	} else if (netns_id_attr) {
30588c2ecf20Sopenharmony_ci		net = get_net_ns_by_id(sock_net(skb->sk),
30598c2ecf20Sopenharmony_ci				       nla_get_u32(netns_id_attr));
30608c2ecf20Sopenharmony_ci		if (!net)
30618c2ecf20Sopenharmony_ci			net = ERR_PTR(-EINVAL);
30628c2ecf20Sopenharmony_ci	} else {
30638c2ecf20Sopenharmony_ci		WARN_ON(1);
30648c2ecf20Sopenharmony_ci		net = ERR_PTR(-EINVAL);
30658c2ecf20Sopenharmony_ci	}
30668c2ecf20Sopenharmony_ci	if (IS_ERR(net)) {
30678c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(info->extack, "Unknown network namespace");
30688c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
30698c2ecf20Sopenharmony_ci	}
30708c2ecf20Sopenharmony_ci	if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) {
30718c2ecf20Sopenharmony_ci		put_net(net);
30728c2ecf20Sopenharmony_ci		return ERR_PTR(-EPERM);
30738c2ecf20Sopenharmony_ci	}
30748c2ecf20Sopenharmony_ci	return net;
30758c2ecf20Sopenharmony_ci}
30768c2ecf20Sopenharmony_ci
30778c2ecf20Sopenharmony_cistatic void devlink_param_notify(struct devlink *devlink,
30788c2ecf20Sopenharmony_ci				 unsigned int port_index,
30798c2ecf20Sopenharmony_ci				 struct devlink_param_item *param_item,
30808c2ecf20Sopenharmony_ci				 enum devlink_command cmd);
30818c2ecf20Sopenharmony_ci
30828c2ecf20Sopenharmony_cistatic void devlink_ns_change_notify(struct devlink *devlink,
30838c2ecf20Sopenharmony_ci				     struct net *dest_net, struct net *curr_net,
30848c2ecf20Sopenharmony_ci				     bool new)
30858c2ecf20Sopenharmony_ci{
30868c2ecf20Sopenharmony_ci	struct devlink_param_item *param_item;
30878c2ecf20Sopenharmony_ci	enum devlink_command cmd;
30888c2ecf20Sopenharmony_ci
30898c2ecf20Sopenharmony_ci	/* Userspace needs to be notified about devlink objects
30908c2ecf20Sopenharmony_ci	 * removed from original and entering new network namespace.
30918c2ecf20Sopenharmony_ci	 * The rest of the devlink objects are re-created during
30928c2ecf20Sopenharmony_ci	 * reload process so the notifications are generated separatelly.
30938c2ecf20Sopenharmony_ci	 */
30948c2ecf20Sopenharmony_ci
30958c2ecf20Sopenharmony_ci	if (!dest_net || net_eq(dest_net, curr_net))
30968c2ecf20Sopenharmony_ci		return;
30978c2ecf20Sopenharmony_ci
30988c2ecf20Sopenharmony_ci	if (new)
30998c2ecf20Sopenharmony_ci		devlink_notify(devlink, DEVLINK_CMD_NEW);
31008c2ecf20Sopenharmony_ci
31018c2ecf20Sopenharmony_ci	cmd = new ? DEVLINK_CMD_PARAM_NEW : DEVLINK_CMD_PARAM_DEL;
31028c2ecf20Sopenharmony_ci	list_for_each_entry(param_item, &devlink->param_list, list)
31038c2ecf20Sopenharmony_ci		devlink_param_notify(devlink, 0, param_item, cmd);
31048c2ecf20Sopenharmony_ci
31058c2ecf20Sopenharmony_ci	if (!new)
31068c2ecf20Sopenharmony_ci		devlink_notify(devlink, DEVLINK_CMD_DEL);
31078c2ecf20Sopenharmony_ci}
31088c2ecf20Sopenharmony_ci
31098c2ecf20Sopenharmony_cistatic bool devlink_reload_supported(const struct devlink_ops *ops)
31108c2ecf20Sopenharmony_ci{
31118c2ecf20Sopenharmony_ci	return ops->reload_down && ops->reload_up;
31128c2ecf20Sopenharmony_ci}
31138c2ecf20Sopenharmony_ci
31148c2ecf20Sopenharmony_cistatic void devlink_reload_failed_set(struct devlink *devlink,
31158c2ecf20Sopenharmony_ci				      bool reload_failed)
31168c2ecf20Sopenharmony_ci{
31178c2ecf20Sopenharmony_ci	if (devlink->reload_failed == reload_failed)
31188c2ecf20Sopenharmony_ci		return;
31198c2ecf20Sopenharmony_ci	devlink->reload_failed = reload_failed;
31208c2ecf20Sopenharmony_ci	devlink_notify(devlink, DEVLINK_CMD_NEW);
31218c2ecf20Sopenharmony_ci}
31228c2ecf20Sopenharmony_ci
31238c2ecf20Sopenharmony_cibool devlink_is_reload_failed(const struct devlink *devlink)
31248c2ecf20Sopenharmony_ci{
31258c2ecf20Sopenharmony_ci	return devlink->reload_failed;
31268c2ecf20Sopenharmony_ci}
31278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_is_reload_failed);
31288c2ecf20Sopenharmony_ci
31298c2ecf20Sopenharmony_cistatic void
31308c2ecf20Sopenharmony_ci__devlink_reload_stats_update(struct devlink *devlink, u32 *reload_stats,
31318c2ecf20Sopenharmony_ci			      enum devlink_reload_limit limit, u32 actions_performed)
31328c2ecf20Sopenharmony_ci{
31338c2ecf20Sopenharmony_ci	unsigned long actions = actions_performed;
31348c2ecf20Sopenharmony_ci	int stat_idx;
31358c2ecf20Sopenharmony_ci	int action;
31368c2ecf20Sopenharmony_ci
31378c2ecf20Sopenharmony_ci	for_each_set_bit(action, &actions, __DEVLINK_RELOAD_ACTION_MAX) {
31388c2ecf20Sopenharmony_ci		stat_idx = limit * __DEVLINK_RELOAD_ACTION_MAX + action;
31398c2ecf20Sopenharmony_ci		reload_stats[stat_idx]++;
31408c2ecf20Sopenharmony_ci	}
31418c2ecf20Sopenharmony_ci	devlink_notify(devlink, DEVLINK_CMD_NEW);
31428c2ecf20Sopenharmony_ci}
31438c2ecf20Sopenharmony_ci
31448c2ecf20Sopenharmony_cistatic void
31458c2ecf20Sopenharmony_cidevlink_reload_stats_update(struct devlink *devlink, enum devlink_reload_limit limit,
31468c2ecf20Sopenharmony_ci			    u32 actions_performed)
31478c2ecf20Sopenharmony_ci{
31488c2ecf20Sopenharmony_ci	__devlink_reload_stats_update(devlink, devlink->stats.reload_stats, limit,
31498c2ecf20Sopenharmony_ci				      actions_performed);
31508c2ecf20Sopenharmony_ci}
31518c2ecf20Sopenharmony_ci
31528c2ecf20Sopenharmony_ci/**
31538c2ecf20Sopenharmony_ci *	devlink_remote_reload_actions_performed - Update devlink on reload actions
31548c2ecf20Sopenharmony_ci *	  performed which are not a direct result of devlink reload call.
31558c2ecf20Sopenharmony_ci *
31568c2ecf20Sopenharmony_ci *	This should be called by a driver after performing reload actions in case it was not
31578c2ecf20Sopenharmony_ci *	a result of devlink reload call. For example fw_activate was performed as a result
31588c2ecf20Sopenharmony_ci *	of devlink reload triggered fw_activate on another host.
31598c2ecf20Sopenharmony_ci *	The motivation for this function is to keep data on reload actions performed on this
31608c2ecf20Sopenharmony_ci *	function whether it was done due to direct devlink reload call or not.
31618c2ecf20Sopenharmony_ci *
31628c2ecf20Sopenharmony_ci *	@devlink: devlink
31638c2ecf20Sopenharmony_ci *	@limit: reload limit
31648c2ecf20Sopenharmony_ci *	@actions_performed: bitmask of actions performed
31658c2ecf20Sopenharmony_ci */
31668c2ecf20Sopenharmony_civoid devlink_remote_reload_actions_performed(struct devlink *devlink,
31678c2ecf20Sopenharmony_ci					     enum devlink_reload_limit limit,
31688c2ecf20Sopenharmony_ci					     u32 actions_performed)
31698c2ecf20Sopenharmony_ci{
31708c2ecf20Sopenharmony_ci	if (WARN_ON(!actions_performed ||
31718c2ecf20Sopenharmony_ci		    actions_performed & BIT(DEVLINK_RELOAD_ACTION_UNSPEC) ||
31728c2ecf20Sopenharmony_ci		    actions_performed >= BIT(__DEVLINK_RELOAD_ACTION_MAX) ||
31738c2ecf20Sopenharmony_ci		    limit > DEVLINK_RELOAD_LIMIT_MAX))
31748c2ecf20Sopenharmony_ci		return;
31758c2ecf20Sopenharmony_ci
31768c2ecf20Sopenharmony_ci	__devlink_reload_stats_update(devlink, devlink->stats.remote_reload_stats, limit,
31778c2ecf20Sopenharmony_ci				      actions_performed);
31788c2ecf20Sopenharmony_ci}
31798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_remote_reload_actions_performed);
31808c2ecf20Sopenharmony_ci
31818c2ecf20Sopenharmony_cistatic int devlink_reload(struct devlink *devlink, struct net *dest_net,
31828c2ecf20Sopenharmony_ci			  enum devlink_reload_action action, enum devlink_reload_limit limit,
31838c2ecf20Sopenharmony_ci			  u32 *actions_performed, struct netlink_ext_ack *extack)
31848c2ecf20Sopenharmony_ci{
31858c2ecf20Sopenharmony_ci	u32 remote_reload_stats[DEVLINK_RELOAD_STATS_ARRAY_SIZE];
31868c2ecf20Sopenharmony_ci	struct net *curr_net;
31878c2ecf20Sopenharmony_ci	int err;
31888c2ecf20Sopenharmony_ci
31898c2ecf20Sopenharmony_ci	if (!devlink->reload_enabled)
31908c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
31918c2ecf20Sopenharmony_ci
31928c2ecf20Sopenharmony_ci	memcpy(remote_reload_stats, devlink->stats.remote_reload_stats,
31938c2ecf20Sopenharmony_ci	       sizeof(remote_reload_stats));
31948c2ecf20Sopenharmony_ci
31958c2ecf20Sopenharmony_ci	curr_net = devlink_net(devlink);
31968c2ecf20Sopenharmony_ci	devlink_ns_change_notify(devlink, dest_net, curr_net, false);
31978c2ecf20Sopenharmony_ci	err = devlink->ops->reload_down(devlink, !!dest_net, action, limit, extack);
31988c2ecf20Sopenharmony_ci	if (err)
31998c2ecf20Sopenharmony_ci		return err;
32008c2ecf20Sopenharmony_ci
32018c2ecf20Sopenharmony_ci	if (dest_net && !net_eq(dest_net, curr_net))
32028c2ecf20Sopenharmony_ci		__devlink_net_set(devlink, dest_net);
32038c2ecf20Sopenharmony_ci
32048c2ecf20Sopenharmony_ci	err = devlink->ops->reload_up(devlink, action, limit, actions_performed, extack);
32058c2ecf20Sopenharmony_ci	devlink_reload_failed_set(devlink, !!err);
32068c2ecf20Sopenharmony_ci	if (err)
32078c2ecf20Sopenharmony_ci		return err;
32088c2ecf20Sopenharmony_ci
32098c2ecf20Sopenharmony_ci	devlink_ns_change_notify(devlink, dest_net, curr_net, true);
32108c2ecf20Sopenharmony_ci	WARN_ON(!(*actions_performed & BIT(action)));
32118c2ecf20Sopenharmony_ci	/* Catch driver on updating the remote action within devlink reload */
32128c2ecf20Sopenharmony_ci	WARN_ON(memcmp(remote_reload_stats, devlink->stats.remote_reload_stats,
32138c2ecf20Sopenharmony_ci		       sizeof(remote_reload_stats)));
32148c2ecf20Sopenharmony_ci	devlink_reload_stats_update(devlink, limit, *actions_performed);
32158c2ecf20Sopenharmony_ci	return 0;
32168c2ecf20Sopenharmony_ci}
32178c2ecf20Sopenharmony_ci
32188c2ecf20Sopenharmony_cistatic int
32198c2ecf20Sopenharmony_cidevlink_nl_reload_actions_performed_snd(struct devlink *devlink, u32 actions_performed,
32208c2ecf20Sopenharmony_ci					enum devlink_command cmd, struct genl_info *info)
32218c2ecf20Sopenharmony_ci{
32228c2ecf20Sopenharmony_ci	struct sk_buff *msg;
32238c2ecf20Sopenharmony_ci	void *hdr;
32248c2ecf20Sopenharmony_ci
32258c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
32268c2ecf20Sopenharmony_ci	if (!msg)
32278c2ecf20Sopenharmony_ci		return -ENOMEM;
32288c2ecf20Sopenharmony_ci
32298c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq, &devlink_nl_family, 0, cmd);
32308c2ecf20Sopenharmony_ci	if (!hdr)
32318c2ecf20Sopenharmony_ci		goto free_msg;
32328c2ecf20Sopenharmony_ci
32338c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(msg, devlink))
32348c2ecf20Sopenharmony_ci		goto nla_put_failure;
32358c2ecf20Sopenharmony_ci
32368c2ecf20Sopenharmony_ci	if (nla_put_bitfield32(msg, DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED, actions_performed,
32378c2ecf20Sopenharmony_ci			       actions_performed))
32388c2ecf20Sopenharmony_ci		goto nla_put_failure;
32398c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
32408c2ecf20Sopenharmony_ci
32418c2ecf20Sopenharmony_ci	return genlmsg_reply(msg, info);
32428c2ecf20Sopenharmony_ci
32438c2ecf20Sopenharmony_cinla_put_failure:
32448c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
32458c2ecf20Sopenharmony_cifree_msg:
32468c2ecf20Sopenharmony_ci	nlmsg_free(msg);
32478c2ecf20Sopenharmony_ci	return -EMSGSIZE;
32488c2ecf20Sopenharmony_ci}
32498c2ecf20Sopenharmony_ci
32508c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info)
32518c2ecf20Sopenharmony_ci{
32528c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
32538c2ecf20Sopenharmony_ci	enum devlink_reload_action action;
32548c2ecf20Sopenharmony_ci	enum devlink_reload_limit limit;
32558c2ecf20Sopenharmony_ci	struct net *dest_net = NULL;
32568c2ecf20Sopenharmony_ci	u32 actions_performed;
32578c2ecf20Sopenharmony_ci	int err;
32588c2ecf20Sopenharmony_ci
32598c2ecf20Sopenharmony_ci	if (!devlink_reload_supported(devlink->ops))
32608c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
32618c2ecf20Sopenharmony_ci
32628c2ecf20Sopenharmony_ci	err = devlink_resources_validate(devlink, NULL, info);
32638c2ecf20Sopenharmony_ci	if (err) {
32648c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(info->extack, "resources size validation failed");
32658c2ecf20Sopenharmony_ci		return err;
32668c2ecf20Sopenharmony_ci	}
32678c2ecf20Sopenharmony_ci
32688c2ecf20Sopenharmony_ci	if (info->attrs[DEVLINK_ATTR_RELOAD_ACTION])
32698c2ecf20Sopenharmony_ci		action = nla_get_u8(info->attrs[DEVLINK_ATTR_RELOAD_ACTION]);
32708c2ecf20Sopenharmony_ci	else
32718c2ecf20Sopenharmony_ci		action = DEVLINK_RELOAD_ACTION_DRIVER_REINIT;
32728c2ecf20Sopenharmony_ci
32738c2ecf20Sopenharmony_ci	if (!devlink_reload_action_is_supported(devlink, action)) {
32748c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(info->extack,
32758c2ecf20Sopenharmony_ci				   "Requested reload action is not supported by the driver");
32768c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
32778c2ecf20Sopenharmony_ci	}
32788c2ecf20Sopenharmony_ci
32798c2ecf20Sopenharmony_ci	limit = DEVLINK_RELOAD_LIMIT_UNSPEC;
32808c2ecf20Sopenharmony_ci	if (info->attrs[DEVLINK_ATTR_RELOAD_LIMITS]) {
32818c2ecf20Sopenharmony_ci		struct nla_bitfield32 limits;
32828c2ecf20Sopenharmony_ci		u32 limits_selected;
32838c2ecf20Sopenharmony_ci
32848c2ecf20Sopenharmony_ci		limits = nla_get_bitfield32(info->attrs[DEVLINK_ATTR_RELOAD_LIMITS]);
32858c2ecf20Sopenharmony_ci		limits_selected = limits.value & limits.selector;
32868c2ecf20Sopenharmony_ci		if (!limits_selected) {
32878c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(info->extack, "Invalid limit selected");
32888c2ecf20Sopenharmony_ci			return -EINVAL;
32898c2ecf20Sopenharmony_ci		}
32908c2ecf20Sopenharmony_ci		for (limit = 0 ; limit <= DEVLINK_RELOAD_LIMIT_MAX ; limit++)
32918c2ecf20Sopenharmony_ci			if (limits_selected & BIT(limit))
32928c2ecf20Sopenharmony_ci				break;
32938c2ecf20Sopenharmony_ci		/* UAPI enables multiselection, but currently it is not used */
32948c2ecf20Sopenharmony_ci		if (limits_selected != BIT(limit)) {
32958c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(info->extack,
32968c2ecf20Sopenharmony_ci					   "Multiselection of limit is not supported");
32978c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
32988c2ecf20Sopenharmony_ci		}
32998c2ecf20Sopenharmony_ci		if (!devlink_reload_limit_is_supported(devlink, limit)) {
33008c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(info->extack,
33018c2ecf20Sopenharmony_ci					   "Requested limit is not supported by the driver");
33028c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
33038c2ecf20Sopenharmony_ci		}
33048c2ecf20Sopenharmony_ci		if (devlink_reload_combination_is_invalid(action, limit)) {
33058c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(info->extack,
33068c2ecf20Sopenharmony_ci					   "Requested limit is invalid for this action");
33078c2ecf20Sopenharmony_ci			return -EINVAL;
33088c2ecf20Sopenharmony_ci		}
33098c2ecf20Sopenharmony_ci	}
33108c2ecf20Sopenharmony_ci	if (info->attrs[DEVLINK_ATTR_NETNS_PID] ||
33118c2ecf20Sopenharmony_ci	    info->attrs[DEVLINK_ATTR_NETNS_FD] ||
33128c2ecf20Sopenharmony_ci	    info->attrs[DEVLINK_ATTR_NETNS_ID]) {
33138c2ecf20Sopenharmony_ci		dest_net = devlink_netns_get(skb, info);
33148c2ecf20Sopenharmony_ci		if (IS_ERR(dest_net))
33158c2ecf20Sopenharmony_ci			return PTR_ERR(dest_net);
33168c2ecf20Sopenharmony_ci	}
33178c2ecf20Sopenharmony_ci
33188c2ecf20Sopenharmony_ci	err = devlink_reload(devlink, dest_net, action, limit, &actions_performed, info->extack);
33198c2ecf20Sopenharmony_ci
33208c2ecf20Sopenharmony_ci	if (dest_net)
33218c2ecf20Sopenharmony_ci		put_net(dest_net);
33228c2ecf20Sopenharmony_ci
33238c2ecf20Sopenharmony_ci	if (err)
33248c2ecf20Sopenharmony_ci		return err;
33258c2ecf20Sopenharmony_ci	/* For backward compatibility generate reply only if attributes used by user */
33268c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_RELOAD_ACTION] && !info->attrs[DEVLINK_ATTR_RELOAD_LIMITS])
33278c2ecf20Sopenharmony_ci		return 0;
33288c2ecf20Sopenharmony_ci
33298c2ecf20Sopenharmony_ci	return devlink_nl_reload_actions_performed_snd(devlink, actions_performed,
33308c2ecf20Sopenharmony_ci						       DEVLINK_CMD_RELOAD, info);
33318c2ecf20Sopenharmony_ci}
33328c2ecf20Sopenharmony_ci
33338c2ecf20Sopenharmony_cistatic int devlink_nl_flash_update_fill(struct sk_buff *msg,
33348c2ecf20Sopenharmony_ci					struct devlink *devlink,
33358c2ecf20Sopenharmony_ci					enum devlink_command cmd,
33368c2ecf20Sopenharmony_ci					struct devlink_flash_notify *params)
33378c2ecf20Sopenharmony_ci{
33388c2ecf20Sopenharmony_ci	void *hdr;
33398c2ecf20Sopenharmony_ci
33408c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd);
33418c2ecf20Sopenharmony_ci	if (!hdr)
33428c2ecf20Sopenharmony_ci		return -EMSGSIZE;
33438c2ecf20Sopenharmony_ci
33448c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(msg, devlink))
33458c2ecf20Sopenharmony_ci		goto nla_put_failure;
33468c2ecf20Sopenharmony_ci
33478c2ecf20Sopenharmony_ci	if (cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS)
33488c2ecf20Sopenharmony_ci		goto out;
33498c2ecf20Sopenharmony_ci
33508c2ecf20Sopenharmony_ci	if (params->status_msg &&
33518c2ecf20Sopenharmony_ci	    nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG,
33528c2ecf20Sopenharmony_ci			   params->status_msg))
33538c2ecf20Sopenharmony_ci		goto nla_put_failure;
33548c2ecf20Sopenharmony_ci	if (params->component &&
33558c2ecf20Sopenharmony_ci	    nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,
33568c2ecf20Sopenharmony_ci			   params->component))
33578c2ecf20Sopenharmony_ci		goto nla_put_failure;
33588c2ecf20Sopenharmony_ci	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE,
33598c2ecf20Sopenharmony_ci			      params->done, DEVLINK_ATTR_PAD))
33608c2ecf20Sopenharmony_ci		goto nla_put_failure;
33618c2ecf20Sopenharmony_ci	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL,
33628c2ecf20Sopenharmony_ci			      params->total, DEVLINK_ATTR_PAD))
33638c2ecf20Sopenharmony_ci		goto nla_put_failure;
33648c2ecf20Sopenharmony_ci	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT,
33658c2ecf20Sopenharmony_ci			      params->timeout, DEVLINK_ATTR_PAD))
33668c2ecf20Sopenharmony_ci		goto nla_put_failure;
33678c2ecf20Sopenharmony_ci
33688c2ecf20Sopenharmony_ciout:
33698c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
33708c2ecf20Sopenharmony_ci	return 0;
33718c2ecf20Sopenharmony_ci
33728c2ecf20Sopenharmony_cinla_put_failure:
33738c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
33748c2ecf20Sopenharmony_ci	return -EMSGSIZE;
33758c2ecf20Sopenharmony_ci}
33768c2ecf20Sopenharmony_ci
33778c2ecf20Sopenharmony_cistatic void __devlink_flash_update_notify(struct devlink *devlink,
33788c2ecf20Sopenharmony_ci					  enum devlink_command cmd,
33798c2ecf20Sopenharmony_ci					  struct devlink_flash_notify *params)
33808c2ecf20Sopenharmony_ci{
33818c2ecf20Sopenharmony_ci	struct sk_buff *msg;
33828c2ecf20Sopenharmony_ci	int err;
33838c2ecf20Sopenharmony_ci
33848c2ecf20Sopenharmony_ci	WARN_ON(cmd != DEVLINK_CMD_FLASH_UPDATE &&
33858c2ecf20Sopenharmony_ci		cmd != DEVLINK_CMD_FLASH_UPDATE_END &&
33868c2ecf20Sopenharmony_ci		cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS);
33878c2ecf20Sopenharmony_ci
33888c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
33898c2ecf20Sopenharmony_ci	if (!msg)
33908c2ecf20Sopenharmony_ci		return;
33918c2ecf20Sopenharmony_ci
33928c2ecf20Sopenharmony_ci	err = devlink_nl_flash_update_fill(msg, devlink, cmd, params);
33938c2ecf20Sopenharmony_ci	if (err)
33948c2ecf20Sopenharmony_ci		goto out_free_msg;
33958c2ecf20Sopenharmony_ci
33968c2ecf20Sopenharmony_ci	genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
33978c2ecf20Sopenharmony_ci				msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
33988c2ecf20Sopenharmony_ci	return;
33998c2ecf20Sopenharmony_ci
34008c2ecf20Sopenharmony_ciout_free_msg:
34018c2ecf20Sopenharmony_ci	nlmsg_free(msg);
34028c2ecf20Sopenharmony_ci}
34038c2ecf20Sopenharmony_ci
34048c2ecf20Sopenharmony_civoid devlink_flash_update_begin_notify(struct devlink *devlink)
34058c2ecf20Sopenharmony_ci{
34068c2ecf20Sopenharmony_ci	struct devlink_flash_notify params = {};
34078c2ecf20Sopenharmony_ci
34088c2ecf20Sopenharmony_ci	__devlink_flash_update_notify(devlink,
34098c2ecf20Sopenharmony_ci				      DEVLINK_CMD_FLASH_UPDATE,
34108c2ecf20Sopenharmony_ci				      &params);
34118c2ecf20Sopenharmony_ci}
34128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_flash_update_begin_notify);
34138c2ecf20Sopenharmony_ci
34148c2ecf20Sopenharmony_civoid devlink_flash_update_end_notify(struct devlink *devlink)
34158c2ecf20Sopenharmony_ci{
34168c2ecf20Sopenharmony_ci	struct devlink_flash_notify params = {};
34178c2ecf20Sopenharmony_ci
34188c2ecf20Sopenharmony_ci	__devlink_flash_update_notify(devlink,
34198c2ecf20Sopenharmony_ci				      DEVLINK_CMD_FLASH_UPDATE_END,
34208c2ecf20Sopenharmony_ci				      &params);
34218c2ecf20Sopenharmony_ci}
34228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_flash_update_end_notify);
34238c2ecf20Sopenharmony_ci
34248c2ecf20Sopenharmony_civoid devlink_flash_update_status_notify(struct devlink *devlink,
34258c2ecf20Sopenharmony_ci					const char *status_msg,
34268c2ecf20Sopenharmony_ci					const char *component,
34278c2ecf20Sopenharmony_ci					unsigned long done,
34288c2ecf20Sopenharmony_ci					unsigned long total)
34298c2ecf20Sopenharmony_ci{
34308c2ecf20Sopenharmony_ci	struct devlink_flash_notify params = {
34318c2ecf20Sopenharmony_ci		.status_msg = status_msg,
34328c2ecf20Sopenharmony_ci		.component = component,
34338c2ecf20Sopenharmony_ci		.done = done,
34348c2ecf20Sopenharmony_ci		.total = total,
34358c2ecf20Sopenharmony_ci	};
34368c2ecf20Sopenharmony_ci
34378c2ecf20Sopenharmony_ci	__devlink_flash_update_notify(devlink,
34388c2ecf20Sopenharmony_ci				      DEVLINK_CMD_FLASH_UPDATE_STATUS,
34398c2ecf20Sopenharmony_ci				      &params);
34408c2ecf20Sopenharmony_ci}
34418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_flash_update_status_notify);
34428c2ecf20Sopenharmony_ci
34438c2ecf20Sopenharmony_civoid devlink_flash_update_timeout_notify(struct devlink *devlink,
34448c2ecf20Sopenharmony_ci					 const char *status_msg,
34458c2ecf20Sopenharmony_ci					 const char *component,
34468c2ecf20Sopenharmony_ci					 unsigned long timeout)
34478c2ecf20Sopenharmony_ci{
34488c2ecf20Sopenharmony_ci	struct devlink_flash_notify params = {
34498c2ecf20Sopenharmony_ci		.status_msg = status_msg,
34508c2ecf20Sopenharmony_ci		.component = component,
34518c2ecf20Sopenharmony_ci		.timeout = timeout,
34528c2ecf20Sopenharmony_ci	};
34538c2ecf20Sopenharmony_ci
34548c2ecf20Sopenharmony_ci	__devlink_flash_update_notify(devlink,
34558c2ecf20Sopenharmony_ci				      DEVLINK_CMD_FLASH_UPDATE_STATUS,
34568c2ecf20Sopenharmony_ci				      &params);
34578c2ecf20Sopenharmony_ci}
34588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_flash_update_timeout_notify);
34598c2ecf20Sopenharmony_ci
34608c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_flash_update(struct sk_buff *skb,
34618c2ecf20Sopenharmony_ci				       struct genl_info *info)
34628c2ecf20Sopenharmony_ci{
34638c2ecf20Sopenharmony_ci	struct nlattr *nla_component, *nla_overwrite_mask;
34648c2ecf20Sopenharmony_ci	struct devlink_flash_update_params params = {};
34658c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
34668c2ecf20Sopenharmony_ci	u32 supported_params;
34678c2ecf20Sopenharmony_ci
34688c2ecf20Sopenharmony_ci	if (!devlink->ops->flash_update)
34698c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
34708c2ecf20Sopenharmony_ci
34718c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME])
34728c2ecf20Sopenharmony_ci		return -EINVAL;
34738c2ecf20Sopenharmony_ci
34748c2ecf20Sopenharmony_ci	supported_params = devlink->ops->supported_flash_update_params;
34758c2ecf20Sopenharmony_ci
34768c2ecf20Sopenharmony_ci	params.file_name = nla_data(info->attrs[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME]);
34778c2ecf20Sopenharmony_ci
34788c2ecf20Sopenharmony_ci	nla_component = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT];
34798c2ecf20Sopenharmony_ci	if (nla_component) {
34808c2ecf20Sopenharmony_ci		if (!(supported_params & DEVLINK_SUPPORT_FLASH_UPDATE_COMPONENT)) {
34818c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR(info->extack, nla_component,
34828c2ecf20Sopenharmony_ci					    "component update is not supported by this device");
34838c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
34848c2ecf20Sopenharmony_ci		}
34858c2ecf20Sopenharmony_ci		params.component = nla_data(nla_component);
34868c2ecf20Sopenharmony_ci	}
34878c2ecf20Sopenharmony_ci
34888c2ecf20Sopenharmony_ci	nla_overwrite_mask = info->attrs[DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK];
34898c2ecf20Sopenharmony_ci	if (nla_overwrite_mask) {
34908c2ecf20Sopenharmony_ci		struct nla_bitfield32 sections;
34918c2ecf20Sopenharmony_ci
34928c2ecf20Sopenharmony_ci		if (!(supported_params & DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK)) {
34938c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_ATTR(info->extack, nla_overwrite_mask,
34948c2ecf20Sopenharmony_ci					    "overwrite settings are not supported by this device");
34958c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
34968c2ecf20Sopenharmony_ci		}
34978c2ecf20Sopenharmony_ci		sections = nla_get_bitfield32(nla_overwrite_mask);
34988c2ecf20Sopenharmony_ci		params.overwrite_mask = sections.value & sections.selector;
34998c2ecf20Sopenharmony_ci	}
35008c2ecf20Sopenharmony_ci
35018c2ecf20Sopenharmony_ci	return devlink->ops->flash_update(devlink, &params, info->extack);
35028c2ecf20Sopenharmony_ci}
35038c2ecf20Sopenharmony_ci
35048c2ecf20Sopenharmony_cistatic const struct devlink_param devlink_param_generic[] = {
35058c2ecf20Sopenharmony_ci	{
35068c2ecf20Sopenharmony_ci		.id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
35078c2ecf20Sopenharmony_ci		.name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
35088c2ecf20Sopenharmony_ci		.type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
35098c2ecf20Sopenharmony_ci	},
35108c2ecf20Sopenharmony_ci	{
35118c2ecf20Sopenharmony_ci		.id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
35128c2ecf20Sopenharmony_ci		.name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
35138c2ecf20Sopenharmony_ci		.type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
35148c2ecf20Sopenharmony_ci	},
35158c2ecf20Sopenharmony_ci	{
35168c2ecf20Sopenharmony_ci		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
35178c2ecf20Sopenharmony_ci		.name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
35188c2ecf20Sopenharmony_ci		.type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
35198c2ecf20Sopenharmony_ci	},
35208c2ecf20Sopenharmony_ci	{
35218c2ecf20Sopenharmony_ci		.id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
35228c2ecf20Sopenharmony_ci		.name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
35238c2ecf20Sopenharmony_ci		.type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
35248c2ecf20Sopenharmony_ci	},
35258c2ecf20Sopenharmony_ci	{
35268c2ecf20Sopenharmony_ci		.id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
35278c2ecf20Sopenharmony_ci		.name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
35288c2ecf20Sopenharmony_ci		.type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
35298c2ecf20Sopenharmony_ci	},
35308c2ecf20Sopenharmony_ci	{
35318c2ecf20Sopenharmony_ci		.id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
35328c2ecf20Sopenharmony_ci		.name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
35338c2ecf20Sopenharmony_ci		.type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
35348c2ecf20Sopenharmony_ci	},
35358c2ecf20Sopenharmony_ci	{
35368c2ecf20Sopenharmony_ci		.id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
35378c2ecf20Sopenharmony_ci		.name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
35388c2ecf20Sopenharmony_ci		.type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
35398c2ecf20Sopenharmony_ci	},
35408c2ecf20Sopenharmony_ci	{
35418c2ecf20Sopenharmony_ci		.id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
35428c2ecf20Sopenharmony_ci		.name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
35438c2ecf20Sopenharmony_ci		.type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
35448c2ecf20Sopenharmony_ci	},
35458c2ecf20Sopenharmony_ci	{
35468c2ecf20Sopenharmony_ci		.id = DEVLINK_PARAM_GENERIC_ID_RESET_DEV_ON_DRV_PROBE,
35478c2ecf20Sopenharmony_ci		.name = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_NAME,
35488c2ecf20Sopenharmony_ci		.type = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_TYPE,
35498c2ecf20Sopenharmony_ci	},
35508c2ecf20Sopenharmony_ci	{
35518c2ecf20Sopenharmony_ci		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE,
35528c2ecf20Sopenharmony_ci		.name = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_NAME,
35538c2ecf20Sopenharmony_ci		.type = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_TYPE,
35548c2ecf20Sopenharmony_ci	},
35558c2ecf20Sopenharmony_ci	{
35568c2ecf20Sopenharmony_ci		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_REMOTE_DEV_RESET,
35578c2ecf20Sopenharmony_ci		.name = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_NAME,
35588c2ecf20Sopenharmony_ci		.type = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_TYPE,
35598c2ecf20Sopenharmony_ci	},
35608c2ecf20Sopenharmony_ci};
35618c2ecf20Sopenharmony_ci
35628c2ecf20Sopenharmony_cistatic int devlink_param_generic_verify(const struct devlink_param *param)
35638c2ecf20Sopenharmony_ci{
35648c2ecf20Sopenharmony_ci	/* verify it match generic parameter by id and name */
35658c2ecf20Sopenharmony_ci	if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
35668c2ecf20Sopenharmony_ci		return -EINVAL;
35678c2ecf20Sopenharmony_ci	if (strcmp(param->name, devlink_param_generic[param->id].name))
35688c2ecf20Sopenharmony_ci		return -ENOENT;
35698c2ecf20Sopenharmony_ci
35708c2ecf20Sopenharmony_ci	WARN_ON(param->type != devlink_param_generic[param->id].type);
35718c2ecf20Sopenharmony_ci
35728c2ecf20Sopenharmony_ci	return 0;
35738c2ecf20Sopenharmony_ci}
35748c2ecf20Sopenharmony_ci
35758c2ecf20Sopenharmony_cistatic int devlink_param_driver_verify(const struct devlink_param *param)
35768c2ecf20Sopenharmony_ci{
35778c2ecf20Sopenharmony_ci	int i;
35788c2ecf20Sopenharmony_ci
35798c2ecf20Sopenharmony_ci	if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
35808c2ecf20Sopenharmony_ci		return -EINVAL;
35818c2ecf20Sopenharmony_ci	/* verify no such name in generic params */
35828c2ecf20Sopenharmony_ci	for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
35838c2ecf20Sopenharmony_ci		if (!strcmp(param->name, devlink_param_generic[i].name))
35848c2ecf20Sopenharmony_ci			return -EEXIST;
35858c2ecf20Sopenharmony_ci
35868c2ecf20Sopenharmony_ci	return 0;
35878c2ecf20Sopenharmony_ci}
35888c2ecf20Sopenharmony_ci
35898c2ecf20Sopenharmony_cistatic struct devlink_param_item *
35908c2ecf20Sopenharmony_cidevlink_param_find_by_name(struct list_head *param_list,
35918c2ecf20Sopenharmony_ci			   const char *param_name)
35928c2ecf20Sopenharmony_ci{
35938c2ecf20Sopenharmony_ci	struct devlink_param_item *param_item;
35948c2ecf20Sopenharmony_ci
35958c2ecf20Sopenharmony_ci	list_for_each_entry(param_item, param_list, list)
35968c2ecf20Sopenharmony_ci		if (!strcmp(param_item->param->name, param_name))
35978c2ecf20Sopenharmony_ci			return param_item;
35988c2ecf20Sopenharmony_ci	return NULL;
35998c2ecf20Sopenharmony_ci}
36008c2ecf20Sopenharmony_ci
36018c2ecf20Sopenharmony_cistatic struct devlink_param_item *
36028c2ecf20Sopenharmony_cidevlink_param_find_by_id(struct list_head *param_list, u32 param_id)
36038c2ecf20Sopenharmony_ci{
36048c2ecf20Sopenharmony_ci	struct devlink_param_item *param_item;
36058c2ecf20Sopenharmony_ci
36068c2ecf20Sopenharmony_ci	list_for_each_entry(param_item, param_list, list)
36078c2ecf20Sopenharmony_ci		if (param_item->param->id == param_id)
36088c2ecf20Sopenharmony_ci			return param_item;
36098c2ecf20Sopenharmony_ci	return NULL;
36108c2ecf20Sopenharmony_ci}
36118c2ecf20Sopenharmony_ci
36128c2ecf20Sopenharmony_cistatic bool
36138c2ecf20Sopenharmony_cidevlink_param_cmode_is_supported(const struct devlink_param *param,
36148c2ecf20Sopenharmony_ci				 enum devlink_param_cmode cmode)
36158c2ecf20Sopenharmony_ci{
36168c2ecf20Sopenharmony_ci	return test_bit(cmode, &param->supported_cmodes);
36178c2ecf20Sopenharmony_ci}
36188c2ecf20Sopenharmony_ci
36198c2ecf20Sopenharmony_cistatic int devlink_param_get(struct devlink *devlink,
36208c2ecf20Sopenharmony_ci			     const struct devlink_param *param,
36218c2ecf20Sopenharmony_ci			     struct devlink_param_gset_ctx *ctx)
36228c2ecf20Sopenharmony_ci{
36238c2ecf20Sopenharmony_ci	if (!param->get)
36248c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
36258c2ecf20Sopenharmony_ci	return param->get(devlink, param->id, ctx);
36268c2ecf20Sopenharmony_ci}
36278c2ecf20Sopenharmony_ci
36288c2ecf20Sopenharmony_cistatic int devlink_param_set(struct devlink *devlink,
36298c2ecf20Sopenharmony_ci			     const struct devlink_param *param,
36308c2ecf20Sopenharmony_ci			     struct devlink_param_gset_ctx *ctx)
36318c2ecf20Sopenharmony_ci{
36328c2ecf20Sopenharmony_ci	if (!param->set)
36338c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
36348c2ecf20Sopenharmony_ci	return param->set(devlink, param->id, ctx);
36358c2ecf20Sopenharmony_ci}
36368c2ecf20Sopenharmony_ci
36378c2ecf20Sopenharmony_cistatic int
36388c2ecf20Sopenharmony_cidevlink_param_type_to_nla_type(enum devlink_param_type param_type)
36398c2ecf20Sopenharmony_ci{
36408c2ecf20Sopenharmony_ci	switch (param_type) {
36418c2ecf20Sopenharmony_ci	case DEVLINK_PARAM_TYPE_U8:
36428c2ecf20Sopenharmony_ci		return NLA_U8;
36438c2ecf20Sopenharmony_ci	case DEVLINK_PARAM_TYPE_U16:
36448c2ecf20Sopenharmony_ci		return NLA_U16;
36458c2ecf20Sopenharmony_ci	case DEVLINK_PARAM_TYPE_U32:
36468c2ecf20Sopenharmony_ci		return NLA_U32;
36478c2ecf20Sopenharmony_ci	case DEVLINK_PARAM_TYPE_STRING:
36488c2ecf20Sopenharmony_ci		return NLA_STRING;
36498c2ecf20Sopenharmony_ci	case DEVLINK_PARAM_TYPE_BOOL:
36508c2ecf20Sopenharmony_ci		return NLA_FLAG;
36518c2ecf20Sopenharmony_ci	default:
36528c2ecf20Sopenharmony_ci		return -EINVAL;
36538c2ecf20Sopenharmony_ci	}
36548c2ecf20Sopenharmony_ci}
36558c2ecf20Sopenharmony_ci
36568c2ecf20Sopenharmony_cistatic int
36578c2ecf20Sopenharmony_cidevlink_nl_param_value_fill_one(struct sk_buff *msg,
36588c2ecf20Sopenharmony_ci				enum devlink_param_type type,
36598c2ecf20Sopenharmony_ci				enum devlink_param_cmode cmode,
36608c2ecf20Sopenharmony_ci				union devlink_param_value val)
36618c2ecf20Sopenharmony_ci{
36628c2ecf20Sopenharmony_ci	struct nlattr *param_value_attr;
36638c2ecf20Sopenharmony_ci
36648c2ecf20Sopenharmony_ci	param_value_attr = nla_nest_start_noflag(msg,
36658c2ecf20Sopenharmony_ci						 DEVLINK_ATTR_PARAM_VALUE);
36668c2ecf20Sopenharmony_ci	if (!param_value_attr)
36678c2ecf20Sopenharmony_ci		goto nla_put_failure;
36688c2ecf20Sopenharmony_ci
36698c2ecf20Sopenharmony_ci	if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
36708c2ecf20Sopenharmony_ci		goto value_nest_cancel;
36718c2ecf20Sopenharmony_ci
36728c2ecf20Sopenharmony_ci	switch (type) {
36738c2ecf20Sopenharmony_ci	case DEVLINK_PARAM_TYPE_U8:
36748c2ecf20Sopenharmony_ci		if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
36758c2ecf20Sopenharmony_ci			goto value_nest_cancel;
36768c2ecf20Sopenharmony_ci		break;
36778c2ecf20Sopenharmony_ci	case DEVLINK_PARAM_TYPE_U16:
36788c2ecf20Sopenharmony_ci		if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
36798c2ecf20Sopenharmony_ci			goto value_nest_cancel;
36808c2ecf20Sopenharmony_ci		break;
36818c2ecf20Sopenharmony_ci	case DEVLINK_PARAM_TYPE_U32:
36828c2ecf20Sopenharmony_ci		if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
36838c2ecf20Sopenharmony_ci			goto value_nest_cancel;
36848c2ecf20Sopenharmony_ci		break;
36858c2ecf20Sopenharmony_ci	case DEVLINK_PARAM_TYPE_STRING:
36868c2ecf20Sopenharmony_ci		if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
36878c2ecf20Sopenharmony_ci				   val.vstr))
36888c2ecf20Sopenharmony_ci			goto value_nest_cancel;
36898c2ecf20Sopenharmony_ci		break;
36908c2ecf20Sopenharmony_ci	case DEVLINK_PARAM_TYPE_BOOL:
36918c2ecf20Sopenharmony_ci		if (val.vbool &&
36928c2ecf20Sopenharmony_ci		    nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
36938c2ecf20Sopenharmony_ci			goto value_nest_cancel;
36948c2ecf20Sopenharmony_ci		break;
36958c2ecf20Sopenharmony_ci	}
36968c2ecf20Sopenharmony_ci
36978c2ecf20Sopenharmony_ci	nla_nest_end(msg, param_value_attr);
36988c2ecf20Sopenharmony_ci	return 0;
36998c2ecf20Sopenharmony_ci
37008c2ecf20Sopenharmony_civalue_nest_cancel:
37018c2ecf20Sopenharmony_ci	nla_nest_cancel(msg, param_value_attr);
37028c2ecf20Sopenharmony_cinla_put_failure:
37038c2ecf20Sopenharmony_ci	return -EMSGSIZE;
37048c2ecf20Sopenharmony_ci}
37058c2ecf20Sopenharmony_ci
37068c2ecf20Sopenharmony_cistatic int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
37078c2ecf20Sopenharmony_ci				 unsigned int port_index,
37088c2ecf20Sopenharmony_ci				 struct devlink_param_item *param_item,
37098c2ecf20Sopenharmony_ci				 enum devlink_command cmd,
37108c2ecf20Sopenharmony_ci				 u32 portid, u32 seq, int flags)
37118c2ecf20Sopenharmony_ci{
37128c2ecf20Sopenharmony_ci	union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
37138c2ecf20Sopenharmony_ci	bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
37148c2ecf20Sopenharmony_ci	const struct devlink_param *param = param_item->param;
37158c2ecf20Sopenharmony_ci	struct devlink_param_gset_ctx ctx;
37168c2ecf20Sopenharmony_ci	struct nlattr *param_values_list;
37178c2ecf20Sopenharmony_ci	struct nlattr *param_attr;
37188c2ecf20Sopenharmony_ci	int nla_type;
37198c2ecf20Sopenharmony_ci	void *hdr;
37208c2ecf20Sopenharmony_ci	int err;
37218c2ecf20Sopenharmony_ci	int i;
37228c2ecf20Sopenharmony_ci
37238c2ecf20Sopenharmony_ci	/* Get value from driver part to driverinit configuration mode */
37248c2ecf20Sopenharmony_ci	for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
37258c2ecf20Sopenharmony_ci		if (!devlink_param_cmode_is_supported(param, i))
37268c2ecf20Sopenharmony_ci			continue;
37278c2ecf20Sopenharmony_ci		if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
37288c2ecf20Sopenharmony_ci			if (!param_item->driverinit_value_valid)
37298c2ecf20Sopenharmony_ci				return -EOPNOTSUPP;
37308c2ecf20Sopenharmony_ci			param_value[i] = param_item->driverinit_value;
37318c2ecf20Sopenharmony_ci		} else {
37328c2ecf20Sopenharmony_ci			if (!param_item->published)
37338c2ecf20Sopenharmony_ci				continue;
37348c2ecf20Sopenharmony_ci			ctx.cmode = i;
37358c2ecf20Sopenharmony_ci			err = devlink_param_get(devlink, param, &ctx);
37368c2ecf20Sopenharmony_ci			if (err)
37378c2ecf20Sopenharmony_ci				return err;
37388c2ecf20Sopenharmony_ci			param_value[i] = ctx.val;
37398c2ecf20Sopenharmony_ci		}
37408c2ecf20Sopenharmony_ci		param_value_set[i] = true;
37418c2ecf20Sopenharmony_ci	}
37428c2ecf20Sopenharmony_ci
37438c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
37448c2ecf20Sopenharmony_ci	if (!hdr)
37458c2ecf20Sopenharmony_ci		return -EMSGSIZE;
37468c2ecf20Sopenharmony_ci
37478c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(msg, devlink))
37488c2ecf20Sopenharmony_ci		goto genlmsg_cancel;
37498c2ecf20Sopenharmony_ci
37508c2ecf20Sopenharmony_ci	if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
37518c2ecf20Sopenharmony_ci	    cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
37528c2ecf20Sopenharmony_ci	    cmd == DEVLINK_CMD_PORT_PARAM_DEL)
37538c2ecf20Sopenharmony_ci		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
37548c2ecf20Sopenharmony_ci			goto genlmsg_cancel;
37558c2ecf20Sopenharmony_ci
37568c2ecf20Sopenharmony_ci	param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM);
37578c2ecf20Sopenharmony_ci	if (!param_attr)
37588c2ecf20Sopenharmony_ci		goto genlmsg_cancel;
37598c2ecf20Sopenharmony_ci	if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
37608c2ecf20Sopenharmony_ci		goto param_nest_cancel;
37618c2ecf20Sopenharmony_ci	if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
37628c2ecf20Sopenharmony_ci		goto param_nest_cancel;
37638c2ecf20Sopenharmony_ci
37648c2ecf20Sopenharmony_ci	nla_type = devlink_param_type_to_nla_type(param->type);
37658c2ecf20Sopenharmony_ci	if (nla_type < 0)
37668c2ecf20Sopenharmony_ci		goto param_nest_cancel;
37678c2ecf20Sopenharmony_ci	if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
37688c2ecf20Sopenharmony_ci		goto param_nest_cancel;
37698c2ecf20Sopenharmony_ci
37708c2ecf20Sopenharmony_ci	param_values_list = nla_nest_start_noflag(msg,
37718c2ecf20Sopenharmony_ci						  DEVLINK_ATTR_PARAM_VALUES_LIST);
37728c2ecf20Sopenharmony_ci	if (!param_values_list)
37738c2ecf20Sopenharmony_ci		goto param_nest_cancel;
37748c2ecf20Sopenharmony_ci
37758c2ecf20Sopenharmony_ci	for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
37768c2ecf20Sopenharmony_ci		if (!param_value_set[i])
37778c2ecf20Sopenharmony_ci			continue;
37788c2ecf20Sopenharmony_ci		err = devlink_nl_param_value_fill_one(msg, param->type,
37798c2ecf20Sopenharmony_ci						      i, param_value[i]);
37808c2ecf20Sopenharmony_ci		if (err)
37818c2ecf20Sopenharmony_ci			goto values_list_nest_cancel;
37828c2ecf20Sopenharmony_ci	}
37838c2ecf20Sopenharmony_ci
37848c2ecf20Sopenharmony_ci	nla_nest_end(msg, param_values_list);
37858c2ecf20Sopenharmony_ci	nla_nest_end(msg, param_attr);
37868c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
37878c2ecf20Sopenharmony_ci	return 0;
37888c2ecf20Sopenharmony_ci
37898c2ecf20Sopenharmony_civalues_list_nest_cancel:
37908c2ecf20Sopenharmony_ci	nla_nest_end(msg, param_values_list);
37918c2ecf20Sopenharmony_ciparam_nest_cancel:
37928c2ecf20Sopenharmony_ci	nla_nest_cancel(msg, param_attr);
37938c2ecf20Sopenharmony_cigenlmsg_cancel:
37948c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
37958c2ecf20Sopenharmony_ci	return -EMSGSIZE;
37968c2ecf20Sopenharmony_ci}
37978c2ecf20Sopenharmony_ci
37988c2ecf20Sopenharmony_cistatic void devlink_param_notify(struct devlink *devlink,
37998c2ecf20Sopenharmony_ci				 unsigned int port_index,
38008c2ecf20Sopenharmony_ci				 struct devlink_param_item *param_item,
38018c2ecf20Sopenharmony_ci				 enum devlink_command cmd)
38028c2ecf20Sopenharmony_ci{
38038c2ecf20Sopenharmony_ci	struct sk_buff *msg;
38048c2ecf20Sopenharmony_ci	int err;
38058c2ecf20Sopenharmony_ci
38068c2ecf20Sopenharmony_ci	WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
38078c2ecf20Sopenharmony_ci		cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
38088c2ecf20Sopenharmony_ci		cmd != DEVLINK_CMD_PORT_PARAM_DEL);
38098c2ecf20Sopenharmony_ci
38108c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
38118c2ecf20Sopenharmony_ci	if (!msg)
38128c2ecf20Sopenharmony_ci		return;
38138c2ecf20Sopenharmony_ci	err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
38148c2ecf20Sopenharmony_ci				    0, 0, 0);
38158c2ecf20Sopenharmony_ci	if (err) {
38168c2ecf20Sopenharmony_ci		nlmsg_free(msg);
38178c2ecf20Sopenharmony_ci		return;
38188c2ecf20Sopenharmony_ci	}
38198c2ecf20Sopenharmony_ci
38208c2ecf20Sopenharmony_ci	genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
38218c2ecf20Sopenharmony_ci				msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
38228c2ecf20Sopenharmony_ci}
38238c2ecf20Sopenharmony_ci
38248c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_param_get_dumpit(struct sk_buff *msg,
38258c2ecf20Sopenharmony_ci					   struct netlink_callback *cb)
38268c2ecf20Sopenharmony_ci{
38278c2ecf20Sopenharmony_ci	struct devlink_param_item *param_item;
38288c2ecf20Sopenharmony_ci	struct devlink *devlink;
38298c2ecf20Sopenharmony_ci	int start = cb->args[0];
38308c2ecf20Sopenharmony_ci	int idx = 0;
38318c2ecf20Sopenharmony_ci	int err = 0;
38328c2ecf20Sopenharmony_ci
38338c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
38348c2ecf20Sopenharmony_ci	list_for_each_entry(devlink, &devlink_list, list) {
38358c2ecf20Sopenharmony_ci		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
38368c2ecf20Sopenharmony_ci			continue;
38378c2ecf20Sopenharmony_ci		mutex_lock(&devlink->lock);
38388c2ecf20Sopenharmony_ci		list_for_each_entry(param_item, &devlink->param_list, list) {
38398c2ecf20Sopenharmony_ci			if (idx < start) {
38408c2ecf20Sopenharmony_ci				idx++;
38418c2ecf20Sopenharmony_ci				continue;
38428c2ecf20Sopenharmony_ci			}
38438c2ecf20Sopenharmony_ci			err = devlink_nl_param_fill(msg, devlink, 0, param_item,
38448c2ecf20Sopenharmony_ci						    DEVLINK_CMD_PARAM_GET,
38458c2ecf20Sopenharmony_ci						    NETLINK_CB(cb->skb).portid,
38468c2ecf20Sopenharmony_ci						    cb->nlh->nlmsg_seq,
38478c2ecf20Sopenharmony_ci						    NLM_F_MULTI);
38488c2ecf20Sopenharmony_ci			if (err == -EOPNOTSUPP) {
38498c2ecf20Sopenharmony_ci				err = 0;
38508c2ecf20Sopenharmony_ci			} else if (err) {
38518c2ecf20Sopenharmony_ci				mutex_unlock(&devlink->lock);
38528c2ecf20Sopenharmony_ci				goto out;
38538c2ecf20Sopenharmony_ci			}
38548c2ecf20Sopenharmony_ci			idx++;
38558c2ecf20Sopenharmony_ci		}
38568c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->lock);
38578c2ecf20Sopenharmony_ci	}
38588c2ecf20Sopenharmony_ciout:
38598c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
38608c2ecf20Sopenharmony_ci
38618c2ecf20Sopenharmony_ci	if (err != -EMSGSIZE)
38628c2ecf20Sopenharmony_ci		return err;
38638c2ecf20Sopenharmony_ci
38648c2ecf20Sopenharmony_ci	cb->args[0] = idx;
38658c2ecf20Sopenharmony_ci	return msg->len;
38668c2ecf20Sopenharmony_ci}
38678c2ecf20Sopenharmony_ci
38688c2ecf20Sopenharmony_cistatic int
38698c2ecf20Sopenharmony_cidevlink_param_type_get_from_info(struct genl_info *info,
38708c2ecf20Sopenharmony_ci				 enum devlink_param_type *param_type)
38718c2ecf20Sopenharmony_ci{
38728c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_PARAM_TYPE])
38738c2ecf20Sopenharmony_ci		return -EINVAL;
38748c2ecf20Sopenharmony_ci
38758c2ecf20Sopenharmony_ci	switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
38768c2ecf20Sopenharmony_ci	case NLA_U8:
38778c2ecf20Sopenharmony_ci		*param_type = DEVLINK_PARAM_TYPE_U8;
38788c2ecf20Sopenharmony_ci		break;
38798c2ecf20Sopenharmony_ci	case NLA_U16:
38808c2ecf20Sopenharmony_ci		*param_type = DEVLINK_PARAM_TYPE_U16;
38818c2ecf20Sopenharmony_ci		break;
38828c2ecf20Sopenharmony_ci	case NLA_U32:
38838c2ecf20Sopenharmony_ci		*param_type = DEVLINK_PARAM_TYPE_U32;
38848c2ecf20Sopenharmony_ci		break;
38858c2ecf20Sopenharmony_ci	case NLA_STRING:
38868c2ecf20Sopenharmony_ci		*param_type = DEVLINK_PARAM_TYPE_STRING;
38878c2ecf20Sopenharmony_ci		break;
38888c2ecf20Sopenharmony_ci	case NLA_FLAG:
38898c2ecf20Sopenharmony_ci		*param_type = DEVLINK_PARAM_TYPE_BOOL;
38908c2ecf20Sopenharmony_ci		break;
38918c2ecf20Sopenharmony_ci	default:
38928c2ecf20Sopenharmony_ci		return -EINVAL;
38938c2ecf20Sopenharmony_ci	}
38948c2ecf20Sopenharmony_ci
38958c2ecf20Sopenharmony_ci	return 0;
38968c2ecf20Sopenharmony_ci}
38978c2ecf20Sopenharmony_ci
38988c2ecf20Sopenharmony_cistatic int
38998c2ecf20Sopenharmony_cidevlink_param_value_get_from_info(const struct devlink_param *param,
39008c2ecf20Sopenharmony_ci				  struct genl_info *info,
39018c2ecf20Sopenharmony_ci				  union devlink_param_value *value)
39028c2ecf20Sopenharmony_ci{
39038c2ecf20Sopenharmony_ci	struct nlattr *param_data;
39048c2ecf20Sopenharmony_ci	int len;
39058c2ecf20Sopenharmony_ci
39068c2ecf20Sopenharmony_ci	param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
39078c2ecf20Sopenharmony_ci
39088c2ecf20Sopenharmony_ci	if (param->type != DEVLINK_PARAM_TYPE_BOOL && !param_data)
39098c2ecf20Sopenharmony_ci		return -EINVAL;
39108c2ecf20Sopenharmony_ci
39118c2ecf20Sopenharmony_ci	switch (param->type) {
39128c2ecf20Sopenharmony_ci	case DEVLINK_PARAM_TYPE_U8:
39138c2ecf20Sopenharmony_ci		if (nla_len(param_data) != sizeof(u8))
39148c2ecf20Sopenharmony_ci			return -EINVAL;
39158c2ecf20Sopenharmony_ci		value->vu8 = nla_get_u8(param_data);
39168c2ecf20Sopenharmony_ci		break;
39178c2ecf20Sopenharmony_ci	case DEVLINK_PARAM_TYPE_U16:
39188c2ecf20Sopenharmony_ci		if (nla_len(param_data) != sizeof(u16))
39198c2ecf20Sopenharmony_ci			return -EINVAL;
39208c2ecf20Sopenharmony_ci		value->vu16 = nla_get_u16(param_data);
39218c2ecf20Sopenharmony_ci		break;
39228c2ecf20Sopenharmony_ci	case DEVLINK_PARAM_TYPE_U32:
39238c2ecf20Sopenharmony_ci		if (nla_len(param_data) != sizeof(u32))
39248c2ecf20Sopenharmony_ci			return -EINVAL;
39258c2ecf20Sopenharmony_ci		value->vu32 = nla_get_u32(param_data);
39268c2ecf20Sopenharmony_ci		break;
39278c2ecf20Sopenharmony_ci	case DEVLINK_PARAM_TYPE_STRING:
39288c2ecf20Sopenharmony_ci		len = strnlen(nla_data(param_data), nla_len(param_data));
39298c2ecf20Sopenharmony_ci		if (len == nla_len(param_data) ||
39308c2ecf20Sopenharmony_ci		    len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
39318c2ecf20Sopenharmony_ci			return -EINVAL;
39328c2ecf20Sopenharmony_ci		strcpy(value->vstr, nla_data(param_data));
39338c2ecf20Sopenharmony_ci		break;
39348c2ecf20Sopenharmony_ci	case DEVLINK_PARAM_TYPE_BOOL:
39358c2ecf20Sopenharmony_ci		if (param_data && nla_len(param_data))
39368c2ecf20Sopenharmony_ci			return -EINVAL;
39378c2ecf20Sopenharmony_ci		value->vbool = nla_get_flag(param_data);
39388c2ecf20Sopenharmony_ci		break;
39398c2ecf20Sopenharmony_ci	}
39408c2ecf20Sopenharmony_ci	return 0;
39418c2ecf20Sopenharmony_ci}
39428c2ecf20Sopenharmony_ci
39438c2ecf20Sopenharmony_cistatic struct devlink_param_item *
39448c2ecf20Sopenharmony_cidevlink_param_get_from_info(struct list_head *param_list,
39458c2ecf20Sopenharmony_ci			    struct genl_info *info)
39468c2ecf20Sopenharmony_ci{
39478c2ecf20Sopenharmony_ci	char *param_name;
39488c2ecf20Sopenharmony_ci
39498c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_PARAM_NAME])
39508c2ecf20Sopenharmony_ci		return NULL;
39518c2ecf20Sopenharmony_ci
39528c2ecf20Sopenharmony_ci	param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
39538c2ecf20Sopenharmony_ci	return devlink_param_find_by_name(param_list, param_name);
39548c2ecf20Sopenharmony_ci}
39558c2ecf20Sopenharmony_ci
39568c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_param_get_doit(struct sk_buff *skb,
39578c2ecf20Sopenharmony_ci					 struct genl_info *info)
39588c2ecf20Sopenharmony_ci{
39598c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
39608c2ecf20Sopenharmony_ci	struct devlink_param_item *param_item;
39618c2ecf20Sopenharmony_ci	struct sk_buff *msg;
39628c2ecf20Sopenharmony_ci	int err;
39638c2ecf20Sopenharmony_ci
39648c2ecf20Sopenharmony_ci	param_item = devlink_param_get_from_info(&devlink->param_list, info);
39658c2ecf20Sopenharmony_ci	if (!param_item)
39668c2ecf20Sopenharmony_ci		return -EINVAL;
39678c2ecf20Sopenharmony_ci
39688c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
39698c2ecf20Sopenharmony_ci	if (!msg)
39708c2ecf20Sopenharmony_ci		return -ENOMEM;
39718c2ecf20Sopenharmony_ci
39728c2ecf20Sopenharmony_ci	err = devlink_nl_param_fill(msg, devlink, 0, param_item,
39738c2ecf20Sopenharmony_ci				    DEVLINK_CMD_PARAM_GET,
39748c2ecf20Sopenharmony_ci				    info->snd_portid, info->snd_seq, 0);
39758c2ecf20Sopenharmony_ci	if (err) {
39768c2ecf20Sopenharmony_ci		nlmsg_free(msg);
39778c2ecf20Sopenharmony_ci		return err;
39788c2ecf20Sopenharmony_ci	}
39798c2ecf20Sopenharmony_ci
39808c2ecf20Sopenharmony_ci	return genlmsg_reply(msg, info);
39818c2ecf20Sopenharmony_ci}
39828c2ecf20Sopenharmony_ci
39838c2ecf20Sopenharmony_cistatic int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
39848c2ecf20Sopenharmony_ci					   unsigned int port_index,
39858c2ecf20Sopenharmony_ci					   struct list_head *param_list,
39868c2ecf20Sopenharmony_ci					   struct genl_info *info,
39878c2ecf20Sopenharmony_ci					   enum devlink_command cmd)
39888c2ecf20Sopenharmony_ci{
39898c2ecf20Sopenharmony_ci	enum devlink_param_type param_type;
39908c2ecf20Sopenharmony_ci	struct devlink_param_gset_ctx ctx;
39918c2ecf20Sopenharmony_ci	enum devlink_param_cmode cmode;
39928c2ecf20Sopenharmony_ci	struct devlink_param_item *param_item;
39938c2ecf20Sopenharmony_ci	const struct devlink_param *param;
39948c2ecf20Sopenharmony_ci	union devlink_param_value value;
39958c2ecf20Sopenharmony_ci	int err = 0;
39968c2ecf20Sopenharmony_ci
39978c2ecf20Sopenharmony_ci	param_item = devlink_param_get_from_info(param_list, info);
39988c2ecf20Sopenharmony_ci	if (!param_item)
39998c2ecf20Sopenharmony_ci		return -EINVAL;
40008c2ecf20Sopenharmony_ci	param = param_item->param;
40018c2ecf20Sopenharmony_ci	err = devlink_param_type_get_from_info(info, &param_type);
40028c2ecf20Sopenharmony_ci	if (err)
40038c2ecf20Sopenharmony_ci		return err;
40048c2ecf20Sopenharmony_ci	if (param_type != param->type)
40058c2ecf20Sopenharmony_ci		return -EINVAL;
40068c2ecf20Sopenharmony_ci	err = devlink_param_value_get_from_info(param, info, &value);
40078c2ecf20Sopenharmony_ci	if (err)
40088c2ecf20Sopenharmony_ci		return err;
40098c2ecf20Sopenharmony_ci	if (param->validate) {
40108c2ecf20Sopenharmony_ci		err = param->validate(devlink, param->id, value, info->extack);
40118c2ecf20Sopenharmony_ci		if (err)
40128c2ecf20Sopenharmony_ci			return err;
40138c2ecf20Sopenharmony_ci	}
40148c2ecf20Sopenharmony_ci
40158c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE])
40168c2ecf20Sopenharmony_ci		return -EINVAL;
40178c2ecf20Sopenharmony_ci	cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
40188c2ecf20Sopenharmony_ci	if (!devlink_param_cmode_is_supported(param, cmode))
40198c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
40208c2ecf20Sopenharmony_ci
40218c2ecf20Sopenharmony_ci	if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
40228c2ecf20Sopenharmony_ci		if (param->type == DEVLINK_PARAM_TYPE_STRING)
40238c2ecf20Sopenharmony_ci			strcpy(param_item->driverinit_value.vstr, value.vstr);
40248c2ecf20Sopenharmony_ci		else
40258c2ecf20Sopenharmony_ci			param_item->driverinit_value = value;
40268c2ecf20Sopenharmony_ci		param_item->driverinit_value_valid = true;
40278c2ecf20Sopenharmony_ci	} else {
40288c2ecf20Sopenharmony_ci		if (!param->set)
40298c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
40308c2ecf20Sopenharmony_ci		ctx.val = value;
40318c2ecf20Sopenharmony_ci		ctx.cmode = cmode;
40328c2ecf20Sopenharmony_ci		err = devlink_param_set(devlink, param, &ctx);
40338c2ecf20Sopenharmony_ci		if (err)
40348c2ecf20Sopenharmony_ci			return err;
40358c2ecf20Sopenharmony_ci	}
40368c2ecf20Sopenharmony_ci
40378c2ecf20Sopenharmony_ci	devlink_param_notify(devlink, port_index, param_item, cmd);
40388c2ecf20Sopenharmony_ci	return 0;
40398c2ecf20Sopenharmony_ci}
40408c2ecf20Sopenharmony_ci
40418c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_param_set_doit(struct sk_buff *skb,
40428c2ecf20Sopenharmony_ci					 struct genl_info *info)
40438c2ecf20Sopenharmony_ci{
40448c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
40458c2ecf20Sopenharmony_ci
40468c2ecf20Sopenharmony_ci	return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->param_list,
40478c2ecf20Sopenharmony_ci					       info, DEVLINK_CMD_PARAM_NEW);
40488c2ecf20Sopenharmony_ci}
40498c2ecf20Sopenharmony_ci
40508c2ecf20Sopenharmony_cistatic int devlink_param_register_one(struct devlink *devlink,
40518c2ecf20Sopenharmony_ci				      unsigned int port_index,
40528c2ecf20Sopenharmony_ci				      struct list_head *param_list,
40538c2ecf20Sopenharmony_ci				      const struct devlink_param *param,
40548c2ecf20Sopenharmony_ci				      enum devlink_command cmd)
40558c2ecf20Sopenharmony_ci{
40568c2ecf20Sopenharmony_ci	struct devlink_param_item *param_item;
40578c2ecf20Sopenharmony_ci
40588c2ecf20Sopenharmony_ci	if (devlink_param_find_by_name(param_list, param->name))
40598c2ecf20Sopenharmony_ci		return -EEXIST;
40608c2ecf20Sopenharmony_ci
40618c2ecf20Sopenharmony_ci	if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
40628c2ecf20Sopenharmony_ci		WARN_ON(param->get || param->set);
40638c2ecf20Sopenharmony_ci	else
40648c2ecf20Sopenharmony_ci		WARN_ON(!param->get || !param->set);
40658c2ecf20Sopenharmony_ci
40668c2ecf20Sopenharmony_ci	param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
40678c2ecf20Sopenharmony_ci	if (!param_item)
40688c2ecf20Sopenharmony_ci		return -ENOMEM;
40698c2ecf20Sopenharmony_ci	param_item->param = param;
40708c2ecf20Sopenharmony_ci
40718c2ecf20Sopenharmony_ci	list_add_tail(&param_item->list, param_list);
40728c2ecf20Sopenharmony_ci	devlink_param_notify(devlink, port_index, param_item, cmd);
40738c2ecf20Sopenharmony_ci	return 0;
40748c2ecf20Sopenharmony_ci}
40758c2ecf20Sopenharmony_ci
40768c2ecf20Sopenharmony_cistatic void devlink_param_unregister_one(struct devlink *devlink,
40778c2ecf20Sopenharmony_ci					 unsigned int port_index,
40788c2ecf20Sopenharmony_ci					 struct list_head *param_list,
40798c2ecf20Sopenharmony_ci					 const struct devlink_param *param,
40808c2ecf20Sopenharmony_ci					 enum devlink_command cmd)
40818c2ecf20Sopenharmony_ci{
40828c2ecf20Sopenharmony_ci	struct devlink_param_item *param_item;
40838c2ecf20Sopenharmony_ci
40848c2ecf20Sopenharmony_ci	param_item = devlink_param_find_by_name(param_list, param->name);
40858c2ecf20Sopenharmony_ci	WARN_ON(!param_item);
40868c2ecf20Sopenharmony_ci	devlink_param_notify(devlink, port_index, param_item, cmd);
40878c2ecf20Sopenharmony_ci	list_del(&param_item->list);
40888c2ecf20Sopenharmony_ci	kfree(param_item);
40898c2ecf20Sopenharmony_ci}
40908c2ecf20Sopenharmony_ci
40918c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
40928c2ecf20Sopenharmony_ci						struct netlink_callback *cb)
40938c2ecf20Sopenharmony_ci{
40948c2ecf20Sopenharmony_ci	struct devlink_param_item *param_item;
40958c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port;
40968c2ecf20Sopenharmony_ci	struct devlink *devlink;
40978c2ecf20Sopenharmony_ci	int start = cb->args[0];
40988c2ecf20Sopenharmony_ci	int idx = 0;
40998c2ecf20Sopenharmony_ci	int err = 0;
41008c2ecf20Sopenharmony_ci
41018c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
41028c2ecf20Sopenharmony_ci	list_for_each_entry(devlink, &devlink_list, list) {
41038c2ecf20Sopenharmony_ci		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
41048c2ecf20Sopenharmony_ci			continue;
41058c2ecf20Sopenharmony_ci		mutex_lock(&devlink->lock);
41068c2ecf20Sopenharmony_ci		list_for_each_entry(devlink_port, &devlink->port_list, list) {
41078c2ecf20Sopenharmony_ci			list_for_each_entry(param_item,
41088c2ecf20Sopenharmony_ci					    &devlink_port->param_list, list) {
41098c2ecf20Sopenharmony_ci				if (idx < start) {
41108c2ecf20Sopenharmony_ci					idx++;
41118c2ecf20Sopenharmony_ci					continue;
41128c2ecf20Sopenharmony_ci				}
41138c2ecf20Sopenharmony_ci				err = devlink_nl_param_fill(msg,
41148c2ecf20Sopenharmony_ci						devlink_port->devlink,
41158c2ecf20Sopenharmony_ci						devlink_port->index, param_item,
41168c2ecf20Sopenharmony_ci						DEVLINK_CMD_PORT_PARAM_GET,
41178c2ecf20Sopenharmony_ci						NETLINK_CB(cb->skb).portid,
41188c2ecf20Sopenharmony_ci						cb->nlh->nlmsg_seq,
41198c2ecf20Sopenharmony_ci						NLM_F_MULTI);
41208c2ecf20Sopenharmony_ci				if (err == -EOPNOTSUPP) {
41218c2ecf20Sopenharmony_ci					err = 0;
41228c2ecf20Sopenharmony_ci				} else if (err) {
41238c2ecf20Sopenharmony_ci					mutex_unlock(&devlink->lock);
41248c2ecf20Sopenharmony_ci					goto out;
41258c2ecf20Sopenharmony_ci				}
41268c2ecf20Sopenharmony_ci				idx++;
41278c2ecf20Sopenharmony_ci			}
41288c2ecf20Sopenharmony_ci		}
41298c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->lock);
41308c2ecf20Sopenharmony_ci	}
41318c2ecf20Sopenharmony_ciout:
41328c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
41338c2ecf20Sopenharmony_ci
41348c2ecf20Sopenharmony_ci	if (err != -EMSGSIZE)
41358c2ecf20Sopenharmony_ci		return err;
41368c2ecf20Sopenharmony_ci
41378c2ecf20Sopenharmony_ci	cb->args[0] = idx;
41388c2ecf20Sopenharmony_ci	return msg->len;
41398c2ecf20Sopenharmony_ci}
41408c2ecf20Sopenharmony_ci
41418c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
41428c2ecf20Sopenharmony_ci					      struct genl_info *info)
41438c2ecf20Sopenharmony_ci{
41448c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port = info->user_ptr[1];
41458c2ecf20Sopenharmony_ci	struct devlink_param_item *param_item;
41468c2ecf20Sopenharmony_ci	struct sk_buff *msg;
41478c2ecf20Sopenharmony_ci	int err;
41488c2ecf20Sopenharmony_ci
41498c2ecf20Sopenharmony_ci	param_item = devlink_param_get_from_info(&devlink_port->param_list,
41508c2ecf20Sopenharmony_ci						 info);
41518c2ecf20Sopenharmony_ci	if (!param_item)
41528c2ecf20Sopenharmony_ci		return -EINVAL;
41538c2ecf20Sopenharmony_ci
41548c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
41558c2ecf20Sopenharmony_ci	if (!msg)
41568c2ecf20Sopenharmony_ci		return -ENOMEM;
41578c2ecf20Sopenharmony_ci
41588c2ecf20Sopenharmony_ci	err = devlink_nl_param_fill(msg, devlink_port->devlink,
41598c2ecf20Sopenharmony_ci				    devlink_port->index, param_item,
41608c2ecf20Sopenharmony_ci				    DEVLINK_CMD_PORT_PARAM_GET,
41618c2ecf20Sopenharmony_ci				    info->snd_portid, info->snd_seq, 0);
41628c2ecf20Sopenharmony_ci	if (err) {
41638c2ecf20Sopenharmony_ci		nlmsg_free(msg);
41648c2ecf20Sopenharmony_ci		return err;
41658c2ecf20Sopenharmony_ci	}
41668c2ecf20Sopenharmony_ci
41678c2ecf20Sopenharmony_ci	return genlmsg_reply(msg, info);
41688c2ecf20Sopenharmony_ci}
41698c2ecf20Sopenharmony_ci
41708c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
41718c2ecf20Sopenharmony_ci					      struct genl_info *info)
41728c2ecf20Sopenharmony_ci{
41738c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port = info->user_ptr[1];
41748c2ecf20Sopenharmony_ci
41758c2ecf20Sopenharmony_ci	return __devlink_nl_cmd_param_set_doit(devlink_port->devlink,
41768c2ecf20Sopenharmony_ci					       devlink_port->index,
41778c2ecf20Sopenharmony_ci					       &devlink_port->param_list, info,
41788c2ecf20Sopenharmony_ci					       DEVLINK_CMD_PORT_PARAM_NEW);
41798c2ecf20Sopenharmony_ci}
41808c2ecf20Sopenharmony_ci
41818c2ecf20Sopenharmony_cistatic int devlink_nl_region_snapshot_id_put(struct sk_buff *msg,
41828c2ecf20Sopenharmony_ci					     struct devlink *devlink,
41838c2ecf20Sopenharmony_ci					     struct devlink_snapshot *snapshot)
41848c2ecf20Sopenharmony_ci{
41858c2ecf20Sopenharmony_ci	struct nlattr *snap_attr;
41868c2ecf20Sopenharmony_ci	int err;
41878c2ecf20Sopenharmony_ci
41888c2ecf20Sopenharmony_ci	snap_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_SNAPSHOT);
41898c2ecf20Sopenharmony_ci	if (!snap_attr)
41908c2ecf20Sopenharmony_ci		return -EINVAL;
41918c2ecf20Sopenharmony_ci
41928c2ecf20Sopenharmony_ci	err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID, snapshot->id);
41938c2ecf20Sopenharmony_ci	if (err)
41948c2ecf20Sopenharmony_ci		goto nla_put_failure;
41958c2ecf20Sopenharmony_ci
41968c2ecf20Sopenharmony_ci	nla_nest_end(msg, snap_attr);
41978c2ecf20Sopenharmony_ci	return 0;
41988c2ecf20Sopenharmony_ci
41998c2ecf20Sopenharmony_cinla_put_failure:
42008c2ecf20Sopenharmony_ci	nla_nest_cancel(msg, snap_attr);
42018c2ecf20Sopenharmony_ci	return err;
42028c2ecf20Sopenharmony_ci}
42038c2ecf20Sopenharmony_ci
42048c2ecf20Sopenharmony_cistatic int devlink_nl_region_snapshots_id_put(struct sk_buff *msg,
42058c2ecf20Sopenharmony_ci					      struct devlink *devlink,
42068c2ecf20Sopenharmony_ci					      struct devlink_region *region)
42078c2ecf20Sopenharmony_ci{
42088c2ecf20Sopenharmony_ci	struct devlink_snapshot *snapshot;
42098c2ecf20Sopenharmony_ci	struct nlattr *snapshots_attr;
42108c2ecf20Sopenharmony_ci	int err;
42118c2ecf20Sopenharmony_ci
42128c2ecf20Sopenharmony_ci	snapshots_attr = nla_nest_start_noflag(msg,
42138c2ecf20Sopenharmony_ci					       DEVLINK_ATTR_REGION_SNAPSHOTS);
42148c2ecf20Sopenharmony_ci	if (!snapshots_attr)
42158c2ecf20Sopenharmony_ci		return -EINVAL;
42168c2ecf20Sopenharmony_ci
42178c2ecf20Sopenharmony_ci	list_for_each_entry(snapshot, &region->snapshot_list, list) {
42188c2ecf20Sopenharmony_ci		err = devlink_nl_region_snapshot_id_put(msg, devlink, snapshot);
42198c2ecf20Sopenharmony_ci		if (err)
42208c2ecf20Sopenharmony_ci			goto nla_put_failure;
42218c2ecf20Sopenharmony_ci	}
42228c2ecf20Sopenharmony_ci
42238c2ecf20Sopenharmony_ci	nla_nest_end(msg, snapshots_attr);
42248c2ecf20Sopenharmony_ci	return 0;
42258c2ecf20Sopenharmony_ci
42268c2ecf20Sopenharmony_cinla_put_failure:
42278c2ecf20Sopenharmony_ci	nla_nest_cancel(msg, snapshots_attr);
42288c2ecf20Sopenharmony_ci	return err;
42298c2ecf20Sopenharmony_ci}
42308c2ecf20Sopenharmony_ci
42318c2ecf20Sopenharmony_cistatic int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
42328c2ecf20Sopenharmony_ci				  enum devlink_command cmd, u32 portid,
42338c2ecf20Sopenharmony_ci				  u32 seq, int flags,
42348c2ecf20Sopenharmony_ci				  struct devlink_region *region)
42358c2ecf20Sopenharmony_ci{
42368c2ecf20Sopenharmony_ci	void *hdr;
42378c2ecf20Sopenharmony_ci	int err;
42388c2ecf20Sopenharmony_ci
42398c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
42408c2ecf20Sopenharmony_ci	if (!hdr)
42418c2ecf20Sopenharmony_ci		return -EMSGSIZE;
42428c2ecf20Sopenharmony_ci
42438c2ecf20Sopenharmony_ci	err = devlink_nl_put_handle(msg, devlink);
42448c2ecf20Sopenharmony_ci	if (err)
42458c2ecf20Sopenharmony_ci		goto nla_put_failure;
42468c2ecf20Sopenharmony_ci
42478c2ecf20Sopenharmony_ci	if (region->port) {
42488c2ecf20Sopenharmony_ci		err = nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX,
42498c2ecf20Sopenharmony_ci				  region->port->index);
42508c2ecf20Sopenharmony_ci		if (err)
42518c2ecf20Sopenharmony_ci			goto nla_put_failure;
42528c2ecf20Sopenharmony_ci	}
42538c2ecf20Sopenharmony_ci
42548c2ecf20Sopenharmony_ci	err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME, region->ops->name);
42558c2ecf20Sopenharmony_ci	if (err)
42568c2ecf20Sopenharmony_ci		goto nla_put_failure;
42578c2ecf20Sopenharmony_ci
42588c2ecf20Sopenharmony_ci	err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
42598c2ecf20Sopenharmony_ci				region->size,
42608c2ecf20Sopenharmony_ci				DEVLINK_ATTR_PAD);
42618c2ecf20Sopenharmony_ci	if (err)
42628c2ecf20Sopenharmony_ci		goto nla_put_failure;
42638c2ecf20Sopenharmony_ci
42648c2ecf20Sopenharmony_ci	err = devlink_nl_region_snapshots_id_put(msg, devlink, region);
42658c2ecf20Sopenharmony_ci	if (err)
42668c2ecf20Sopenharmony_ci		goto nla_put_failure;
42678c2ecf20Sopenharmony_ci
42688c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
42698c2ecf20Sopenharmony_ci	return 0;
42708c2ecf20Sopenharmony_ci
42718c2ecf20Sopenharmony_cinla_put_failure:
42728c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
42738c2ecf20Sopenharmony_ci	return err;
42748c2ecf20Sopenharmony_ci}
42758c2ecf20Sopenharmony_ci
42768c2ecf20Sopenharmony_cistatic struct sk_buff *
42778c2ecf20Sopenharmony_cidevlink_nl_region_notify_build(struct devlink_region *region,
42788c2ecf20Sopenharmony_ci			       struct devlink_snapshot *snapshot,
42798c2ecf20Sopenharmony_ci			       enum devlink_command cmd, u32 portid, u32 seq)
42808c2ecf20Sopenharmony_ci{
42818c2ecf20Sopenharmony_ci	struct devlink *devlink = region->devlink;
42828c2ecf20Sopenharmony_ci	struct sk_buff *msg;
42838c2ecf20Sopenharmony_ci	void *hdr;
42848c2ecf20Sopenharmony_ci	int err;
42858c2ecf20Sopenharmony_ci
42868c2ecf20Sopenharmony_ci
42878c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
42888c2ecf20Sopenharmony_ci	if (!msg)
42898c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
42908c2ecf20Sopenharmony_ci
42918c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, 0, cmd);
42928c2ecf20Sopenharmony_ci	if (!hdr) {
42938c2ecf20Sopenharmony_ci		err = -EMSGSIZE;
42948c2ecf20Sopenharmony_ci		goto out_free_msg;
42958c2ecf20Sopenharmony_ci	}
42968c2ecf20Sopenharmony_ci
42978c2ecf20Sopenharmony_ci	err = devlink_nl_put_handle(msg, devlink);
42988c2ecf20Sopenharmony_ci	if (err)
42998c2ecf20Sopenharmony_ci		goto out_cancel_msg;
43008c2ecf20Sopenharmony_ci
43018c2ecf20Sopenharmony_ci	if (region->port) {
43028c2ecf20Sopenharmony_ci		err = nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX,
43038c2ecf20Sopenharmony_ci				  region->port->index);
43048c2ecf20Sopenharmony_ci		if (err)
43058c2ecf20Sopenharmony_ci			goto out_cancel_msg;
43068c2ecf20Sopenharmony_ci	}
43078c2ecf20Sopenharmony_ci
43088c2ecf20Sopenharmony_ci	err = nla_put_string(msg, DEVLINK_ATTR_REGION_NAME,
43098c2ecf20Sopenharmony_ci			     region->ops->name);
43108c2ecf20Sopenharmony_ci	if (err)
43118c2ecf20Sopenharmony_ci		goto out_cancel_msg;
43128c2ecf20Sopenharmony_ci
43138c2ecf20Sopenharmony_ci	if (snapshot) {
43148c2ecf20Sopenharmony_ci		err = nla_put_u32(msg, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
43158c2ecf20Sopenharmony_ci				  snapshot->id);
43168c2ecf20Sopenharmony_ci		if (err)
43178c2ecf20Sopenharmony_ci			goto out_cancel_msg;
43188c2ecf20Sopenharmony_ci	} else {
43198c2ecf20Sopenharmony_ci		err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_SIZE,
43208c2ecf20Sopenharmony_ci					region->size, DEVLINK_ATTR_PAD);
43218c2ecf20Sopenharmony_ci		if (err)
43228c2ecf20Sopenharmony_ci			goto out_cancel_msg;
43238c2ecf20Sopenharmony_ci	}
43248c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
43258c2ecf20Sopenharmony_ci
43268c2ecf20Sopenharmony_ci	return msg;
43278c2ecf20Sopenharmony_ci
43288c2ecf20Sopenharmony_ciout_cancel_msg:
43298c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
43308c2ecf20Sopenharmony_ciout_free_msg:
43318c2ecf20Sopenharmony_ci	nlmsg_free(msg);
43328c2ecf20Sopenharmony_ci	return ERR_PTR(err);
43338c2ecf20Sopenharmony_ci}
43348c2ecf20Sopenharmony_ci
43358c2ecf20Sopenharmony_cistatic void devlink_nl_region_notify(struct devlink_region *region,
43368c2ecf20Sopenharmony_ci				     struct devlink_snapshot *snapshot,
43378c2ecf20Sopenharmony_ci				     enum devlink_command cmd)
43388c2ecf20Sopenharmony_ci{
43398c2ecf20Sopenharmony_ci	struct devlink *devlink = region->devlink;
43408c2ecf20Sopenharmony_ci	struct sk_buff *msg;
43418c2ecf20Sopenharmony_ci
43428c2ecf20Sopenharmony_ci	WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
43438c2ecf20Sopenharmony_ci
43448c2ecf20Sopenharmony_ci	msg = devlink_nl_region_notify_build(region, snapshot, cmd, 0, 0);
43458c2ecf20Sopenharmony_ci	if (IS_ERR(msg))
43468c2ecf20Sopenharmony_ci		return;
43478c2ecf20Sopenharmony_ci
43488c2ecf20Sopenharmony_ci	genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
43498c2ecf20Sopenharmony_ci				msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
43508c2ecf20Sopenharmony_ci}
43518c2ecf20Sopenharmony_ci
43528c2ecf20Sopenharmony_ci/**
43538c2ecf20Sopenharmony_ci * __devlink_snapshot_id_increment - Increment number of snapshots using an id
43548c2ecf20Sopenharmony_ci *	@devlink: devlink instance
43558c2ecf20Sopenharmony_ci *	@id: the snapshot id
43568c2ecf20Sopenharmony_ci *
43578c2ecf20Sopenharmony_ci *	Track when a new snapshot begins using an id. Load the count for the
43588c2ecf20Sopenharmony_ci *	given id from the snapshot xarray, increment it, and store it back.
43598c2ecf20Sopenharmony_ci *
43608c2ecf20Sopenharmony_ci *	Called when a new snapshot is created with the given id.
43618c2ecf20Sopenharmony_ci *
43628c2ecf20Sopenharmony_ci *	The id *must* have been previously allocated by
43638c2ecf20Sopenharmony_ci *	devlink_region_snapshot_id_get().
43648c2ecf20Sopenharmony_ci *
43658c2ecf20Sopenharmony_ci *	Returns 0 on success, or an error on failure.
43668c2ecf20Sopenharmony_ci */
43678c2ecf20Sopenharmony_cistatic int __devlink_snapshot_id_increment(struct devlink *devlink, u32 id)
43688c2ecf20Sopenharmony_ci{
43698c2ecf20Sopenharmony_ci	unsigned long count;
43708c2ecf20Sopenharmony_ci	void *p;
43718c2ecf20Sopenharmony_ci
43728c2ecf20Sopenharmony_ci	lockdep_assert_held(&devlink->lock);
43738c2ecf20Sopenharmony_ci
43748c2ecf20Sopenharmony_ci	p = xa_load(&devlink->snapshot_ids, id);
43758c2ecf20Sopenharmony_ci	if (WARN_ON(!p))
43768c2ecf20Sopenharmony_ci		return -EINVAL;
43778c2ecf20Sopenharmony_ci
43788c2ecf20Sopenharmony_ci	if (WARN_ON(!xa_is_value(p)))
43798c2ecf20Sopenharmony_ci		return -EINVAL;
43808c2ecf20Sopenharmony_ci
43818c2ecf20Sopenharmony_ci	count = xa_to_value(p);
43828c2ecf20Sopenharmony_ci	count++;
43838c2ecf20Sopenharmony_ci
43848c2ecf20Sopenharmony_ci	return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
43858c2ecf20Sopenharmony_ci			       GFP_KERNEL));
43868c2ecf20Sopenharmony_ci}
43878c2ecf20Sopenharmony_ci
43888c2ecf20Sopenharmony_ci/**
43898c2ecf20Sopenharmony_ci * __devlink_snapshot_id_decrement - Decrease number of snapshots using an id
43908c2ecf20Sopenharmony_ci *	@devlink: devlink instance
43918c2ecf20Sopenharmony_ci *	@id: the snapshot id
43928c2ecf20Sopenharmony_ci *
43938c2ecf20Sopenharmony_ci *	Track when a snapshot is deleted and stops using an id. Load the count
43948c2ecf20Sopenharmony_ci *	for the given id from the snapshot xarray, decrement it, and store it
43958c2ecf20Sopenharmony_ci *	back.
43968c2ecf20Sopenharmony_ci *
43978c2ecf20Sopenharmony_ci *	If the count reaches zero, erase this id from the xarray, freeing it
43988c2ecf20Sopenharmony_ci *	up for future re-use by devlink_region_snapshot_id_get().
43998c2ecf20Sopenharmony_ci *
44008c2ecf20Sopenharmony_ci *	Called when a snapshot using the given id is deleted, and when the
44018c2ecf20Sopenharmony_ci *	initial allocator of the id is finished using it.
44028c2ecf20Sopenharmony_ci */
44038c2ecf20Sopenharmony_cistatic void __devlink_snapshot_id_decrement(struct devlink *devlink, u32 id)
44048c2ecf20Sopenharmony_ci{
44058c2ecf20Sopenharmony_ci	unsigned long count;
44068c2ecf20Sopenharmony_ci	void *p;
44078c2ecf20Sopenharmony_ci
44088c2ecf20Sopenharmony_ci	lockdep_assert_held(&devlink->lock);
44098c2ecf20Sopenharmony_ci
44108c2ecf20Sopenharmony_ci	p = xa_load(&devlink->snapshot_ids, id);
44118c2ecf20Sopenharmony_ci	if (WARN_ON(!p))
44128c2ecf20Sopenharmony_ci		return;
44138c2ecf20Sopenharmony_ci
44148c2ecf20Sopenharmony_ci	if (WARN_ON(!xa_is_value(p)))
44158c2ecf20Sopenharmony_ci		return;
44168c2ecf20Sopenharmony_ci
44178c2ecf20Sopenharmony_ci	count = xa_to_value(p);
44188c2ecf20Sopenharmony_ci
44198c2ecf20Sopenharmony_ci	if (count > 1) {
44208c2ecf20Sopenharmony_ci		count--;
44218c2ecf20Sopenharmony_ci		xa_store(&devlink->snapshot_ids, id, xa_mk_value(count),
44228c2ecf20Sopenharmony_ci			 GFP_KERNEL);
44238c2ecf20Sopenharmony_ci	} else {
44248c2ecf20Sopenharmony_ci		/* If this was the last user, we can erase this id */
44258c2ecf20Sopenharmony_ci		xa_erase(&devlink->snapshot_ids, id);
44268c2ecf20Sopenharmony_ci	}
44278c2ecf20Sopenharmony_ci}
44288c2ecf20Sopenharmony_ci
44298c2ecf20Sopenharmony_ci/**
44308c2ecf20Sopenharmony_ci *	__devlink_snapshot_id_insert - Insert a specific snapshot ID
44318c2ecf20Sopenharmony_ci *	@devlink: devlink instance
44328c2ecf20Sopenharmony_ci *	@id: the snapshot id
44338c2ecf20Sopenharmony_ci *
44348c2ecf20Sopenharmony_ci *	Mark the given snapshot id as used by inserting a zero value into the
44358c2ecf20Sopenharmony_ci *	snapshot xarray.
44368c2ecf20Sopenharmony_ci *
44378c2ecf20Sopenharmony_ci *	This must be called while holding the devlink instance lock. Unlike
44388c2ecf20Sopenharmony_ci *	devlink_snapshot_id_get, the initial reference count is zero, not one.
44398c2ecf20Sopenharmony_ci *	It is expected that the id will immediately be used before
44408c2ecf20Sopenharmony_ci *	releasing the devlink instance lock.
44418c2ecf20Sopenharmony_ci *
44428c2ecf20Sopenharmony_ci *	Returns zero on success, or an error code if the snapshot id could not
44438c2ecf20Sopenharmony_ci *	be inserted.
44448c2ecf20Sopenharmony_ci */
44458c2ecf20Sopenharmony_cistatic int __devlink_snapshot_id_insert(struct devlink *devlink, u32 id)
44468c2ecf20Sopenharmony_ci{
44478c2ecf20Sopenharmony_ci	lockdep_assert_held(&devlink->lock);
44488c2ecf20Sopenharmony_ci
44498c2ecf20Sopenharmony_ci	if (xa_load(&devlink->snapshot_ids, id))
44508c2ecf20Sopenharmony_ci		return -EEXIST;
44518c2ecf20Sopenharmony_ci
44528c2ecf20Sopenharmony_ci	return xa_err(xa_store(&devlink->snapshot_ids, id, xa_mk_value(0),
44538c2ecf20Sopenharmony_ci			       GFP_KERNEL));
44548c2ecf20Sopenharmony_ci}
44558c2ecf20Sopenharmony_ci
44568c2ecf20Sopenharmony_ci/**
44578c2ecf20Sopenharmony_ci *	__devlink_region_snapshot_id_get - get snapshot ID
44588c2ecf20Sopenharmony_ci *	@devlink: devlink instance
44598c2ecf20Sopenharmony_ci *	@id: storage to return snapshot id
44608c2ecf20Sopenharmony_ci *
44618c2ecf20Sopenharmony_ci *	Allocates a new snapshot id. Returns zero on success, or a negative
44628c2ecf20Sopenharmony_ci *	error on failure. Must be called while holding the devlink instance
44638c2ecf20Sopenharmony_ci *	lock.
44648c2ecf20Sopenharmony_ci *
44658c2ecf20Sopenharmony_ci *	Snapshot IDs are tracked using an xarray which stores the number of
44668c2ecf20Sopenharmony_ci *	users of the snapshot id.
44678c2ecf20Sopenharmony_ci *
44688c2ecf20Sopenharmony_ci *	Note that the caller of this function counts as a 'user', in order to
44698c2ecf20Sopenharmony_ci *	avoid race conditions. The caller must release its hold on the
44708c2ecf20Sopenharmony_ci *	snapshot by using devlink_region_snapshot_id_put.
44718c2ecf20Sopenharmony_ci */
44728c2ecf20Sopenharmony_cistatic int __devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
44738c2ecf20Sopenharmony_ci{
44748c2ecf20Sopenharmony_ci	lockdep_assert_held(&devlink->lock);
44758c2ecf20Sopenharmony_ci
44768c2ecf20Sopenharmony_ci	return xa_alloc(&devlink->snapshot_ids, id, xa_mk_value(1),
44778c2ecf20Sopenharmony_ci			xa_limit_32b, GFP_KERNEL);
44788c2ecf20Sopenharmony_ci}
44798c2ecf20Sopenharmony_ci
44808c2ecf20Sopenharmony_ci/**
44818c2ecf20Sopenharmony_ci *	__devlink_region_snapshot_create - create a new snapshot
44828c2ecf20Sopenharmony_ci *	This will add a new snapshot of a region. The snapshot
44838c2ecf20Sopenharmony_ci *	will be stored on the region struct and can be accessed
44848c2ecf20Sopenharmony_ci *	from devlink. This is useful for future analyses of snapshots.
44858c2ecf20Sopenharmony_ci *	Multiple snapshots can be created on a region.
44868c2ecf20Sopenharmony_ci *	The @snapshot_id should be obtained using the getter function.
44878c2ecf20Sopenharmony_ci *
44888c2ecf20Sopenharmony_ci *	Must be called only while holding the devlink instance lock.
44898c2ecf20Sopenharmony_ci *
44908c2ecf20Sopenharmony_ci *	@region: devlink region of the snapshot
44918c2ecf20Sopenharmony_ci *	@data: snapshot data
44928c2ecf20Sopenharmony_ci *	@snapshot_id: snapshot id to be created
44938c2ecf20Sopenharmony_ci */
44948c2ecf20Sopenharmony_cistatic int
44958c2ecf20Sopenharmony_ci__devlink_region_snapshot_create(struct devlink_region *region,
44968c2ecf20Sopenharmony_ci				 u8 *data, u32 snapshot_id)
44978c2ecf20Sopenharmony_ci{
44988c2ecf20Sopenharmony_ci	struct devlink *devlink = region->devlink;
44998c2ecf20Sopenharmony_ci	struct devlink_snapshot *snapshot;
45008c2ecf20Sopenharmony_ci	int err;
45018c2ecf20Sopenharmony_ci
45028c2ecf20Sopenharmony_ci	lockdep_assert_held(&devlink->lock);
45038c2ecf20Sopenharmony_ci
45048c2ecf20Sopenharmony_ci	/* check if region can hold one more snapshot */
45058c2ecf20Sopenharmony_ci	if (region->cur_snapshots == region->max_snapshots)
45068c2ecf20Sopenharmony_ci		return -ENOSPC;
45078c2ecf20Sopenharmony_ci
45088c2ecf20Sopenharmony_ci	if (devlink_region_snapshot_get_by_id(region, snapshot_id))
45098c2ecf20Sopenharmony_ci		return -EEXIST;
45108c2ecf20Sopenharmony_ci
45118c2ecf20Sopenharmony_ci	snapshot = kzalloc(sizeof(*snapshot), GFP_KERNEL);
45128c2ecf20Sopenharmony_ci	if (!snapshot)
45138c2ecf20Sopenharmony_ci		return -ENOMEM;
45148c2ecf20Sopenharmony_ci
45158c2ecf20Sopenharmony_ci	err = __devlink_snapshot_id_increment(devlink, snapshot_id);
45168c2ecf20Sopenharmony_ci	if (err)
45178c2ecf20Sopenharmony_ci		goto err_snapshot_id_increment;
45188c2ecf20Sopenharmony_ci
45198c2ecf20Sopenharmony_ci	snapshot->id = snapshot_id;
45208c2ecf20Sopenharmony_ci	snapshot->region = region;
45218c2ecf20Sopenharmony_ci	snapshot->data = data;
45228c2ecf20Sopenharmony_ci
45238c2ecf20Sopenharmony_ci	list_add_tail(&snapshot->list, &region->snapshot_list);
45248c2ecf20Sopenharmony_ci
45258c2ecf20Sopenharmony_ci	region->cur_snapshots++;
45268c2ecf20Sopenharmony_ci
45278c2ecf20Sopenharmony_ci	devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_NEW);
45288c2ecf20Sopenharmony_ci	return 0;
45298c2ecf20Sopenharmony_ci
45308c2ecf20Sopenharmony_cierr_snapshot_id_increment:
45318c2ecf20Sopenharmony_ci	kfree(snapshot);
45328c2ecf20Sopenharmony_ci	return err;
45338c2ecf20Sopenharmony_ci}
45348c2ecf20Sopenharmony_ci
45358c2ecf20Sopenharmony_cistatic void devlink_region_snapshot_del(struct devlink_region *region,
45368c2ecf20Sopenharmony_ci					struct devlink_snapshot *snapshot)
45378c2ecf20Sopenharmony_ci{
45388c2ecf20Sopenharmony_ci	struct devlink *devlink = region->devlink;
45398c2ecf20Sopenharmony_ci
45408c2ecf20Sopenharmony_ci	lockdep_assert_held(&devlink->lock);
45418c2ecf20Sopenharmony_ci
45428c2ecf20Sopenharmony_ci	devlink_nl_region_notify(region, snapshot, DEVLINK_CMD_REGION_DEL);
45438c2ecf20Sopenharmony_ci	region->cur_snapshots--;
45448c2ecf20Sopenharmony_ci	list_del(&snapshot->list);
45458c2ecf20Sopenharmony_ci	region->ops->destructor(snapshot->data);
45468c2ecf20Sopenharmony_ci	__devlink_snapshot_id_decrement(devlink, snapshot->id);
45478c2ecf20Sopenharmony_ci	kfree(snapshot);
45488c2ecf20Sopenharmony_ci}
45498c2ecf20Sopenharmony_ci
45508c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_region_get_doit(struct sk_buff *skb,
45518c2ecf20Sopenharmony_ci					  struct genl_info *info)
45528c2ecf20Sopenharmony_ci{
45538c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
45548c2ecf20Sopenharmony_ci	struct devlink_port *port = NULL;
45558c2ecf20Sopenharmony_ci	struct devlink_region *region;
45568c2ecf20Sopenharmony_ci	const char *region_name;
45578c2ecf20Sopenharmony_ci	struct sk_buff *msg;
45588c2ecf20Sopenharmony_ci	unsigned int index;
45598c2ecf20Sopenharmony_ci	int err;
45608c2ecf20Sopenharmony_ci
45618c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_REGION_NAME])
45628c2ecf20Sopenharmony_ci		return -EINVAL;
45638c2ecf20Sopenharmony_ci
45648c2ecf20Sopenharmony_ci	if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
45658c2ecf20Sopenharmony_ci		index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
45668c2ecf20Sopenharmony_ci
45678c2ecf20Sopenharmony_ci		port = devlink_port_get_by_index(devlink, index);
45688c2ecf20Sopenharmony_ci		if (!port)
45698c2ecf20Sopenharmony_ci			return -ENODEV;
45708c2ecf20Sopenharmony_ci	}
45718c2ecf20Sopenharmony_ci
45728c2ecf20Sopenharmony_ci	region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
45738c2ecf20Sopenharmony_ci	if (port)
45748c2ecf20Sopenharmony_ci		region = devlink_port_region_get_by_name(port, region_name);
45758c2ecf20Sopenharmony_ci	else
45768c2ecf20Sopenharmony_ci		region = devlink_region_get_by_name(devlink, region_name);
45778c2ecf20Sopenharmony_ci
45788c2ecf20Sopenharmony_ci	if (!region)
45798c2ecf20Sopenharmony_ci		return -EINVAL;
45808c2ecf20Sopenharmony_ci
45818c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
45828c2ecf20Sopenharmony_ci	if (!msg)
45838c2ecf20Sopenharmony_ci		return -ENOMEM;
45848c2ecf20Sopenharmony_ci
45858c2ecf20Sopenharmony_ci	err = devlink_nl_region_fill(msg, devlink, DEVLINK_CMD_REGION_GET,
45868c2ecf20Sopenharmony_ci				     info->snd_portid, info->snd_seq, 0,
45878c2ecf20Sopenharmony_ci				     region);
45888c2ecf20Sopenharmony_ci	if (err) {
45898c2ecf20Sopenharmony_ci		nlmsg_free(msg);
45908c2ecf20Sopenharmony_ci		return err;
45918c2ecf20Sopenharmony_ci	}
45928c2ecf20Sopenharmony_ci
45938c2ecf20Sopenharmony_ci	return genlmsg_reply(msg, info);
45948c2ecf20Sopenharmony_ci}
45958c2ecf20Sopenharmony_ci
45968c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_region_get_port_dumpit(struct sk_buff *msg,
45978c2ecf20Sopenharmony_ci						 struct netlink_callback *cb,
45988c2ecf20Sopenharmony_ci						 struct devlink_port *port,
45998c2ecf20Sopenharmony_ci						 int *idx,
46008c2ecf20Sopenharmony_ci						 int start)
46018c2ecf20Sopenharmony_ci{
46028c2ecf20Sopenharmony_ci	struct devlink_region *region;
46038c2ecf20Sopenharmony_ci	int err = 0;
46048c2ecf20Sopenharmony_ci
46058c2ecf20Sopenharmony_ci	list_for_each_entry(region, &port->region_list, list) {
46068c2ecf20Sopenharmony_ci		if (*idx < start) {
46078c2ecf20Sopenharmony_ci			(*idx)++;
46088c2ecf20Sopenharmony_ci			continue;
46098c2ecf20Sopenharmony_ci		}
46108c2ecf20Sopenharmony_ci		err = devlink_nl_region_fill(msg, port->devlink,
46118c2ecf20Sopenharmony_ci					     DEVLINK_CMD_REGION_GET,
46128c2ecf20Sopenharmony_ci					     NETLINK_CB(cb->skb).portid,
46138c2ecf20Sopenharmony_ci					     cb->nlh->nlmsg_seq,
46148c2ecf20Sopenharmony_ci					     NLM_F_MULTI, region);
46158c2ecf20Sopenharmony_ci		if (err)
46168c2ecf20Sopenharmony_ci			goto out;
46178c2ecf20Sopenharmony_ci		(*idx)++;
46188c2ecf20Sopenharmony_ci	}
46198c2ecf20Sopenharmony_ci
46208c2ecf20Sopenharmony_ciout:
46218c2ecf20Sopenharmony_ci	return err;
46228c2ecf20Sopenharmony_ci}
46238c2ecf20Sopenharmony_ci
46248c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_region_get_devlink_dumpit(struct sk_buff *msg,
46258c2ecf20Sopenharmony_ci						    struct netlink_callback *cb,
46268c2ecf20Sopenharmony_ci						    struct devlink *devlink,
46278c2ecf20Sopenharmony_ci						    int *idx,
46288c2ecf20Sopenharmony_ci						    int start)
46298c2ecf20Sopenharmony_ci{
46308c2ecf20Sopenharmony_ci	struct devlink_region *region;
46318c2ecf20Sopenharmony_ci	struct devlink_port *port;
46328c2ecf20Sopenharmony_ci	int err = 0;
46338c2ecf20Sopenharmony_ci
46348c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
46358c2ecf20Sopenharmony_ci	list_for_each_entry(region, &devlink->region_list, list) {
46368c2ecf20Sopenharmony_ci		if (*idx < start) {
46378c2ecf20Sopenharmony_ci			(*idx)++;
46388c2ecf20Sopenharmony_ci			continue;
46398c2ecf20Sopenharmony_ci		}
46408c2ecf20Sopenharmony_ci		err = devlink_nl_region_fill(msg, devlink,
46418c2ecf20Sopenharmony_ci					     DEVLINK_CMD_REGION_GET,
46428c2ecf20Sopenharmony_ci					     NETLINK_CB(cb->skb).portid,
46438c2ecf20Sopenharmony_ci					     cb->nlh->nlmsg_seq,
46448c2ecf20Sopenharmony_ci					     NLM_F_MULTI, region);
46458c2ecf20Sopenharmony_ci		if (err)
46468c2ecf20Sopenharmony_ci			goto out;
46478c2ecf20Sopenharmony_ci		(*idx)++;
46488c2ecf20Sopenharmony_ci	}
46498c2ecf20Sopenharmony_ci
46508c2ecf20Sopenharmony_ci	list_for_each_entry(port, &devlink->port_list, list) {
46518c2ecf20Sopenharmony_ci		err = devlink_nl_cmd_region_get_port_dumpit(msg, cb, port, idx,
46528c2ecf20Sopenharmony_ci							    start);
46538c2ecf20Sopenharmony_ci		if (err)
46548c2ecf20Sopenharmony_ci			goto out;
46558c2ecf20Sopenharmony_ci	}
46568c2ecf20Sopenharmony_ci
46578c2ecf20Sopenharmony_ciout:
46588c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
46598c2ecf20Sopenharmony_ci	return err;
46608c2ecf20Sopenharmony_ci}
46618c2ecf20Sopenharmony_ci
46628c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_region_get_dumpit(struct sk_buff *msg,
46638c2ecf20Sopenharmony_ci					    struct netlink_callback *cb)
46648c2ecf20Sopenharmony_ci{
46658c2ecf20Sopenharmony_ci	struct devlink *devlink;
46668c2ecf20Sopenharmony_ci	int start = cb->args[0];
46678c2ecf20Sopenharmony_ci	int idx = 0;
46688c2ecf20Sopenharmony_ci	int err;
46698c2ecf20Sopenharmony_ci
46708c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
46718c2ecf20Sopenharmony_ci	list_for_each_entry(devlink, &devlink_list, list) {
46728c2ecf20Sopenharmony_ci		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
46738c2ecf20Sopenharmony_ci			continue;
46748c2ecf20Sopenharmony_ci		err = devlink_nl_cmd_region_get_devlink_dumpit(msg, cb, devlink,
46758c2ecf20Sopenharmony_ci							       &idx, start);
46768c2ecf20Sopenharmony_ci		if (err)
46778c2ecf20Sopenharmony_ci			goto out;
46788c2ecf20Sopenharmony_ci	}
46798c2ecf20Sopenharmony_ciout:
46808c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
46818c2ecf20Sopenharmony_ci	cb->args[0] = idx;
46828c2ecf20Sopenharmony_ci	return msg->len;
46838c2ecf20Sopenharmony_ci}
46848c2ecf20Sopenharmony_ci
46858c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_region_del(struct sk_buff *skb,
46868c2ecf20Sopenharmony_ci				     struct genl_info *info)
46878c2ecf20Sopenharmony_ci{
46888c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
46898c2ecf20Sopenharmony_ci	struct devlink_snapshot *snapshot;
46908c2ecf20Sopenharmony_ci	struct devlink_port *port = NULL;
46918c2ecf20Sopenharmony_ci	struct devlink_region *region;
46928c2ecf20Sopenharmony_ci	const char *region_name;
46938c2ecf20Sopenharmony_ci	unsigned int index;
46948c2ecf20Sopenharmony_ci	u32 snapshot_id;
46958c2ecf20Sopenharmony_ci
46968c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_REGION_NAME] ||
46978c2ecf20Sopenharmony_ci	    !info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
46988c2ecf20Sopenharmony_ci		return -EINVAL;
46998c2ecf20Sopenharmony_ci
47008c2ecf20Sopenharmony_ci	region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
47018c2ecf20Sopenharmony_ci	snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
47028c2ecf20Sopenharmony_ci
47038c2ecf20Sopenharmony_ci	if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
47048c2ecf20Sopenharmony_ci		index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
47058c2ecf20Sopenharmony_ci
47068c2ecf20Sopenharmony_ci		port = devlink_port_get_by_index(devlink, index);
47078c2ecf20Sopenharmony_ci		if (!port)
47088c2ecf20Sopenharmony_ci			return -ENODEV;
47098c2ecf20Sopenharmony_ci	}
47108c2ecf20Sopenharmony_ci
47118c2ecf20Sopenharmony_ci	if (port)
47128c2ecf20Sopenharmony_ci		region = devlink_port_region_get_by_name(port, region_name);
47138c2ecf20Sopenharmony_ci	else
47148c2ecf20Sopenharmony_ci		region = devlink_region_get_by_name(devlink, region_name);
47158c2ecf20Sopenharmony_ci
47168c2ecf20Sopenharmony_ci	if (!region)
47178c2ecf20Sopenharmony_ci		return -EINVAL;
47188c2ecf20Sopenharmony_ci
47198c2ecf20Sopenharmony_ci	snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
47208c2ecf20Sopenharmony_ci	if (!snapshot)
47218c2ecf20Sopenharmony_ci		return -EINVAL;
47228c2ecf20Sopenharmony_ci
47238c2ecf20Sopenharmony_ci	devlink_region_snapshot_del(region, snapshot);
47248c2ecf20Sopenharmony_ci	return 0;
47258c2ecf20Sopenharmony_ci}
47268c2ecf20Sopenharmony_ci
47278c2ecf20Sopenharmony_cistatic int
47288c2ecf20Sopenharmony_cidevlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
47298c2ecf20Sopenharmony_ci{
47308c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
47318c2ecf20Sopenharmony_ci	struct devlink_snapshot *snapshot;
47328c2ecf20Sopenharmony_ci	struct devlink_port *port = NULL;
47338c2ecf20Sopenharmony_ci	struct nlattr *snapshot_id_attr;
47348c2ecf20Sopenharmony_ci	struct devlink_region *region;
47358c2ecf20Sopenharmony_ci	const char *region_name;
47368c2ecf20Sopenharmony_ci	unsigned int index;
47378c2ecf20Sopenharmony_ci	u32 snapshot_id;
47388c2ecf20Sopenharmony_ci	u8 *data;
47398c2ecf20Sopenharmony_ci	int err;
47408c2ecf20Sopenharmony_ci
47418c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_REGION_NAME]) {
47428c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(info->extack, "No region name provided");
47438c2ecf20Sopenharmony_ci		return -EINVAL;
47448c2ecf20Sopenharmony_ci	}
47458c2ecf20Sopenharmony_ci
47468c2ecf20Sopenharmony_ci	region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
47478c2ecf20Sopenharmony_ci
47488c2ecf20Sopenharmony_ci	if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
47498c2ecf20Sopenharmony_ci		index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
47508c2ecf20Sopenharmony_ci
47518c2ecf20Sopenharmony_ci		port = devlink_port_get_by_index(devlink, index);
47528c2ecf20Sopenharmony_ci		if (!port)
47538c2ecf20Sopenharmony_ci			return -ENODEV;
47548c2ecf20Sopenharmony_ci	}
47558c2ecf20Sopenharmony_ci
47568c2ecf20Sopenharmony_ci	if (port)
47578c2ecf20Sopenharmony_ci		region = devlink_port_region_get_by_name(port, region_name);
47588c2ecf20Sopenharmony_ci	else
47598c2ecf20Sopenharmony_ci		region = devlink_region_get_by_name(devlink, region_name);
47608c2ecf20Sopenharmony_ci
47618c2ecf20Sopenharmony_ci	if (!region) {
47628c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not exist");
47638c2ecf20Sopenharmony_ci		return -EINVAL;
47648c2ecf20Sopenharmony_ci	}
47658c2ecf20Sopenharmony_ci
47668c2ecf20Sopenharmony_ci	if (!region->ops->snapshot) {
47678c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(info->extack, "The requested region does not support taking an immediate snapshot");
47688c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
47698c2ecf20Sopenharmony_ci	}
47708c2ecf20Sopenharmony_ci
47718c2ecf20Sopenharmony_ci	if (region->cur_snapshots == region->max_snapshots) {
47728c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(info->extack, "The region has reached the maximum number of stored snapshots");
47738c2ecf20Sopenharmony_ci		return -ENOSPC;
47748c2ecf20Sopenharmony_ci	}
47758c2ecf20Sopenharmony_ci
47768c2ecf20Sopenharmony_ci	snapshot_id_attr = info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID];
47778c2ecf20Sopenharmony_ci	if (snapshot_id_attr) {
47788c2ecf20Sopenharmony_ci		snapshot_id = nla_get_u32(snapshot_id_attr);
47798c2ecf20Sopenharmony_ci
47808c2ecf20Sopenharmony_ci		if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
47818c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(info->extack, "The requested snapshot id is already in use");
47828c2ecf20Sopenharmony_ci			return -EEXIST;
47838c2ecf20Sopenharmony_ci		}
47848c2ecf20Sopenharmony_ci
47858c2ecf20Sopenharmony_ci		err = __devlink_snapshot_id_insert(devlink, snapshot_id);
47868c2ecf20Sopenharmony_ci		if (err)
47878c2ecf20Sopenharmony_ci			return err;
47888c2ecf20Sopenharmony_ci	} else {
47898c2ecf20Sopenharmony_ci		err = __devlink_region_snapshot_id_get(devlink, &snapshot_id);
47908c2ecf20Sopenharmony_ci		if (err) {
47918c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(info->extack, "Failed to allocate a new snapshot id");
47928c2ecf20Sopenharmony_ci			return err;
47938c2ecf20Sopenharmony_ci		}
47948c2ecf20Sopenharmony_ci	}
47958c2ecf20Sopenharmony_ci
47968c2ecf20Sopenharmony_ci	if (port)
47978c2ecf20Sopenharmony_ci		err = region->port_ops->snapshot(port, region->port_ops,
47988c2ecf20Sopenharmony_ci						 info->extack, &data);
47998c2ecf20Sopenharmony_ci	else
48008c2ecf20Sopenharmony_ci		err = region->ops->snapshot(devlink, region->ops,
48018c2ecf20Sopenharmony_ci					    info->extack, &data);
48028c2ecf20Sopenharmony_ci	if (err)
48038c2ecf20Sopenharmony_ci		goto err_snapshot_capture;
48048c2ecf20Sopenharmony_ci
48058c2ecf20Sopenharmony_ci	err = __devlink_region_snapshot_create(region, data, snapshot_id);
48068c2ecf20Sopenharmony_ci	if (err)
48078c2ecf20Sopenharmony_ci		goto err_snapshot_create;
48088c2ecf20Sopenharmony_ci
48098c2ecf20Sopenharmony_ci	if (!snapshot_id_attr) {
48108c2ecf20Sopenharmony_ci		struct sk_buff *msg;
48118c2ecf20Sopenharmony_ci
48128c2ecf20Sopenharmony_ci		snapshot = devlink_region_snapshot_get_by_id(region,
48138c2ecf20Sopenharmony_ci							     snapshot_id);
48148c2ecf20Sopenharmony_ci		if (WARN_ON(!snapshot))
48158c2ecf20Sopenharmony_ci			return -EINVAL;
48168c2ecf20Sopenharmony_ci
48178c2ecf20Sopenharmony_ci		msg = devlink_nl_region_notify_build(region, snapshot,
48188c2ecf20Sopenharmony_ci						     DEVLINK_CMD_REGION_NEW,
48198c2ecf20Sopenharmony_ci						     info->snd_portid,
48208c2ecf20Sopenharmony_ci						     info->snd_seq);
48218c2ecf20Sopenharmony_ci		err = PTR_ERR_OR_ZERO(msg);
48228c2ecf20Sopenharmony_ci		if (err)
48238c2ecf20Sopenharmony_ci			goto err_notify;
48248c2ecf20Sopenharmony_ci
48258c2ecf20Sopenharmony_ci		err = genlmsg_reply(msg, info);
48268c2ecf20Sopenharmony_ci		if (err)
48278c2ecf20Sopenharmony_ci			goto err_notify;
48288c2ecf20Sopenharmony_ci	}
48298c2ecf20Sopenharmony_ci
48308c2ecf20Sopenharmony_ci	return 0;
48318c2ecf20Sopenharmony_ci
48328c2ecf20Sopenharmony_cierr_snapshot_create:
48338c2ecf20Sopenharmony_ci	region->ops->destructor(data);
48348c2ecf20Sopenharmony_cierr_snapshot_capture:
48358c2ecf20Sopenharmony_ci	__devlink_snapshot_id_decrement(devlink, snapshot_id);
48368c2ecf20Sopenharmony_ci	return err;
48378c2ecf20Sopenharmony_ci
48388c2ecf20Sopenharmony_cierr_notify:
48398c2ecf20Sopenharmony_ci	devlink_region_snapshot_del(region, snapshot);
48408c2ecf20Sopenharmony_ci	return err;
48418c2ecf20Sopenharmony_ci}
48428c2ecf20Sopenharmony_ci
48438c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
48448c2ecf20Sopenharmony_ci						 struct devlink *devlink,
48458c2ecf20Sopenharmony_ci						 u8 *chunk, u32 chunk_size,
48468c2ecf20Sopenharmony_ci						 u64 addr)
48478c2ecf20Sopenharmony_ci{
48488c2ecf20Sopenharmony_ci	struct nlattr *chunk_attr;
48498c2ecf20Sopenharmony_ci	int err;
48508c2ecf20Sopenharmony_ci
48518c2ecf20Sopenharmony_ci	chunk_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_REGION_CHUNK);
48528c2ecf20Sopenharmony_ci	if (!chunk_attr)
48538c2ecf20Sopenharmony_ci		return -EINVAL;
48548c2ecf20Sopenharmony_ci
48558c2ecf20Sopenharmony_ci	err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
48568c2ecf20Sopenharmony_ci	if (err)
48578c2ecf20Sopenharmony_ci		goto nla_put_failure;
48588c2ecf20Sopenharmony_ci
48598c2ecf20Sopenharmony_ci	err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
48608c2ecf20Sopenharmony_ci				DEVLINK_ATTR_PAD);
48618c2ecf20Sopenharmony_ci	if (err)
48628c2ecf20Sopenharmony_ci		goto nla_put_failure;
48638c2ecf20Sopenharmony_ci
48648c2ecf20Sopenharmony_ci	nla_nest_end(msg, chunk_attr);
48658c2ecf20Sopenharmony_ci	return 0;
48668c2ecf20Sopenharmony_ci
48678c2ecf20Sopenharmony_cinla_put_failure:
48688c2ecf20Sopenharmony_ci	nla_nest_cancel(msg, chunk_attr);
48698c2ecf20Sopenharmony_ci	return err;
48708c2ecf20Sopenharmony_ci}
48718c2ecf20Sopenharmony_ci
48728c2ecf20Sopenharmony_ci#define DEVLINK_REGION_READ_CHUNK_SIZE 256
48738c2ecf20Sopenharmony_ci
48748c2ecf20Sopenharmony_cistatic int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
48758c2ecf20Sopenharmony_ci						struct devlink *devlink,
48768c2ecf20Sopenharmony_ci						struct devlink_region *region,
48778c2ecf20Sopenharmony_ci						struct nlattr **attrs,
48788c2ecf20Sopenharmony_ci						u64 start_offset,
48798c2ecf20Sopenharmony_ci						u64 end_offset,
48808c2ecf20Sopenharmony_ci						u64 *new_offset)
48818c2ecf20Sopenharmony_ci{
48828c2ecf20Sopenharmony_ci	struct devlink_snapshot *snapshot;
48838c2ecf20Sopenharmony_ci	u64 curr_offset = start_offset;
48848c2ecf20Sopenharmony_ci	u32 snapshot_id;
48858c2ecf20Sopenharmony_ci	int err = 0;
48868c2ecf20Sopenharmony_ci
48878c2ecf20Sopenharmony_ci	*new_offset = start_offset;
48888c2ecf20Sopenharmony_ci
48898c2ecf20Sopenharmony_ci	snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
48908c2ecf20Sopenharmony_ci	snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
48918c2ecf20Sopenharmony_ci	if (!snapshot)
48928c2ecf20Sopenharmony_ci		return -EINVAL;
48938c2ecf20Sopenharmony_ci
48948c2ecf20Sopenharmony_ci	while (curr_offset < end_offset) {
48958c2ecf20Sopenharmony_ci		u32 data_size;
48968c2ecf20Sopenharmony_ci		u8 *data;
48978c2ecf20Sopenharmony_ci
48988c2ecf20Sopenharmony_ci		if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
48998c2ecf20Sopenharmony_ci			data_size = end_offset - curr_offset;
49008c2ecf20Sopenharmony_ci		else
49018c2ecf20Sopenharmony_ci			data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
49028c2ecf20Sopenharmony_ci
49038c2ecf20Sopenharmony_ci		data = &snapshot->data[curr_offset];
49048c2ecf20Sopenharmony_ci		err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
49058c2ecf20Sopenharmony_ci							    data, data_size,
49068c2ecf20Sopenharmony_ci							    curr_offset);
49078c2ecf20Sopenharmony_ci		if (err)
49088c2ecf20Sopenharmony_ci			break;
49098c2ecf20Sopenharmony_ci
49108c2ecf20Sopenharmony_ci		curr_offset += data_size;
49118c2ecf20Sopenharmony_ci	}
49128c2ecf20Sopenharmony_ci	*new_offset = curr_offset;
49138c2ecf20Sopenharmony_ci
49148c2ecf20Sopenharmony_ci	return err;
49158c2ecf20Sopenharmony_ci}
49168c2ecf20Sopenharmony_ci
49178c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
49188c2ecf20Sopenharmony_ci					     struct netlink_callback *cb)
49198c2ecf20Sopenharmony_ci{
49208c2ecf20Sopenharmony_ci	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
49218c2ecf20Sopenharmony_ci	u64 ret_offset, start_offset, end_offset = U64_MAX;
49228c2ecf20Sopenharmony_ci	struct nlattr **attrs = info->attrs;
49238c2ecf20Sopenharmony_ci	struct devlink_port *port = NULL;
49248c2ecf20Sopenharmony_ci	struct devlink_region *region;
49258c2ecf20Sopenharmony_ci	struct nlattr *chunks_attr;
49268c2ecf20Sopenharmony_ci	const char *region_name;
49278c2ecf20Sopenharmony_ci	struct devlink *devlink;
49288c2ecf20Sopenharmony_ci	unsigned int index;
49298c2ecf20Sopenharmony_ci	void *hdr;
49308c2ecf20Sopenharmony_ci	int err;
49318c2ecf20Sopenharmony_ci
49328c2ecf20Sopenharmony_ci	start_offset = *((u64 *)&cb->args[0]);
49338c2ecf20Sopenharmony_ci
49348c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
49358c2ecf20Sopenharmony_ci	devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
49368c2ecf20Sopenharmony_ci	if (IS_ERR(devlink)) {
49378c2ecf20Sopenharmony_ci		err = PTR_ERR(devlink);
49388c2ecf20Sopenharmony_ci		goto out_dev;
49398c2ecf20Sopenharmony_ci	}
49408c2ecf20Sopenharmony_ci
49418c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
49428c2ecf20Sopenharmony_ci
49438c2ecf20Sopenharmony_ci	if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
49448c2ecf20Sopenharmony_ci	    !attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) {
49458c2ecf20Sopenharmony_ci		err = -EINVAL;
49468c2ecf20Sopenharmony_ci		goto out_unlock;
49478c2ecf20Sopenharmony_ci	}
49488c2ecf20Sopenharmony_ci
49498c2ecf20Sopenharmony_ci	if (info->attrs[DEVLINK_ATTR_PORT_INDEX]) {
49508c2ecf20Sopenharmony_ci		index = nla_get_u32(info->attrs[DEVLINK_ATTR_PORT_INDEX]);
49518c2ecf20Sopenharmony_ci
49528c2ecf20Sopenharmony_ci		port = devlink_port_get_by_index(devlink, index);
49538c2ecf20Sopenharmony_ci		if (!port) {
49548c2ecf20Sopenharmony_ci			err = -ENODEV;
49558c2ecf20Sopenharmony_ci			goto out_unlock;
49568c2ecf20Sopenharmony_ci		}
49578c2ecf20Sopenharmony_ci	}
49588c2ecf20Sopenharmony_ci
49598c2ecf20Sopenharmony_ci	region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
49608c2ecf20Sopenharmony_ci
49618c2ecf20Sopenharmony_ci	if (port)
49628c2ecf20Sopenharmony_ci		region = devlink_port_region_get_by_name(port, region_name);
49638c2ecf20Sopenharmony_ci	else
49648c2ecf20Sopenharmony_ci		region = devlink_region_get_by_name(devlink, region_name);
49658c2ecf20Sopenharmony_ci
49668c2ecf20Sopenharmony_ci	if (!region) {
49678c2ecf20Sopenharmony_ci		err = -EINVAL;
49688c2ecf20Sopenharmony_ci		goto out_unlock;
49698c2ecf20Sopenharmony_ci	}
49708c2ecf20Sopenharmony_ci
49718c2ecf20Sopenharmony_ci	if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
49728c2ecf20Sopenharmony_ci	    attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
49738c2ecf20Sopenharmony_ci		if (!start_offset)
49748c2ecf20Sopenharmony_ci			start_offset =
49758c2ecf20Sopenharmony_ci				nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
49768c2ecf20Sopenharmony_ci
49778c2ecf20Sopenharmony_ci		end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
49788c2ecf20Sopenharmony_ci		end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
49798c2ecf20Sopenharmony_ci	}
49808c2ecf20Sopenharmony_ci
49818c2ecf20Sopenharmony_ci	if (end_offset > region->size)
49828c2ecf20Sopenharmony_ci		end_offset = region->size;
49838c2ecf20Sopenharmony_ci
49848c2ecf20Sopenharmony_ci	/* return 0 if there is no further data to read */
49858c2ecf20Sopenharmony_ci	if (start_offset == end_offset) {
49868c2ecf20Sopenharmony_ci		err = 0;
49878c2ecf20Sopenharmony_ci		goto out_unlock;
49888c2ecf20Sopenharmony_ci	}
49898c2ecf20Sopenharmony_ci
49908c2ecf20Sopenharmony_ci	hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
49918c2ecf20Sopenharmony_ci			  &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
49928c2ecf20Sopenharmony_ci			  DEVLINK_CMD_REGION_READ);
49938c2ecf20Sopenharmony_ci	if (!hdr) {
49948c2ecf20Sopenharmony_ci		err = -EMSGSIZE;
49958c2ecf20Sopenharmony_ci		goto out_unlock;
49968c2ecf20Sopenharmony_ci	}
49978c2ecf20Sopenharmony_ci
49988c2ecf20Sopenharmony_ci	err = devlink_nl_put_handle(skb, devlink);
49998c2ecf20Sopenharmony_ci	if (err)
50008c2ecf20Sopenharmony_ci		goto nla_put_failure;
50018c2ecf20Sopenharmony_ci
50028c2ecf20Sopenharmony_ci	if (region->port) {
50038c2ecf20Sopenharmony_ci		err = nla_put_u32(skb, DEVLINK_ATTR_PORT_INDEX,
50048c2ecf20Sopenharmony_ci				  region->port->index);
50058c2ecf20Sopenharmony_ci		if (err)
50068c2ecf20Sopenharmony_ci			goto nla_put_failure;
50078c2ecf20Sopenharmony_ci	}
50088c2ecf20Sopenharmony_ci
50098c2ecf20Sopenharmony_ci	err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
50108c2ecf20Sopenharmony_ci	if (err)
50118c2ecf20Sopenharmony_ci		goto nla_put_failure;
50128c2ecf20Sopenharmony_ci
50138c2ecf20Sopenharmony_ci	chunks_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_REGION_CHUNKS);
50148c2ecf20Sopenharmony_ci	if (!chunks_attr) {
50158c2ecf20Sopenharmony_ci		err = -EMSGSIZE;
50168c2ecf20Sopenharmony_ci		goto nla_put_failure;
50178c2ecf20Sopenharmony_ci	}
50188c2ecf20Sopenharmony_ci
50198c2ecf20Sopenharmony_ci	err = devlink_nl_region_read_snapshot_fill(skb, devlink,
50208c2ecf20Sopenharmony_ci						   region, attrs,
50218c2ecf20Sopenharmony_ci						   start_offset,
50228c2ecf20Sopenharmony_ci						   end_offset, &ret_offset);
50238c2ecf20Sopenharmony_ci
50248c2ecf20Sopenharmony_ci	if (err && err != -EMSGSIZE)
50258c2ecf20Sopenharmony_ci		goto nla_put_failure;
50268c2ecf20Sopenharmony_ci
50278c2ecf20Sopenharmony_ci	/* Check if there was any progress done to prevent infinite loop */
50288c2ecf20Sopenharmony_ci	if (ret_offset == start_offset) {
50298c2ecf20Sopenharmony_ci		err = -EINVAL;
50308c2ecf20Sopenharmony_ci		goto nla_put_failure;
50318c2ecf20Sopenharmony_ci	}
50328c2ecf20Sopenharmony_ci
50338c2ecf20Sopenharmony_ci	*((u64 *)&cb->args[0]) = ret_offset;
50348c2ecf20Sopenharmony_ci
50358c2ecf20Sopenharmony_ci	nla_nest_end(skb, chunks_attr);
50368c2ecf20Sopenharmony_ci	genlmsg_end(skb, hdr);
50378c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
50388c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
50398c2ecf20Sopenharmony_ci
50408c2ecf20Sopenharmony_ci	return skb->len;
50418c2ecf20Sopenharmony_ci
50428c2ecf20Sopenharmony_cinla_put_failure:
50438c2ecf20Sopenharmony_ci	genlmsg_cancel(skb, hdr);
50448c2ecf20Sopenharmony_ciout_unlock:
50458c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
50468c2ecf20Sopenharmony_ciout_dev:
50478c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
50488c2ecf20Sopenharmony_ci	return err;
50498c2ecf20Sopenharmony_ci}
50508c2ecf20Sopenharmony_ci
50518c2ecf20Sopenharmony_cistruct devlink_info_req {
50528c2ecf20Sopenharmony_ci	struct sk_buff *msg;
50538c2ecf20Sopenharmony_ci};
50548c2ecf20Sopenharmony_ci
50558c2ecf20Sopenharmony_ciint devlink_info_driver_name_put(struct devlink_info_req *req, const char *name)
50568c2ecf20Sopenharmony_ci{
50578c2ecf20Sopenharmony_ci	return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name);
50588c2ecf20Sopenharmony_ci}
50598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_info_driver_name_put);
50608c2ecf20Sopenharmony_ci
50618c2ecf20Sopenharmony_ciint devlink_info_serial_number_put(struct devlink_info_req *req, const char *sn)
50628c2ecf20Sopenharmony_ci{
50638c2ecf20Sopenharmony_ci	return nla_put_string(req->msg, DEVLINK_ATTR_INFO_SERIAL_NUMBER, sn);
50648c2ecf20Sopenharmony_ci}
50658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_info_serial_number_put);
50668c2ecf20Sopenharmony_ci
50678c2ecf20Sopenharmony_ciint devlink_info_board_serial_number_put(struct devlink_info_req *req,
50688c2ecf20Sopenharmony_ci					 const char *bsn)
50698c2ecf20Sopenharmony_ci{
50708c2ecf20Sopenharmony_ci	return nla_put_string(req->msg, DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER,
50718c2ecf20Sopenharmony_ci			      bsn);
50728c2ecf20Sopenharmony_ci}
50738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_info_board_serial_number_put);
50748c2ecf20Sopenharmony_ci
50758c2ecf20Sopenharmony_cistatic int devlink_info_version_put(struct devlink_info_req *req, int attr,
50768c2ecf20Sopenharmony_ci				    const char *version_name,
50778c2ecf20Sopenharmony_ci				    const char *version_value)
50788c2ecf20Sopenharmony_ci{
50798c2ecf20Sopenharmony_ci	struct nlattr *nest;
50808c2ecf20Sopenharmony_ci	int err;
50818c2ecf20Sopenharmony_ci
50828c2ecf20Sopenharmony_ci	nest = nla_nest_start_noflag(req->msg, attr);
50838c2ecf20Sopenharmony_ci	if (!nest)
50848c2ecf20Sopenharmony_ci		return -EMSGSIZE;
50858c2ecf20Sopenharmony_ci
50868c2ecf20Sopenharmony_ci	err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_NAME,
50878c2ecf20Sopenharmony_ci			     version_name);
50888c2ecf20Sopenharmony_ci	if (err)
50898c2ecf20Sopenharmony_ci		goto nla_put_failure;
50908c2ecf20Sopenharmony_ci
50918c2ecf20Sopenharmony_ci	err = nla_put_string(req->msg, DEVLINK_ATTR_INFO_VERSION_VALUE,
50928c2ecf20Sopenharmony_ci			     version_value);
50938c2ecf20Sopenharmony_ci	if (err)
50948c2ecf20Sopenharmony_ci		goto nla_put_failure;
50958c2ecf20Sopenharmony_ci
50968c2ecf20Sopenharmony_ci	nla_nest_end(req->msg, nest);
50978c2ecf20Sopenharmony_ci
50988c2ecf20Sopenharmony_ci	return 0;
50998c2ecf20Sopenharmony_ci
51008c2ecf20Sopenharmony_cinla_put_failure:
51018c2ecf20Sopenharmony_ci	nla_nest_cancel(req->msg, nest);
51028c2ecf20Sopenharmony_ci	return err;
51038c2ecf20Sopenharmony_ci}
51048c2ecf20Sopenharmony_ci
51058c2ecf20Sopenharmony_ciint devlink_info_version_fixed_put(struct devlink_info_req *req,
51068c2ecf20Sopenharmony_ci				   const char *version_name,
51078c2ecf20Sopenharmony_ci				   const char *version_value)
51088c2ecf20Sopenharmony_ci{
51098c2ecf20Sopenharmony_ci	return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_FIXED,
51108c2ecf20Sopenharmony_ci					version_name, version_value);
51118c2ecf20Sopenharmony_ci}
51128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_info_version_fixed_put);
51138c2ecf20Sopenharmony_ci
51148c2ecf20Sopenharmony_ciint devlink_info_version_stored_put(struct devlink_info_req *req,
51158c2ecf20Sopenharmony_ci				    const char *version_name,
51168c2ecf20Sopenharmony_ci				    const char *version_value)
51178c2ecf20Sopenharmony_ci{
51188c2ecf20Sopenharmony_ci	return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_STORED,
51198c2ecf20Sopenharmony_ci					version_name, version_value);
51208c2ecf20Sopenharmony_ci}
51218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_info_version_stored_put);
51228c2ecf20Sopenharmony_ci
51238c2ecf20Sopenharmony_ciint devlink_info_version_running_put(struct devlink_info_req *req,
51248c2ecf20Sopenharmony_ci				     const char *version_name,
51258c2ecf20Sopenharmony_ci				     const char *version_value)
51268c2ecf20Sopenharmony_ci{
51278c2ecf20Sopenharmony_ci	return devlink_info_version_put(req, DEVLINK_ATTR_INFO_VERSION_RUNNING,
51288c2ecf20Sopenharmony_ci					version_name, version_value);
51298c2ecf20Sopenharmony_ci}
51308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_info_version_running_put);
51318c2ecf20Sopenharmony_ci
51328c2ecf20Sopenharmony_cistatic int
51338c2ecf20Sopenharmony_cidevlink_nl_info_fill(struct sk_buff *msg, struct devlink *devlink,
51348c2ecf20Sopenharmony_ci		     enum devlink_command cmd, u32 portid,
51358c2ecf20Sopenharmony_ci		     u32 seq, int flags, struct netlink_ext_ack *extack)
51368c2ecf20Sopenharmony_ci{
51378c2ecf20Sopenharmony_ci	struct devlink_info_req req;
51388c2ecf20Sopenharmony_ci	void *hdr;
51398c2ecf20Sopenharmony_ci	int err;
51408c2ecf20Sopenharmony_ci
51418c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
51428c2ecf20Sopenharmony_ci	if (!hdr)
51438c2ecf20Sopenharmony_ci		return -EMSGSIZE;
51448c2ecf20Sopenharmony_ci
51458c2ecf20Sopenharmony_ci	err = -EMSGSIZE;
51468c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(msg, devlink))
51478c2ecf20Sopenharmony_ci		goto err_cancel_msg;
51488c2ecf20Sopenharmony_ci
51498c2ecf20Sopenharmony_ci	req.msg = msg;
51508c2ecf20Sopenharmony_ci	err = devlink->ops->info_get(devlink, &req, extack);
51518c2ecf20Sopenharmony_ci	if (err)
51528c2ecf20Sopenharmony_ci		goto err_cancel_msg;
51538c2ecf20Sopenharmony_ci
51548c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
51558c2ecf20Sopenharmony_ci	return 0;
51568c2ecf20Sopenharmony_ci
51578c2ecf20Sopenharmony_cierr_cancel_msg:
51588c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
51598c2ecf20Sopenharmony_ci	return err;
51608c2ecf20Sopenharmony_ci}
51618c2ecf20Sopenharmony_ci
51628c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_info_get_doit(struct sk_buff *skb,
51638c2ecf20Sopenharmony_ci					struct genl_info *info)
51648c2ecf20Sopenharmony_ci{
51658c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
51668c2ecf20Sopenharmony_ci	struct sk_buff *msg;
51678c2ecf20Sopenharmony_ci	int err;
51688c2ecf20Sopenharmony_ci
51698c2ecf20Sopenharmony_ci	if (!devlink->ops->info_get)
51708c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
51718c2ecf20Sopenharmony_ci
51728c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
51738c2ecf20Sopenharmony_ci	if (!msg)
51748c2ecf20Sopenharmony_ci		return -ENOMEM;
51758c2ecf20Sopenharmony_ci
51768c2ecf20Sopenharmony_ci	err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
51778c2ecf20Sopenharmony_ci				   info->snd_portid, info->snd_seq, 0,
51788c2ecf20Sopenharmony_ci				   info->extack);
51798c2ecf20Sopenharmony_ci	if (err) {
51808c2ecf20Sopenharmony_ci		nlmsg_free(msg);
51818c2ecf20Sopenharmony_ci		return err;
51828c2ecf20Sopenharmony_ci	}
51838c2ecf20Sopenharmony_ci
51848c2ecf20Sopenharmony_ci	return genlmsg_reply(msg, info);
51858c2ecf20Sopenharmony_ci}
51868c2ecf20Sopenharmony_ci
51878c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_info_get_dumpit(struct sk_buff *msg,
51888c2ecf20Sopenharmony_ci					  struct netlink_callback *cb)
51898c2ecf20Sopenharmony_ci{
51908c2ecf20Sopenharmony_ci	struct devlink *devlink;
51918c2ecf20Sopenharmony_ci	int start = cb->args[0];
51928c2ecf20Sopenharmony_ci	int idx = 0;
51938c2ecf20Sopenharmony_ci	int err = 0;
51948c2ecf20Sopenharmony_ci
51958c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
51968c2ecf20Sopenharmony_ci	list_for_each_entry(devlink, &devlink_list, list) {
51978c2ecf20Sopenharmony_ci		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
51988c2ecf20Sopenharmony_ci			continue;
51998c2ecf20Sopenharmony_ci		if (idx < start) {
52008c2ecf20Sopenharmony_ci			idx++;
52018c2ecf20Sopenharmony_ci			continue;
52028c2ecf20Sopenharmony_ci		}
52038c2ecf20Sopenharmony_ci
52048c2ecf20Sopenharmony_ci		if (!devlink->ops->info_get) {
52058c2ecf20Sopenharmony_ci			idx++;
52068c2ecf20Sopenharmony_ci			continue;
52078c2ecf20Sopenharmony_ci		}
52088c2ecf20Sopenharmony_ci
52098c2ecf20Sopenharmony_ci		mutex_lock(&devlink->lock);
52108c2ecf20Sopenharmony_ci		err = devlink_nl_info_fill(msg, devlink, DEVLINK_CMD_INFO_GET,
52118c2ecf20Sopenharmony_ci					   NETLINK_CB(cb->skb).portid,
52128c2ecf20Sopenharmony_ci					   cb->nlh->nlmsg_seq, NLM_F_MULTI,
52138c2ecf20Sopenharmony_ci					   cb->extack);
52148c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->lock);
52158c2ecf20Sopenharmony_ci		if (err == -EOPNOTSUPP)
52168c2ecf20Sopenharmony_ci			err = 0;
52178c2ecf20Sopenharmony_ci		else if (err)
52188c2ecf20Sopenharmony_ci			break;
52198c2ecf20Sopenharmony_ci		idx++;
52208c2ecf20Sopenharmony_ci	}
52218c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
52228c2ecf20Sopenharmony_ci
52238c2ecf20Sopenharmony_ci	if (err != -EMSGSIZE)
52248c2ecf20Sopenharmony_ci		return err;
52258c2ecf20Sopenharmony_ci
52268c2ecf20Sopenharmony_ci	cb->args[0] = idx;
52278c2ecf20Sopenharmony_ci	return msg->len;
52288c2ecf20Sopenharmony_ci}
52298c2ecf20Sopenharmony_ci
52308c2ecf20Sopenharmony_cistruct devlink_fmsg_item {
52318c2ecf20Sopenharmony_ci	struct list_head list;
52328c2ecf20Sopenharmony_ci	int attrtype;
52338c2ecf20Sopenharmony_ci	u8 nla_type;
52348c2ecf20Sopenharmony_ci	u16 len;
52358c2ecf20Sopenharmony_ci	int value[];
52368c2ecf20Sopenharmony_ci};
52378c2ecf20Sopenharmony_ci
52388c2ecf20Sopenharmony_cistruct devlink_fmsg {
52398c2ecf20Sopenharmony_ci	struct list_head item_list;
52408c2ecf20Sopenharmony_ci	bool putting_binary; /* This flag forces enclosing of binary data
52418c2ecf20Sopenharmony_ci			      * in an array brackets. It forces using
52428c2ecf20Sopenharmony_ci			      * of designated API:
52438c2ecf20Sopenharmony_ci			      * devlink_fmsg_binary_pair_nest_start()
52448c2ecf20Sopenharmony_ci			      * devlink_fmsg_binary_pair_nest_end()
52458c2ecf20Sopenharmony_ci			      */
52468c2ecf20Sopenharmony_ci};
52478c2ecf20Sopenharmony_ci
52488c2ecf20Sopenharmony_cistatic struct devlink_fmsg *devlink_fmsg_alloc(void)
52498c2ecf20Sopenharmony_ci{
52508c2ecf20Sopenharmony_ci	struct devlink_fmsg *fmsg;
52518c2ecf20Sopenharmony_ci
52528c2ecf20Sopenharmony_ci	fmsg = kzalloc(sizeof(*fmsg), GFP_KERNEL);
52538c2ecf20Sopenharmony_ci	if (!fmsg)
52548c2ecf20Sopenharmony_ci		return NULL;
52558c2ecf20Sopenharmony_ci
52568c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&fmsg->item_list);
52578c2ecf20Sopenharmony_ci
52588c2ecf20Sopenharmony_ci	return fmsg;
52598c2ecf20Sopenharmony_ci}
52608c2ecf20Sopenharmony_ci
52618c2ecf20Sopenharmony_cistatic void devlink_fmsg_free(struct devlink_fmsg *fmsg)
52628c2ecf20Sopenharmony_ci{
52638c2ecf20Sopenharmony_ci	struct devlink_fmsg_item *item, *tmp;
52648c2ecf20Sopenharmony_ci
52658c2ecf20Sopenharmony_ci	list_for_each_entry_safe(item, tmp, &fmsg->item_list, list) {
52668c2ecf20Sopenharmony_ci		list_del(&item->list);
52678c2ecf20Sopenharmony_ci		kfree(item);
52688c2ecf20Sopenharmony_ci	}
52698c2ecf20Sopenharmony_ci	kfree(fmsg);
52708c2ecf20Sopenharmony_ci}
52718c2ecf20Sopenharmony_ci
52728c2ecf20Sopenharmony_cistatic int devlink_fmsg_nest_common(struct devlink_fmsg *fmsg,
52738c2ecf20Sopenharmony_ci				    int attrtype)
52748c2ecf20Sopenharmony_ci{
52758c2ecf20Sopenharmony_ci	struct devlink_fmsg_item *item;
52768c2ecf20Sopenharmony_ci
52778c2ecf20Sopenharmony_ci	item = kzalloc(sizeof(*item), GFP_KERNEL);
52788c2ecf20Sopenharmony_ci	if (!item)
52798c2ecf20Sopenharmony_ci		return -ENOMEM;
52808c2ecf20Sopenharmony_ci
52818c2ecf20Sopenharmony_ci	item->attrtype = attrtype;
52828c2ecf20Sopenharmony_ci	list_add_tail(&item->list, &fmsg->item_list);
52838c2ecf20Sopenharmony_ci
52848c2ecf20Sopenharmony_ci	return 0;
52858c2ecf20Sopenharmony_ci}
52868c2ecf20Sopenharmony_ci
52878c2ecf20Sopenharmony_ciint devlink_fmsg_obj_nest_start(struct devlink_fmsg *fmsg)
52888c2ecf20Sopenharmony_ci{
52898c2ecf20Sopenharmony_ci	if (fmsg->putting_binary)
52908c2ecf20Sopenharmony_ci		return -EINVAL;
52918c2ecf20Sopenharmony_ci
52928c2ecf20Sopenharmony_ci	return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_OBJ_NEST_START);
52938c2ecf20Sopenharmony_ci}
52948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_start);
52958c2ecf20Sopenharmony_ci
52968c2ecf20Sopenharmony_cistatic int devlink_fmsg_nest_end(struct devlink_fmsg *fmsg)
52978c2ecf20Sopenharmony_ci{
52988c2ecf20Sopenharmony_ci	if (fmsg->putting_binary)
52998c2ecf20Sopenharmony_ci		return -EINVAL;
53008c2ecf20Sopenharmony_ci
53018c2ecf20Sopenharmony_ci	return devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_NEST_END);
53028c2ecf20Sopenharmony_ci}
53038c2ecf20Sopenharmony_ci
53048c2ecf20Sopenharmony_ciint devlink_fmsg_obj_nest_end(struct devlink_fmsg *fmsg)
53058c2ecf20Sopenharmony_ci{
53068c2ecf20Sopenharmony_ci	if (fmsg->putting_binary)
53078c2ecf20Sopenharmony_ci		return -EINVAL;
53088c2ecf20Sopenharmony_ci
53098c2ecf20Sopenharmony_ci	return devlink_fmsg_nest_end(fmsg);
53108c2ecf20Sopenharmony_ci}
53118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_obj_nest_end);
53128c2ecf20Sopenharmony_ci
53138c2ecf20Sopenharmony_ci#define DEVLINK_FMSG_MAX_SIZE (GENLMSG_DEFAULT_SIZE - GENL_HDRLEN - NLA_HDRLEN)
53148c2ecf20Sopenharmony_ci
53158c2ecf20Sopenharmony_cistatic int devlink_fmsg_put_name(struct devlink_fmsg *fmsg, const char *name)
53168c2ecf20Sopenharmony_ci{
53178c2ecf20Sopenharmony_ci	struct devlink_fmsg_item *item;
53188c2ecf20Sopenharmony_ci
53198c2ecf20Sopenharmony_ci	if (fmsg->putting_binary)
53208c2ecf20Sopenharmony_ci		return -EINVAL;
53218c2ecf20Sopenharmony_ci
53228c2ecf20Sopenharmony_ci	if (strlen(name) + 1 > DEVLINK_FMSG_MAX_SIZE)
53238c2ecf20Sopenharmony_ci		return -EMSGSIZE;
53248c2ecf20Sopenharmony_ci
53258c2ecf20Sopenharmony_ci	item = kzalloc(sizeof(*item) + strlen(name) + 1, GFP_KERNEL);
53268c2ecf20Sopenharmony_ci	if (!item)
53278c2ecf20Sopenharmony_ci		return -ENOMEM;
53288c2ecf20Sopenharmony_ci
53298c2ecf20Sopenharmony_ci	item->nla_type = NLA_NUL_STRING;
53308c2ecf20Sopenharmony_ci	item->len = strlen(name) + 1;
53318c2ecf20Sopenharmony_ci	item->attrtype = DEVLINK_ATTR_FMSG_OBJ_NAME;
53328c2ecf20Sopenharmony_ci	memcpy(&item->value, name, item->len);
53338c2ecf20Sopenharmony_ci	list_add_tail(&item->list, &fmsg->item_list);
53348c2ecf20Sopenharmony_ci
53358c2ecf20Sopenharmony_ci	return 0;
53368c2ecf20Sopenharmony_ci}
53378c2ecf20Sopenharmony_ci
53388c2ecf20Sopenharmony_ciint devlink_fmsg_pair_nest_start(struct devlink_fmsg *fmsg, const char *name)
53398c2ecf20Sopenharmony_ci{
53408c2ecf20Sopenharmony_ci	int err;
53418c2ecf20Sopenharmony_ci
53428c2ecf20Sopenharmony_ci	if (fmsg->putting_binary)
53438c2ecf20Sopenharmony_ci		return -EINVAL;
53448c2ecf20Sopenharmony_ci
53458c2ecf20Sopenharmony_ci	err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_PAIR_NEST_START);
53468c2ecf20Sopenharmony_ci	if (err)
53478c2ecf20Sopenharmony_ci		return err;
53488c2ecf20Sopenharmony_ci
53498c2ecf20Sopenharmony_ci	err = devlink_fmsg_put_name(fmsg, name);
53508c2ecf20Sopenharmony_ci	if (err)
53518c2ecf20Sopenharmony_ci		return err;
53528c2ecf20Sopenharmony_ci
53538c2ecf20Sopenharmony_ci	return 0;
53548c2ecf20Sopenharmony_ci}
53558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_start);
53568c2ecf20Sopenharmony_ci
53578c2ecf20Sopenharmony_ciint devlink_fmsg_pair_nest_end(struct devlink_fmsg *fmsg)
53588c2ecf20Sopenharmony_ci{
53598c2ecf20Sopenharmony_ci	if (fmsg->putting_binary)
53608c2ecf20Sopenharmony_ci		return -EINVAL;
53618c2ecf20Sopenharmony_ci
53628c2ecf20Sopenharmony_ci	return devlink_fmsg_nest_end(fmsg);
53638c2ecf20Sopenharmony_ci}
53648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_pair_nest_end);
53658c2ecf20Sopenharmony_ci
53668c2ecf20Sopenharmony_ciint devlink_fmsg_arr_pair_nest_start(struct devlink_fmsg *fmsg,
53678c2ecf20Sopenharmony_ci				     const char *name)
53688c2ecf20Sopenharmony_ci{
53698c2ecf20Sopenharmony_ci	int err;
53708c2ecf20Sopenharmony_ci
53718c2ecf20Sopenharmony_ci	if (fmsg->putting_binary)
53728c2ecf20Sopenharmony_ci		return -EINVAL;
53738c2ecf20Sopenharmony_ci
53748c2ecf20Sopenharmony_ci	err = devlink_fmsg_pair_nest_start(fmsg, name);
53758c2ecf20Sopenharmony_ci	if (err)
53768c2ecf20Sopenharmony_ci		return err;
53778c2ecf20Sopenharmony_ci
53788c2ecf20Sopenharmony_ci	err = devlink_fmsg_nest_common(fmsg, DEVLINK_ATTR_FMSG_ARR_NEST_START);
53798c2ecf20Sopenharmony_ci	if (err)
53808c2ecf20Sopenharmony_ci		return err;
53818c2ecf20Sopenharmony_ci
53828c2ecf20Sopenharmony_ci	return 0;
53838c2ecf20Sopenharmony_ci}
53848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_start);
53858c2ecf20Sopenharmony_ci
53868c2ecf20Sopenharmony_ciint devlink_fmsg_arr_pair_nest_end(struct devlink_fmsg *fmsg)
53878c2ecf20Sopenharmony_ci{
53888c2ecf20Sopenharmony_ci	int err;
53898c2ecf20Sopenharmony_ci
53908c2ecf20Sopenharmony_ci	if (fmsg->putting_binary)
53918c2ecf20Sopenharmony_ci		return -EINVAL;
53928c2ecf20Sopenharmony_ci
53938c2ecf20Sopenharmony_ci	err = devlink_fmsg_nest_end(fmsg);
53948c2ecf20Sopenharmony_ci	if (err)
53958c2ecf20Sopenharmony_ci		return err;
53968c2ecf20Sopenharmony_ci
53978c2ecf20Sopenharmony_ci	err = devlink_fmsg_nest_end(fmsg);
53988c2ecf20Sopenharmony_ci	if (err)
53998c2ecf20Sopenharmony_ci		return err;
54008c2ecf20Sopenharmony_ci
54018c2ecf20Sopenharmony_ci	return 0;
54028c2ecf20Sopenharmony_ci}
54038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_arr_pair_nest_end);
54048c2ecf20Sopenharmony_ci
54058c2ecf20Sopenharmony_ciint devlink_fmsg_binary_pair_nest_start(struct devlink_fmsg *fmsg,
54068c2ecf20Sopenharmony_ci					const char *name)
54078c2ecf20Sopenharmony_ci{
54088c2ecf20Sopenharmony_ci	int err;
54098c2ecf20Sopenharmony_ci
54108c2ecf20Sopenharmony_ci	err = devlink_fmsg_arr_pair_nest_start(fmsg, name);
54118c2ecf20Sopenharmony_ci	if (err)
54128c2ecf20Sopenharmony_ci		return err;
54138c2ecf20Sopenharmony_ci
54148c2ecf20Sopenharmony_ci	fmsg->putting_binary = true;
54158c2ecf20Sopenharmony_ci	return err;
54168c2ecf20Sopenharmony_ci}
54178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_start);
54188c2ecf20Sopenharmony_ci
54198c2ecf20Sopenharmony_ciint devlink_fmsg_binary_pair_nest_end(struct devlink_fmsg *fmsg)
54208c2ecf20Sopenharmony_ci{
54218c2ecf20Sopenharmony_ci	if (!fmsg->putting_binary)
54228c2ecf20Sopenharmony_ci		return -EINVAL;
54238c2ecf20Sopenharmony_ci
54248c2ecf20Sopenharmony_ci	fmsg->putting_binary = false;
54258c2ecf20Sopenharmony_ci	return devlink_fmsg_arr_pair_nest_end(fmsg);
54268c2ecf20Sopenharmony_ci}
54278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_nest_end);
54288c2ecf20Sopenharmony_ci
54298c2ecf20Sopenharmony_cistatic int devlink_fmsg_put_value(struct devlink_fmsg *fmsg,
54308c2ecf20Sopenharmony_ci				  const void *value, u16 value_len,
54318c2ecf20Sopenharmony_ci				  u8 value_nla_type)
54328c2ecf20Sopenharmony_ci{
54338c2ecf20Sopenharmony_ci	struct devlink_fmsg_item *item;
54348c2ecf20Sopenharmony_ci
54358c2ecf20Sopenharmony_ci	if (value_len > DEVLINK_FMSG_MAX_SIZE)
54368c2ecf20Sopenharmony_ci		return -EMSGSIZE;
54378c2ecf20Sopenharmony_ci
54388c2ecf20Sopenharmony_ci	item = kzalloc(sizeof(*item) + value_len, GFP_KERNEL);
54398c2ecf20Sopenharmony_ci	if (!item)
54408c2ecf20Sopenharmony_ci		return -ENOMEM;
54418c2ecf20Sopenharmony_ci
54428c2ecf20Sopenharmony_ci	item->nla_type = value_nla_type;
54438c2ecf20Sopenharmony_ci	item->len = value_len;
54448c2ecf20Sopenharmony_ci	item->attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
54458c2ecf20Sopenharmony_ci	memcpy(&item->value, value, item->len);
54468c2ecf20Sopenharmony_ci	list_add_tail(&item->list, &fmsg->item_list);
54478c2ecf20Sopenharmony_ci
54488c2ecf20Sopenharmony_ci	return 0;
54498c2ecf20Sopenharmony_ci}
54508c2ecf20Sopenharmony_ci
54518c2ecf20Sopenharmony_ciint devlink_fmsg_bool_put(struct devlink_fmsg *fmsg, bool value)
54528c2ecf20Sopenharmony_ci{
54538c2ecf20Sopenharmony_ci	if (fmsg->putting_binary)
54548c2ecf20Sopenharmony_ci		return -EINVAL;
54558c2ecf20Sopenharmony_ci
54568c2ecf20Sopenharmony_ci	return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_FLAG);
54578c2ecf20Sopenharmony_ci}
54588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_bool_put);
54598c2ecf20Sopenharmony_ci
54608c2ecf20Sopenharmony_ciint devlink_fmsg_u8_put(struct devlink_fmsg *fmsg, u8 value)
54618c2ecf20Sopenharmony_ci{
54628c2ecf20Sopenharmony_ci	if (fmsg->putting_binary)
54638c2ecf20Sopenharmony_ci		return -EINVAL;
54648c2ecf20Sopenharmony_ci
54658c2ecf20Sopenharmony_ci	return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U8);
54668c2ecf20Sopenharmony_ci}
54678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_u8_put);
54688c2ecf20Sopenharmony_ci
54698c2ecf20Sopenharmony_ciint devlink_fmsg_u32_put(struct devlink_fmsg *fmsg, u32 value)
54708c2ecf20Sopenharmony_ci{
54718c2ecf20Sopenharmony_ci	if (fmsg->putting_binary)
54728c2ecf20Sopenharmony_ci		return -EINVAL;
54738c2ecf20Sopenharmony_ci
54748c2ecf20Sopenharmony_ci	return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U32);
54758c2ecf20Sopenharmony_ci}
54768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_u32_put);
54778c2ecf20Sopenharmony_ci
54788c2ecf20Sopenharmony_ciint devlink_fmsg_u64_put(struct devlink_fmsg *fmsg, u64 value)
54798c2ecf20Sopenharmony_ci{
54808c2ecf20Sopenharmony_ci	if (fmsg->putting_binary)
54818c2ecf20Sopenharmony_ci		return -EINVAL;
54828c2ecf20Sopenharmony_ci
54838c2ecf20Sopenharmony_ci	return devlink_fmsg_put_value(fmsg, &value, sizeof(value), NLA_U64);
54848c2ecf20Sopenharmony_ci}
54858c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_u64_put);
54868c2ecf20Sopenharmony_ci
54878c2ecf20Sopenharmony_ciint devlink_fmsg_string_put(struct devlink_fmsg *fmsg, const char *value)
54888c2ecf20Sopenharmony_ci{
54898c2ecf20Sopenharmony_ci	if (fmsg->putting_binary)
54908c2ecf20Sopenharmony_ci		return -EINVAL;
54918c2ecf20Sopenharmony_ci
54928c2ecf20Sopenharmony_ci	return devlink_fmsg_put_value(fmsg, value, strlen(value) + 1,
54938c2ecf20Sopenharmony_ci				      NLA_NUL_STRING);
54948c2ecf20Sopenharmony_ci}
54958c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_string_put);
54968c2ecf20Sopenharmony_ci
54978c2ecf20Sopenharmony_ciint devlink_fmsg_binary_put(struct devlink_fmsg *fmsg, const void *value,
54988c2ecf20Sopenharmony_ci			    u16 value_len)
54998c2ecf20Sopenharmony_ci{
55008c2ecf20Sopenharmony_ci	if (!fmsg->putting_binary)
55018c2ecf20Sopenharmony_ci		return -EINVAL;
55028c2ecf20Sopenharmony_ci
55038c2ecf20Sopenharmony_ci	return devlink_fmsg_put_value(fmsg, value, value_len, NLA_BINARY);
55048c2ecf20Sopenharmony_ci}
55058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_binary_put);
55068c2ecf20Sopenharmony_ci
55078c2ecf20Sopenharmony_ciint devlink_fmsg_bool_pair_put(struct devlink_fmsg *fmsg, const char *name,
55088c2ecf20Sopenharmony_ci			       bool value)
55098c2ecf20Sopenharmony_ci{
55108c2ecf20Sopenharmony_ci	int err;
55118c2ecf20Sopenharmony_ci
55128c2ecf20Sopenharmony_ci	err = devlink_fmsg_pair_nest_start(fmsg, name);
55138c2ecf20Sopenharmony_ci	if (err)
55148c2ecf20Sopenharmony_ci		return err;
55158c2ecf20Sopenharmony_ci
55168c2ecf20Sopenharmony_ci	err = devlink_fmsg_bool_put(fmsg, value);
55178c2ecf20Sopenharmony_ci	if (err)
55188c2ecf20Sopenharmony_ci		return err;
55198c2ecf20Sopenharmony_ci
55208c2ecf20Sopenharmony_ci	err = devlink_fmsg_pair_nest_end(fmsg);
55218c2ecf20Sopenharmony_ci	if (err)
55228c2ecf20Sopenharmony_ci		return err;
55238c2ecf20Sopenharmony_ci
55248c2ecf20Sopenharmony_ci	return 0;
55258c2ecf20Sopenharmony_ci}
55268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_bool_pair_put);
55278c2ecf20Sopenharmony_ci
55288c2ecf20Sopenharmony_ciint devlink_fmsg_u8_pair_put(struct devlink_fmsg *fmsg, const char *name,
55298c2ecf20Sopenharmony_ci			     u8 value)
55308c2ecf20Sopenharmony_ci{
55318c2ecf20Sopenharmony_ci	int err;
55328c2ecf20Sopenharmony_ci
55338c2ecf20Sopenharmony_ci	err = devlink_fmsg_pair_nest_start(fmsg, name);
55348c2ecf20Sopenharmony_ci	if (err)
55358c2ecf20Sopenharmony_ci		return err;
55368c2ecf20Sopenharmony_ci
55378c2ecf20Sopenharmony_ci	err = devlink_fmsg_u8_put(fmsg, value);
55388c2ecf20Sopenharmony_ci	if (err)
55398c2ecf20Sopenharmony_ci		return err;
55408c2ecf20Sopenharmony_ci
55418c2ecf20Sopenharmony_ci	err = devlink_fmsg_pair_nest_end(fmsg);
55428c2ecf20Sopenharmony_ci	if (err)
55438c2ecf20Sopenharmony_ci		return err;
55448c2ecf20Sopenharmony_ci
55458c2ecf20Sopenharmony_ci	return 0;
55468c2ecf20Sopenharmony_ci}
55478c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_u8_pair_put);
55488c2ecf20Sopenharmony_ci
55498c2ecf20Sopenharmony_ciint devlink_fmsg_u32_pair_put(struct devlink_fmsg *fmsg, const char *name,
55508c2ecf20Sopenharmony_ci			      u32 value)
55518c2ecf20Sopenharmony_ci{
55528c2ecf20Sopenharmony_ci	int err;
55538c2ecf20Sopenharmony_ci
55548c2ecf20Sopenharmony_ci	err = devlink_fmsg_pair_nest_start(fmsg, name);
55558c2ecf20Sopenharmony_ci	if (err)
55568c2ecf20Sopenharmony_ci		return err;
55578c2ecf20Sopenharmony_ci
55588c2ecf20Sopenharmony_ci	err = devlink_fmsg_u32_put(fmsg, value);
55598c2ecf20Sopenharmony_ci	if (err)
55608c2ecf20Sopenharmony_ci		return err;
55618c2ecf20Sopenharmony_ci
55628c2ecf20Sopenharmony_ci	err = devlink_fmsg_pair_nest_end(fmsg);
55638c2ecf20Sopenharmony_ci	if (err)
55648c2ecf20Sopenharmony_ci		return err;
55658c2ecf20Sopenharmony_ci
55668c2ecf20Sopenharmony_ci	return 0;
55678c2ecf20Sopenharmony_ci}
55688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_u32_pair_put);
55698c2ecf20Sopenharmony_ci
55708c2ecf20Sopenharmony_ciint devlink_fmsg_u64_pair_put(struct devlink_fmsg *fmsg, const char *name,
55718c2ecf20Sopenharmony_ci			      u64 value)
55728c2ecf20Sopenharmony_ci{
55738c2ecf20Sopenharmony_ci	int err;
55748c2ecf20Sopenharmony_ci
55758c2ecf20Sopenharmony_ci	err = devlink_fmsg_pair_nest_start(fmsg, name);
55768c2ecf20Sopenharmony_ci	if (err)
55778c2ecf20Sopenharmony_ci		return err;
55788c2ecf20Sopenharmony_ci
55798c2ecf20Sopenharmony_ci	err = devlink_fmsg_u64_put(fmsg, value);
55808c2ecf20Sopenharmony_ci	if (err)
55818c2ecf20Sopenharmony_ci		return err;
55828c2ecf20Sopenharmony_ci
55838c2ecf20Sopenharmony_ci	err = devlink_fmsg_pair_nest_end(fmsg);
55848c2ecf20Sopenharmony_ci	if (err)
55858c2ecf20Sopenharmony_ci		return err;
55868c2ecf20Sopenharmony_ci
55878c2ecf20Sopenharmony_ci	return 0;
55888c2ecf20Sopenharmony_ci}
55898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_u64_pair_put);
55908c2ecf20Sopenharmony_ci
55918c2ecf20Sopenharmony_ciint devlink_fmsg_string_pair_put(struct devlink_fmsg *fmsg, const char *name,
55928c2ecf20Sopenharmony_ci				 const char *value)
55938c2ecf20Sopenharmony_ci{
55948c2ecf20Sopenharmony_ci	int err;
55958c2ecf20Sopenharmony_ci
55968c2ecf20Sopenharmony_ci	err = devlink_fmsg_pair_nest_start(fmsg, name);
55978c2ecf20Sopenharmony_ci	if (err)
55988c2ecf20Sopenharmony_ci		return err;
55998c2ecf20Sopenharmony_ci
56008c2ecf20Sopenharmony_ci	err = devlink_fmsg_string_put(fmsg, value);
56018c2ecf20Sopenharmony_ci	if (err)
56028c2ecf20Sopenharmony_ci		return err;
56038c2ecf20Sopenharmony_ci
56048c2ecf20Sopenharmony_ci	err = devlink_fmsg_pair_nest_end(fmsg);
56058c2ecf20Sopenharmony_ci	if (err)
56068c2ecf20Sopenharmony_ci		return err;
56078c2ecf20Sopenharmony_ci
56088c2ecf20Sopenharmony_ci	return 0;
56098c2ecf20Sopenharmony_ci}
56108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_string_pair_put);
56118c2ecf20Sopenharmony_ci
56128c2ecf20Sopenharmony_ciint devlink_fmsg_binary_pair_put(struct devlink_fmsg *fmsg, const char *name,
56138c2ecf20Sopenharmony_ci				 const void *value, u32 value_len)
56148c2ecf20Sopenharmony_ci{
56158c2ecf20Sopenharmony_ci	u32 data_size;
56168c2ecf20Sopenharmony_ci	int end_err;
56178c2ecf20Sopenharmony_ci	u32 offset;
56188c2ecf20Sopenharmony_ci	int err;
56198c2ecf20Sopenharmony_ci
56208c2ecf20Sopenharmony_ci	err = devlink_fmsg_binary_pair_nest_start(fmsg, name);
56218c2ecf20Sopenharmony_ci	if (err)
56228c2ecf20Sopenharmony_ci		return err;
56238c2ecf20Sopenharmony_ci
56248c2ecf20Sopenharmony_ci	for (offset = 0; offset < value_len; offset += data_size) {
56258c2ecf20Sopenharmony_ci		data_size = value_len - offset;
56268c2ecf20Sopenharmony_ci		if (data_size > DEVLINK_FMSG_MAX_SIZE)
56278c2ecf20Sopenharmony_ci			data_size = DEVLINK_FMSG_MAX_SIZE;
56288c2ecf20Sopenharmony_ci		err = devlink_fmsg_binary_put(fmsg, value + offset, data_size);
56298c2ecf20Sopenharmony_ci		if (err)
56308c2ecf20Sopenharmony_ci			break;
56318c2ecf20Sopenharmony_ci		/* Exit from loop with a break (instead of
56328c2ecf20Sopenharmony_ci		 * return) to make sure putting_binary is turned off in
56338c2ecf20Sopenharmony_ci		 * devlink_fmsg_binary_pair_nest_end
56348c2ecf20Sopenharmony_ci		 */
56358c2ecf20Sopenharmony_ci	}
56368c2ecf20Sopenharmony_ci
56378c2ecf20Sopenharmony_ci	end_err = devlink_fmsg_binary_pair_nest_end(fmsg);
56388c2ecf20Sopenharmony_ci	if (end_err)
56398c2ecf20Sopenharmony_ci		err = end_err;
56408c2ecf20Sopenharmony_ci
56418c2ecf20Sopenharmony_ci	return err;
56428c2ecf20Sopenharmony_ci}
56438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_fmsg_binary_pair_put);
56448c2ecf20Sopenharmony_ci
56458c2ecf20Sopenharmony_cistatic int
56468c2ecf20Sopenharmony_cidevlink_fmsg_item_fill_type(struct devlink_fmsg_item *msg, struct sk_buff *skb)
56478c2ecf20Sopenharmony_ci{
56488c2ecf20Sopenharmony_ci	switch (msg->nla_type) {
56498c2ecf20Sopenharmony_ci	case NLA_FLAG:
56508c2ecf20Sopenharmony_ci	case NLA_U8:
56518c2ecf20Sopenharmony_ci	case NLA_U32:
56528c2ecf20Sopenharmony_ci	case NLA_U64:
56538c2ecf20Sopenharmony_ci	case NLA_NUL_STRING:
56548c2ecf20Sopenharmony_ci	case NLA_BINARY:
56558c2ecf20Sopenharmony_ci		return nla_put_u8(skb, DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE,
56568c2ecf20Sopenharmony_ci				  msg->nla_type);
56578c2ecf20Sopenharmony_ci	default:
56588c2ecf20Sopenharmony_ci		return -EINVAL;
56598c2ecf20Sopenharmony_ci	}
56608c2ecf20Sopenharmony_ci}
56618c2ecf20Sopenharmony_ci
56628c2ecf20Sopenharmony_cistatic int
56638c2ecf20Sopenharmony_cidevlink_fmsg_item_fill_data(struct devlink_fmsg_item *msg, struct sk_buff *skb)
56648c2ecf20Sopenharmony_ci{
56658c2ecf20Sopenharmony_ci	int attrtype = DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA;
56668c2ecf20Sopenharmony_ci	u8 tmp;
56678c2ecf20Sopenharmony_ci
56688c2ecf20Sopenharmony_ci	switch (msg->nla_type) {
56698c2ecf20Sopenharmony_ci	case NLA_FLAG:
56708c2ecf20Sopenharmony_ci		/* Always provide flag data, regardless of its value */
56718c2ecf20Sopenharmony_ci		tmp = *(bool *) msg->value;
56728c2ecf20Sopenharmony_ci
56738c2ecf20Sopenharmony_ci		return nla_put_u8(skb, attrtype, tmp);
56748c2ecf20Sopenharmony_ci	case NLA_U8:
56758c2ecf20Sopenharmony_ci		return nla_put_u8(skb, attrtype, *(u8 *) msg->value);
56768c2ecf20Sopenharmony_ci	case NLA_U32:
56778c2ecf20Sopenharmony_ci		return nla_put_u32(skb, attrtype, *(u32 *) msg->value);
56788c2ecf20Sopenharmony_ci	case NLA_U64:
56798c2ecf20Sopenharmony_ci		return nla_put_u64_64bit(skb, attrtype, *(u64 *) msg->value,
56808c2ecf20Sopenharmony_ci					 DEVLINK_ATTR_PAD);
56818c2ecf20Sopenharmony_ci	case NLA_NUL_STRING:
56828c2ecf20Sopenharmony_ci		return nla_put_string(skb, attrtype, (char *) &msg->value);
56838c2ecf20Sopenharmony_ci	case NLA_BINARY:
56848c2ecf20Sopenharmony_ci		return nla_put(skb, attrtype, msg->len, (void *) &msg->value);
56858c2ecf20Sopenharmony_ci	default:
56868c2ecf20Sopenharmony_ci		return -EINVAL;
56878c2ecf20Sopenharmony_ci	}
56888c2ecf20Sopenharmony_ci}
56898c2ecf20Sopenharmony_ci
56908c2ecf20Sopenharmony_cistatic int
56918c2ecf20Sopenharmony_cidevlink_fmsg_prepare_skb(struct devlink_fmsg *fmsg, struct sk_buff *skb,
56928c2ecf20Sopenharmony_ci			 int *start)
56938c2ecf20Sopenharmony_ci{
56948c2ecf20Sopenharmony_ci	struct devlink_fmsg_item *item;
56958c2ecf20Sopenharmony_ci	struct nlattr *fmsg_nlattr;
56968c2ecf20Sopenharmony_ci	int i = 0;
56978c2ecf20Sopenharmony_ci	int err;
56988c2ecf20Sopenharmony_ci
56998c2ecf20Sopenharmony_ci	fmsg_nlattr = nla_nest_start_noflag(skb, DEVLINK_ATTR_FMSG);
57008c2ecf20Sopenharmony_ci	if (!fmsg_nlattr)
57018c2ecf20Sopenharmony_ci		return -EMSGSIZE;
57028c2ecf20Sopenharmony_ci
57038c2ecf20Sopenharmony_ci	list_for_each_entry(item, &fmsg->item_list, list) {
57048c2ecf20Sopenharmony_ci		if (i < *start) {
57058c2ecf20Sopenharmony_ci			i++;
57068c2ecf20Sopenharmony_ci			continue;
57078c2ecf20Sopenharmony_ci		}
57088c2ecf20Sopenharmony_ci
57098c2ecf20Sopenharmony_ci		switch (item->attrtype) {
57108c2ecf20Sopenharmony_ci		case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
57118c2ecf20Sopenharmony_ci		case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
57128c2ecf20Sopenharmony_ci		case DEVLINK_ATTR_FMSG_ARR_NEST_START:
57138c2ecf20Sopenharmony_ci		case DEVLINK_ATTR_FMSG_NEST_END:
57148c2ecf20Sopenharmony_ci			err = nla_put_flag(skb, item->attrtype);
57158c2ecf20Sopenharmony_ci			break;
57168c2ecf20Sopenharmony_ci		case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
57178c2ecf20Sopenharmony_ci			err = devlink_fmsg_item_fill_type(item, skb);
57188c2ecf20Sopenharmony_ci			if (err)
57198c2ecf20Sopenharmony_ci				break;
57208c2ecf20Sopenharmony_ci			err = devlink_fmsg_item_fill_data(item, skb);
57218c2ecf20Sopenharmony_ci			break;
57228c2ecf20Sopenharmony_ci		case DEVLINK_ATTR_FMSG_OBJ_NAME:
57238c2ecf20Sopenharmony_ci			err = nla_put_string(skb, item->attrtype,
57248c2ecf20Sopenharmony_ci					     (char *) &item->value);
57258c2ecf20Sopenharmony_ci			break;
57268c2ecf20Sopenharmony_ci		default:
57278c2ecf20Sopenharmony_ci			err = -EINVAL;
57288c2ecf20Sopenharmony_ci			break;
57298c2ecf20Sopenharmony_ci		}
57308c2ecf20Sopenharmony_ci		if (!err)
57318c2ecf20Sopenharmony_ci			*start = ++i;
57328c2ecf20Sopenharmony_ci		else
57338c2ecf20Sopenharmony_ci			break;
57348c2ecf20Sopenharmony_ci	}
57358c2ecf20Sopenharmony_ci
57368c2ecf20Sopenharmony_ci	nla_nest_end(skb, fmsg_nlattr);
57378c2ecf20Sopenharmony_ci	return err;
57388c2ecf20Sopenharmony_ci}
57398c2ecf20Sopenharmony_ci
57408c2ecf20Sopenharmony_cistatic int devlink_fmsg_snd(struct devlink_fmsg *fmsg,
57418c2ecf20Sopenharmony_ci			    struct genl_info *info,
57428c2ecf20Sopenharmony_ci			    enum devlink_command cmd, int flags)
57438c2ecf20Sopenharmony_ci{
57448c2ecf20Sopenharmony_ci	struct nlmsghdr *nlh;
57458c2ecf20Sopenharmony_ci	struct sk_buff *skb;
57468c2ecf20Sopenharmony_ci	bool last = false;
57478c2ecf20Sopenharmony_ci	int index = 0;
57488c2ecf20Sopenharmony_ci	void *hdr;
57498c2ecf20Sopenharmony_ci	int err;
57508c2ecf20Sopenharmony_ci
57518c2ecf20Sopenharmony_ci	while (!last) {
57528c2ecf20Sopenharmony_ci		int tmp_index = index;
57538c2ecf20Sopenharmony_ci
57548c2ecf20Sopenharmony_ci		skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
57558c2ecf20Sopenharmony_ci		if (!skb)
57568c2ecf20Sopenharmony_ci			return -ENOMEM;
57578c2ecf20Sopenharmony_ci
57588c2ecf20Sopenharmony_ci		hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
57598c2ecf20Sopenharmony_ci				  &devlink_nl_family, flags | NLM_F_MULTI, cmd);
57608c2ecf20Sopenharmony_ci		if (!hdr) {
57618c2ecf20Sopenharmony_ci			err = -EMSGSIZE;
57628c2ecf20Sopenharmony_ci			goto nla_put_failure;
57638c2ecf20Sopenharmony_ci		}
57648c2ecf20Sopenharmony_ci
57658c2ecf20Sopenharmony_ci		err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
57668c2ecf20Sopenharmony_ci		if (!err)
57678c2ecf20Sopenharmony_ci			last = true;
57688c2ecf20Sopenharmony_ci		else if (err != -EMSGSIZE || tmp_index == index)
57698c2ecf20Sopenharmony_ci			goto nla_put_failure;
57708c2ecf20Sopenharmony_ci
57718c2ecf20Sopenharmony_ci		genlmsg_end(skb, hdr);
57728c2ecf20Sopenharmony_ci		err = genlmsg_reply(skb, info);
57738c2ecf20Sopenharmony_ci		if (err)
57748c2ecf20Sopenharmony_ci			return err;
57758c2ecf20Sopenharmony_ci	}
57768c2ecf20Sopenharmony_ci
57778c2ecf20Sopenharmony_ci	skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
57788c2ecf20Sopenharmony_ci	if (!skb)
57798c2ecf20Sopenharmony_ci		return -ENOMEM;
57808c2ecf20Sopenharmony_ci	nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
57818c2ecf20Sopenharmony_ci			NLMSG_DONE, 0, flags | NLM_F_MULTI);
57828c2ecf20Sopenharmony_ci	if (!nlh) {
57838c2ecf20Sopenharmony_ci		err = -EMSGSIZE;
57848c2ecf20Sopenharmony_ci		goto nla_put_failure;
57858c2ecf20Sopenharmony_ci	}
57868c2ecf20Sopenharmony_ci
57878c2ecf20Sopenharmony_ci	return genlmsg_reply(skb, info);
57888c2ecf20Sopenharmony_ci
57898c2ecf20Sopenharmony_cinla_put_failure:
57908c2ecf20Sopenharmony_ci	nlmsg_free(skb);
57918c2ecf20Sopenharmony_ci	return err;
57928c2ecf20Sopenharmony_ci}
57938c2ecf20Sopenharmony_ci
57948c2ecf20Sopenharmony_cistatic int devlink_fmsg_dumpit(struct devlink_fmsg *fmsg, struct sk_buff *skb,
57958c2ecf20Sopenharmony_ci			       struct netlink_callback *cb,
57968c2ecf20Sopenharmony_ci			       enum devlink_command cmd)
57978c2ecf20Sopenharmony_ci{
57988c2ecf20Sopenharmony_ci	int index = cb->args[0];
57998c2ecf20Sopenharmony_ci	int tmp_index = index;
58008c2ecf20Sopenharmony_ci	void *hdr;
58018c2ecf20Sopenharmony_ci	int err;
58028c2ecf20Sopenharmony_ci
58038c2ecf20Sopenharmony_ci	hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
58048c2ecf20Sopenharmony_ci			  &devlink_nl_family, NLM_F_ACK | NLM_F_MULTI, cmd);
58058c2ecf20Sopenharmony_ci	if (!hdr) {
58068c2ecf20Sopenharmony_ci		err = -EMSGSIZE;
58078c2ecf20Sopenharmony_ci		goto nla_put_failure;
58088c2ecf20Sopenharmony_ci	}
58098c2ecf20Sopenharmony_ci
58108c2ecf20Sopenharmony_ci	err = devlink_fmsg_prepare_skb(fmsg, skb, &index);
58118c2ecf20Sopenharmony_ci	if ((err && err != -EMSGSIZE) || tmp_index == index)
58128c2ecf20Sopenharmony_ci		goto nla_put_failure;
58138c2ecf20Sopenharmony_ci
58148c2ecf20Sopenharmony_ci	cb->args[0] = index;
58158c2ecf20Sopenharmony_ci	genlmsg_end(skb, hdr);
58168c2ecf20Sopenharmony_ci	return skb->len;
58178c2ecf20Sopenharmony_ci
58188c2ecf20Sopenharmony_cinla_put_failure:
58198c2ecf20Sopenharmony_ci	genlmsg_cancel(skb, hdr);
58208c2ecf20Sopenharmony_ci	return err;
58218c2ecf20Sopenharmony_ci}
58228c2ecf20Sopenharmony_ci
58238c2ecf20Sopenharmony_cistruct devlink_health_reporter {
58248c2ecf20Sopenharmony_ci	struct list_head list;
58258c2ecf20Sopenharmony_ci	void *priv;
58268c2ecf20Sopenharmony_ci	const struct devlink_health_reporter_ops *ops;
58278c2ecf20Sopenharmony_ci	struct devlink *devlink;
58288c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port;
58298c2ecf20Sopenharmony_ci	struct devlink_fmsg *dump_fmsg;
58308c2ecf20Sopenharmony_ci	struct mutex dump_lock; /* lock parallel read/write from dump buffers */
58318c2ecf20Sopenharmony_ci	u64 graceful_period;
58328c2ecf20Sopenharmony_ci	bool auto_recover;
58338c2ecf20Sopenharmony_ci	bool auto_dump;
58348c2ecf20Sopenharmony_ci	u8 health_state;
58358c2ecf20Sopenharmony_ci	u64 dump_ts;
58368c2ecf20Sopenharmony_ci	u64 dump_real_ts;
58378c2ecf20Sopenharmony_ci	u64 error_count;
58388c2ecf20Sopenharmony_ci	u64 recovery_count;
58398c2ecf20Sopenharmony_ci	u64 last_recovery_ts;
58408c2ecf20Sopenharmony_ci	refcount_t refcount;
58418c2ecf20Sopenharmony_ci};
58428c2ecf20Sopenharmony_ci
58438c2ecf20Sopenharmony_civoid *
58448c2ecf20Sopenharmony_cidevlink_health_reporter_priv(struct devlink_health_reporter *reporter)
58458c2ecf20Sopenharmony_ci{
58468c2ecf20Sopenharmony_ci	return reporter->priv;
58478c2ecf20Sopenharmony_ci}
58488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_health_reporter_priv);
58498c2ecf20Sopenharmony_ci
58508c2ecf20Sopenharmony_cistatic struct devlink_health_reporter *
58518c2ecf20Sopenharmony_ci__devlink_health_reporter_find_by_name(struct list_head *reporter_list,
58528c2ecf20Sopenharmony_ci				       struct mutex *list_lock,
58538c2ecf20Sopenharmony_ci				       const char *reporter_name)
58548c2ecf20Sopenharmony_ci{
58558c2ecf20Sopenharmony_ci	struct devlink_health_reporter *reporter;
58568c2ecf20Sopenharmony_ci
58578c2ecf20Sopenharmony_ci	lockdep_assert_held(list_lock);
58588c2ecf20Sopenharmony_ci	list_for_each_entry(reporter, reporter_list, list)
58598c2ecf20Sopenharmony_ci		if (!strcmp(reporter->ops->name, reporter_name))
58608c2ecf20Sopenharmony_ci			return reporter;
58618c2ecf20Sopenharmony_ci	return NULL;
58628c2ecf20Sopenharmony_ci}
58638c2ecf20Sopenharmony_ci
58648c2ecf20Sopenharmony_cistatic struct devlink_health_reporter *
58658c2ecf20Sopenharmony_cidevlink_health_reporter_find_by_name(struct devlink *devlink,
58668c2ecf20Sopenharmony_ci				     const char *reporter_name)
58678c2ecf20Sopenharmony_ci{
58688c2ecf20Sopenharmony_ci	return __devlink_health_reporter_find_by_name(&devlink->reporter_list,
58698c2ecf20Sopenharmony_ci						      &devlink->reporters_lock,
58708c2ecf20Sopenharmony_ci						      reporter_name);
58718c2ecf20Sopenharmony_ci}
58728c2ecf20Sopenharmony_ci
58738c2ecf20Sopenharmony_cistatic struct devlink_health_reporter *
58748c2ecf20Sopenharmony_cidevlink_port_health_reporter_find_by_name(struct devlink_port *devlink_port,
58758c2ecf20Sopenharmony_ci					  const char *reporter_name)
58768c2ecf20Sopenharmony_ci{
58778c2ecf20Sopenharmony_ci	return __devlink_health_reporter_find_by_name(&devlink_port->reporter_list,
58788c2ecf20Sopenharmony_ci						      &devlink_port->reporters_lock,
58798c2ecf20Sopenharmony_ci						      reporter_name);
58808c2ecf20Sopenharmony_ci}
58818c2ecf20Sopenharmony_ci
58828c2ecf20Sopenharmony_cistatic struct devlink_health_reporter *
58838c2ecf20Sopenharmony_ci__devlink_health_reporter_create(struct devlink *devlink,
58848c2ecf20Sopenharmony_ci				 const struct devlink_health_reporter_ops *ops,
58858c2ecf20Sopenharmony_ci				 u64 graceful_period, void *priv)
58868c2ecf20Sopenharmony_ci{
58878c2ecf20Sopenharmony_ci	struct devlink_health_reporter *reporter;
58888c2ecf20Sopenharmony_ci
58898c2ecf20Sopenharmony_ci	if (WARN_ON(graceful_period && !ops->recover))
58908c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
58918c2ecf20Sopenharmony_ci
58928c2ecf20Sopenharmony_ci	reporter = kzalloc(sizeof(*reporter), GFP_KERNEL);
58938c2ecf20Sopenharmony_ci	if (!reporter)
58948c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
58958c2ecf20Sopenharmony_ci
58968c2ecf20Sopenharmony_ci	reporter->priv = priv;
58978c2ecf20Sopenharmony_ci	reporter->ops = ops;
58988c2ecf20Sopenharmony_ci	reporter->devlink = devlink;
58998c2ecf20Sopenharmony_ci	reporter->graceful_period = graceful_period;
59008c2ecf20Sopenharmony_ci	reporter->auto_recover = !!ops->recover;
59018c2ecf20Sopenharmony_ci	reporter->auto_dump = !!ops->dump;
59028c2ecf20Sopenharmony_ci	mutex_init(&reporter->dump_lock);
59038c2ecf20Sopenharmony_ci	refcount_set(&reporter->refcount, 1);
59048c2ecf20Sopenharmony_ci	return reporter;
59058c2ecf20Sopenharmony_ci}
59068c2ecf20Sopenharmony_ci
59078c2ecf20Sopenharmony_ci/**
59088c2ecf20Sopenharmony_ci *	devlink_port_health_reporter_create - create devlink health reporter for
59098c2ecf20Sopenharmony_ci *	                                      specified port instance
59108c2ecf20Sopenharmony_ci *
59118c2ecf20Sopenharmony_ci *	@port: devlink_port which should contain the new reporter
59128c2ecf20Sopenharmony_ci *	@ops: ops
59138c2ecf20Sopenharmony_ci *	@graceful_period: to avoid recovery loops, in msecs
59148c2ecf20Sopenharmony_ci *	@priv: priv
59158c2ecf20Sopenharmony_ci */
59168c2ecf20Sopenharmony_cistruct devlink_health_reporter *
59178c2ecf20Sopenharmony_cidevlink_port_health_reporter_create(struct devlink_port *port,
59188c2ecf20Sopenharmony_ci				    const struct devlink_health_reporter_ops *ops,
59198c2ecf20Sopenharmony_ci				    u64 graceful_period, void *priv)
59208c2ecf20Sopenharmony_ci{
59218c2ecf20Sopenharmony_ci	struct devlink_health_reporter *reporter;
59228c2ecf20Sopenharmony_ci
59238c2ecf20Sopenharmony_ci	mutex_lock(&port->reporters_lock);
59248c2ecf20Sopenharmony_ci	if (__devlink_health_reporter_find_by_name(&port->reporter_list,
59258c2ecf20Sopenharmony_ci						   &port->reporters_lock, ops->name)) {
59268c2ecf20Sopenharmony_ci		reporter = ERR_PTR(-EEXIST);
59278c2ecf20Sopenharmony_ci		goto unlock;
59288c2ecf20Sopenharmony_ci	}
59298c2ecf20Sopenharmony_ci
59308c2ecf20Sopenharmony_ci	reporter = __devlink_health_reporter_create(port->devlink, ops,
59318c2ecf20Sopenharmony_ci						    graceful_period, priv);
59328c2ecf20Sopenharmony_ci	if (IS_ERR(reporter))
59338c2ecf20Sopenharmony_ci		goto unlock;
59348c2ecf20Sopenharmony_ci
59358c2ecf20Sopenharmony_ci	reporter->devlink_port = port;
59368c2ecf20Sopenharmony_ci	list_add_tail(&reporter->list, &port->reporter_list);
59378c2ecf20Sopenharmony_ciunlock:
59388c2ecf20Sopenharmony_ci	mutex_unlock(&port->reporters_lock);
59398c2ecf20Sopenharmony_ci	return reporter;
59408c2ecf20Sopenharmony_ci}
59418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_health_reporter_create);
59428c2ecf20Sopenharmony_ci
59438c2ecf20Sopenharmony_ci/**
59448c2ecf20Sopenharmony_ci *	devlink_health_reporter_create - create devlink health reporter
59458c2ecf20Sopenharmony_ci *
59468c2ecf20Sopenharmony_ci *	@devlink: devlink
59478c2ecf20Sopenharmony_ci *	@ops: ops
59488c2ecf20Sopenharmony_ci *	@graceful_period: to avoid recovery loops, in msecs
59498c2ecf20Sopenharmony_ci *	@priv: priv
59508c2ecf20Sopenharmony_ci */
59518c2ecf20Sopenharmony_cistruct devlink_health_reporter *
59528c2ecf20Sopenharmony_cidevlink_health_reporter_create(struct devlink *devlink,
59538c2ecf20Sopenharmony_ci			       const struct devlink_health_reporter_ops *ops,
59548c2ecf20Sopenharmony_ci			       u64 graceful_period, void *priv)
59558c2ecf20Sopenharmony_ci{
59568c2ecf20Sopenharmony_ci	struct devlink_health_reporter *reporter;
59578c2ecf20Sopenharmony_ci
59588c2ecf20Sopenharmony_ci	mutex_lock(&devlink->reporters_lock);
59598c2ecf20Sopenharmony_ci	if (devlink_health_reporter_find_by_name(devlink, ops->name)) {
59608c2ecf20Sopenharmony_ci		reporter = ERR_PTR(-EEXIST);
59618c2ecf20Sopenharmony_ci		goto unlock;
59628c2ecf20Sopenharmony_ci	}
59638c2ecf20Sopenharmony_ci
59648c2ecf20Sopenharmony_ci	reporter = __devlink_health_reporter_create(devlink, ops,
59658c2ecf20Sopenharmony_ci						    graceful_period, priv);
59668c2ecf20Sopenharmony_ci	if (IS_ERR(reporter))
59678c2ecf20Sopenharmony_ci		goto unlock;
59688c2ecf20Sopenharmony_ci
59698c2ecf20Sopenharmony_ci	list_add_tail(&reporter->list, &devlink->reporter_list);
59708c2ecf20Sopenharmony_ciunlock:
59718c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->reporters_lock);
59728c2ecf20Sopenharmony_ci	return reporter;
59738c2ecf20Sopenharmony_ci}
59748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_health_reporter_create);
59758c2ecf20Sopenharmony_ci
59768c2ecf20Sopenharmony_cistatic void
59778c2ecf20Sopenharmony_cidevlink_health_reporter_free(struct devlink_health_reporter *reporter)
59788c2ecf20Sopenharmony_ci{
59798c2ecf20Sopenharmony_ci	mutex_destroy(&reporter->dump_lock);
59808c2ecf20Sopenharmony_ci	if (reporter->dump_fmsg)
59818c2ecf20Sopenharmony_ci		devlink_fmsg_free(reporter->dump_fmsg);
59828c2ecf20Sopenharmony_ci	kfree(reporter);
59838c2ecf20Sopenharmony_ci}
59848c2ecf20Sopenharmony_ci
59858c2ecf20Sopenharmony_cistatic void
59868c2ecf20Sopenharmony_cidevlink_health_reporter_put(struct devlink_health_reporter *reporter)
59878c2ecf20Sopenharmony_ci{
59888c2ecf20Sopenharmony_ci	if (refcount_dec_and_test(&reporter->refcount))
59898c2ecf20Sopenharmony_ci		devlink_health_reporter_free(reporter);
59908c2ecf20Sopenharmony_ci}
59918c2ecf20Sopenharmony_ci
59928c2ecf20Sopenharmony_cistatic void
59938c2ecf20Sopenharmony_ci__devlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
59948c2ecf20Sopenharmony_ci{
59958c2ecf20Sopenharmony_ci	list_del(&reporter->list);
59968c2ecf20Sopenharmony_ci	devlink_health_reporter_put(reporter);
59978c2ecf20Sopenharmony_ci}
59988c2ecf20Sopenharmony_ci
59998c2ecf20Sopenharmony_ci/**
60008c2ecf20Sopenharmony_ci *	devlink_health_reporter_destroy - destroy devlink health reporter
60018c2ecf20Sopenharmony_ci *
60028c2ecf20Sopenharmony_ci *	@reporter: devlink health reporter to destroy
60038c2ecf20Sopenharmony_ci */
60048c2ecf20Sopenharmony_civoid
60058c2ecf20Sopenharmony_cidevlink_health_reporter_destroy(struct devlink_health_reporter *reporter)
60068c2ecf20Sopenharmony_ci{
60078c2ecf20Sopenharmony_ci	struct mutex *lock = &reporter->devlink->reporters_lock;
60088c2ecf20Sopenharmony_ci
60098c2ecf20Sopenharmony_ci	mutex_lock(lock);
60108c2ecf20Sopenharmony_ci	__devlink_health_reporter_destroy(reporter);
60118c2ecf20Sopenharmony_ci	mutex_unlock(lock);
60128c2ecf20Sopenharmony_ci}
60138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_health_reporter_destroy);
60148c2ecf20Sopenharmony_ci
60158c2ecf20Sopenharmony_ci/**
60168c2ecf20Sopenharmony_ci *	devlink_port_health_reporter_destroy - destroy devlink port health reporter
60178c2ecf20Sopenharmony_ci *
60188c2ecf20Sopenharmony_ci *	@reporter: devlink health reporter to destroy
60198c2ecf20Sopenharmony_ci */
60208c2ecf20Sopenharmony_civoid
60218c2ecf20Sopenharmony_cidevlink_port_health_reporter_destroy(struct devlink_health_reporter *reporter)
60228c2ecf20Sopenharmony_ci{
60238c2ecf20Sopenharmony_ci	struct mutex *lock = &reporter->devlink_port->reporters_lock;
60248c2ecf20Sopenharmony_ci
60258c2ecf20Sopenharmony_ci	mutex_lock(lock);
60268c2ecf20Sopenharmony_ci	__devlink_health_reporter_destroy(reporter);
60278c2ecf20Sopenharmony_ci	mutex_unlock(lock);
60288c2ecf20Sopenharmony_ci}
60298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_health_reporter_destroy);
60308c2ecf20Sopenharmony_ci
60318c2ecf20Sopenharmony_cistatic int
60328c2ecf20Sopenharmony_cidevlink_nl_health_reporter_fill(struct sk_buff *msg,
60338c2ecf20Sopenharmony_ci				struct devlink *devlink,
60348c2ecf20Sopenharmony_ci				struct devlink_health_reporter *reporter,
60358c2ecf20Sopenharmony_ci				enum devlink_command cmd, u32 portid,
60368c2ecf20Sopenharmony_ci				u32 seq, int flags)
60378c2ecf20Sopenharmony_ci{
60388c2ecf20Sopenharmony_ci	struct nlattr *reporter_attr;
60398c2ecf20Sopenharmony_ci	void *hdr;
60408c2ecf20Sopenharmony_ci
60418c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
60428c2ecf20Sopenharmony_ci	if (!hdr)
60438c2ecf20Sopenharmony_ci		return -EMSGSIZE;
60448c2ecf20Sopenharmony_ci
60458c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(msg, devlink))
60468c2ecf20Sopenharmony_ci		goto genlmsg_cancel;
60478c2ecf20Sopenharmony_ci
60488c2ecf20Sopenharmony_ci	if (reporter->devlink_port) {
60498c2ecf20Sopenharmony_ci		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, reporter->devlink_port->index))
60508c2ecf20Sopenharmony_ci			goto genlmsg_cancel;
60518c2ecf20Sopenharmony_ci	}
60528c2ecf20Sopenharmony_ci	reporter_attr = nla_nest_start_noflag(msg,
60538c2ecf20Sopenharmony_ci					      DEVLINK_ATTR_HEALTH_REPORTER);
60548c2ecf20Sopenharmony_ci	if (!reporter_attr)
60558c2ecf20Sopenharmony_ci		goto genlmsg_cancel;
60568c2ecf20Sopenharmony_ci	if (nla_put_string(msg, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
60578c2ecf20Sopenharmony_ci			   reporter->ops->name))
60588c2ecf20Sopenharmony_ci		goto reporter_nest_cancel;
60598c2ecf20Sopenharmony_ci	if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
60608c2ecf20Sopenharmony_ci		       reporter->health_state))
60618c2ecf20Sopenharmony_ci		goto reporter_nest_cancel;
60628c2ecf20Sopenharmony_ci	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
60638c2ecf20Sopenharmony_ci			      reporter->error_count, DEVLINK_ATTR_PAD))
60648c2ecf20Sopenharmony_ci		goto reporter_nest_cancel;
60658c2ecf20Sopenharmony_ci	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
60668c2ecf20Sopenharmony_ci			      reporter->recovery_count, DEVLINK_ATTR_PAD))
60678c2ecf20Sopenharmony_ci		goto reporter_nest_cancel;
60688c2ecf20Sopenharmony_ci	if (reporter->ops->recover &&
60698c2ecf20Sopenharmony_ci	    nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
60708c2ecf20Sopenharmony_ci			      reporter->graceful_period,
60718c2ecf20Sopenharmony_ci			      DEVLINK_ATTR_PAD))
60728c2ecf20Sopenharmony_ci		goto reporter_nest_cancel;
60738c2ecf20Sopenharmony_ci	if (reporter->ops->recover &&
60748c2ecf20Sopenharmony_ci	    nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
60758c2ecf20Sopenharmony_ci		       reporter->auto_recover))
60768c2ecf20Sopenharmony_ci		goto reporter_nest_cancel;
60778c2ecf20Sopenharmony_ci	if (reporter->dump_fmsg &&
60788c2ecf20Sopenharmony_ci	    nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS,
60798c2ecf20Sopenharmony_ci			      jiffies_to_msecs(reporter->dump_ts),
60808c2ecf20Sopenharmony_ci			      DEVLINK_ATTR_PAD))
60818c2ecf20Sopenharmony_ci		goto reporter_nest_cancel;
60828c2ecf20Sopenharmony_ci	if (reporter->dump_fmsg &&
60838c2ecf20Sopenharmony_ci	    nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS,
60848c2ecf20Sopenharmony_ci			      reporter->dump_real_ts, DEVLINK_ATTR_PAD))
60858c2ecf20Sopenharmony_ci		goto reporter_nest_cancel;
60868c2ecf20Sopenharmony_ci	if (reporter->ops->dump &&
60878c2ecf20Sopenharmony_ci	    nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
60888c2ecf20Sopenharmony_ci		       reporter->auto_dump))
60898c2ecf20Sopenharmony_ci		goto reporter_nest_cancel;
60908c2ecf20Sopenharmony_ci
60918c2ecf20Sopenharmony_ci	nla_nest_end(msg, reporter_attr);
60928c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
60938c2ecf20Sopenharmony_ci	return 0;
60948c2ecf20Sopenharmony_ci
60958c2ecf20Sopenharmony_cireporter_nest_cancel:
60968c2ecf20Sopenharmony_ci	nla_nest_end(msg, reporter_attr);
60978c2ecf20Sopenharmony_cigenlmsg_cancel:
60988c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
60998c2ecf20Sopenharmony_ci	return -EMSGSIZE;
61008c2ecf20Sopenharmony_ci}
61018c2ecf20Sopenharmony_ci
61028c2ecf20Sopenharmony_cistatic void devlink_recover_notify(struct devlink_health_reporter *reporter,
61038c2ecf20Sopenharmony_ci				   enum devlink_command cmd)
61048c2ecf20Sopenharmony_ci{
61058c2ecf20Sopenharmony_ci	struct sk_buff *msg;
61068c2ecf20Sopenharmony_ci	int err;
61078c2ecf20Sopenharmony_ci
61088c2ecf20Sopenharmony_ci	WARN_ON(cmd != DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
61098c2ecf20Sopenharmony_ci
61108c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
61118c2ecf20Sopenharmony_ci	if (!msg)
61128c2ecf20Sopenharmony_ci		return;
61138c2ecf20Sopenharmony_ci
61148c2ecf20Sopenharmony_ci	err = devlink_nl_health_reporter_fill(msg, reporter->devlink,
61158c2ecf20Sopenharmony_ci					      reporter, cmd, 0, 0, 0);
61168c2ecf20Sopenharmony_ci	if (err) {
61178c2ecf20Sopenharmony_ci		nlmsg_free(msg);
61188c2ecf20Sopenharmony_ci		return;
61198c2ecf20Sopenharmony_ci	}
61208c2ecf20Sopenharmony_ci
61218c2ecf20Sopenharmony_ci	genlmsg_multicast_netns(&devlink_nl_family,
61228c2ecf20Sopenharmony_ci				devlink_net(reporter->devlink),
61238c2ecf20Sopenharmony_ci				msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
61248c2ecf20Sopenharmony_ci}
61258c2ecf20Sopenharmony_ci
61268c2ecf20Sopenharmony_civoid
61278c2ecf20Sopenharmony_cidevlink_health_reporter_recovery_done(struct devlink_health_reporter *reporter)
61288c2ecf20Sopenharmony_ci{
61298c2ecf20Sopenharmony_ci	reporter->recovery_count++;
61308c2ecf20Sopenharmony_ci	reporter->last_recovery_ts = jiffies;
61318c2ecf20Sopenharmony_ci}
61328c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_health_reporter_recovery_done);
61338c2ecf20Sopenharmony_ci
61348c2ecf20Sopenharmony_cistatic int
61358c2ecf20Sopenharmony_cidevlink_health_reporter_recover(struct devlink_health_reporter *reporter,
61368c2ecf20Sopenharmony_ci				void *priv_ctx, struct netlink_ext_ack *extack)
61378c2ecf20Sopenharmony_ci{
61388c2ecf20Sopenharmony_ci	int err;
61398c2ecf20Sopenharmony_ci
61408c2ecf20Sopenharmony_ci	if (reporter->health_state == DEVLINK_HEALTH_REPORTER_STATE_HEALTHY)
61418c2ecf20Sopenharmony_ci		return 0;
61428c2ecf20Sopenharmony_ci
61438c2ecf20Sopenharmony_ci	if (!reporter->ops->recover)
61448c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
61458c2ecf20Sopenharmony_ci
61468c2ecf20Sopenharmony_ci	err = reporter->ops->recover(reporter, priv_ctx, extack);
61478c2ecf20Sopenharmony_ci	if (err)
61488c2ecf20Sopenharmony_ci		return err;
61498c2ecf20Sopenharmony_ci
61508c2ecf20Sopenharmony_ci	devlink_health_reporter_recovery_done(reporter);
61518c2ecf20Sopenharmony_ci	reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_HEALTHY;
61528c2ecf20Sopenharmony_ci	devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
61538c2ecf20Sopenharmony_ci
61548c2ecf20Sopenharmony_ci	return 0;
61558c2ecf20Sopenharmony_ci}
61568c2ecf20Sopenharmony_ci
61578c2ecf20Sopenharmony_cistatic void
61588c2ecf20Sopenharmony_cidevlink_health_dump_clear(struct devlink_health_reporter *reporter)
61598c2ecf20Sopenharmony_ci{
61608c2ecf20Sopenharmony_ci	if (!reporter->dump_fmsg)
61618c2ecf20Sopenharmony_ci		return;
61628c2ecf20Sopenharmony_ci	devlink_fmsg_free(reporter->dump_fmsg);
61638c2ecf20Sopenharmony_ci	reporter->dump_fmsg = NULL;
61648c2ecf20Sopenharmony_ci}
61658c2ecf20Sopenharmony_ci
61668c2ecf20Sopenharmony_cistatic int devlink_health_do_dump(struct devlink_health_reporter *reporter,
61678c2ecf20Sopenharmony_ci				  void *priv_ctx,
61688c2ecf20Sopenharmony_ci				  struct netlink_ext_ack *extack)
61698c2ecf20Sopenharmony_ci{
61708c2ecf20Sopenharmony_ci	int err;
61718c2ecf20Sopenharmony_ci
61728c2ecf20Sopenharmony_ci	if (!reporter->ops->dump)
61738c2ecf20Sopenharmony_ci		return 0;
61748c2ecf20Sopenharmony_ci
61758c2ecf20Sopenharmony_ci	if (reporter->dump_fmsg)
61768c2ecf20Sopenharmony_ci		return 0;
61778c2ecf20Sopenharmony_ci
61788c2ecf20Sopenharmony_ci	reporter->dump_fmsg = devlink_fmsg_alloc();
61798c2ecf20Sopenharmony_ci	if (!reporter->dump_fmsg) {
61808c2ecf20Sopenharmony_ci		err = -ENOMEM;
61818c2ecf20Sopenharmony_ci		return err;
61828c2ecf20Sopenharmony_ci	}
61838c2ecf20Sopenharmony_ci
61848c2ecf20Sopenharmony_ci	err = devlink_fmsg_obj_nest_start(reporter->dump_fmsg);
61858c2ecf20Sopenharmony_ci	if (err)
61868c2ecf20Sopenharmony_ci		goto dump_err;
61878c2ecf20Sopenharmony_ci
61888c2ecf20Sopenharmony_ci	err = reporter->ops->dump(reporter, reporter->dump_fmsg,
61898c2ecf20Sopenharmony_ci				  priv_ctx, extack);
61908c2ecf20Sopenharmony_ci	if (err)
61918c2ecf20Sopenharmony_ci		goto dump_err;
61928c2ecf20Sopenharmony_ci
61938c2ecf20Sopenharmony_ci	err = devlink_fmsg_obj_nest_end(reporter->dump_fmsg);
61948c2ecf20Sopenharmony_ci	if (err)
61958c2ecf20Sopenharmony_ci		goto dump_err;
61968c2ecf20Sopenharmony_ci
61978c2ecf20Sopenharmony_ci	reporter->dump_ts = jiffies;
61988c2ecf20Sopenharmony_ci	reporter->dump_real_ts = ktime_get_real_ns();
61998c2ecf20Sopenharmony_ci
62008c2ecf20Sopenharmony_ci	return 0;
62018c2ecf20Sopenharmony_ci
62028c2ecf20Sopenharmony_cidump_err:
62038c2ecf20Sopenharmony_ci	devlink_health_dump_clear(reporter);
62048c2ecf20Sopenharmony_ci	return err;
62058c2ecf20Sopenharmony_ci}
62068c2ecf20Sopenharmony_ci
62078c2ecf20Sopenharmony_ciint devlink_health_report(struct devlink_health_reporter *reporter,
62088c2ecf20Sopenharmony_ci			  const char *msg, void *priv_ctx)
62098c2ecf20Sopenharmony_ci{
62108c2ecf20Sopenharmony_ci	enum devlink_health_reporter_state prev_health_state;
62118c2ecf20Sopenharmony_ci	struct devlink *devlink = reporter->devlink;
62128c2ecf20Sopenharmony_ci	unsigned long recover_ts_threshold;
62138c2ecf20Sopenharmony_ci
62148c2ecf20Sopenharmony_ci	/* write a log message of the current error */
62158c2ecf20Sopenharmony_ci	WARN_ON(!msg);
62168c2ecf20Sopenharmony_ci	trace_devlink_health_report(devlink, reporter->ops->name, msg);
62178c2ecf20Sopenharmony_ci	reporter->error_count++;
62188c2ecf20Sopenharmony_ci	prev_health_state = reporter->health_state;
62198c2ecf20Sopenharmony_ci	reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
62208c2ecf20Sopenharmony_ci	devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
62218c2ecf20Sopenharmony_ci
62228c2ecf20Sopenharmony_ci	/* abort if the previous error wasn't recovered */
62238c2ecf20Sopenharmony_ci	recover_ts_threshold = reporter->last_recovery_ts +
62248c2ecf20Sopenharmony_ci			       msecs_to_jiffies(reporter->graceful_period);
62258c2ecf20Sopenharmony_ci	if (reporter->auto_recover &&
62268c2ecf20Sopenharmony_ci	    (prev_health_state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY ||
62278c2ecf20Sopenharmony_ci	     (reporter->last_recovery_ts && reporter->recovery_count &&
62288c2ecf20Sopenharmony_ci	      time_is_after_jiffies(recover_ts_threshold)))) {
62298c2ecf20Sopenharmony_ci		trace_devlink_health_recover_aborted(devlink,
62308c2ecf20Sopenharmony_ci						     reporter->ops->name,
62318c2ecf20Sopenharmony_ci						     reporter->health_state,
62328c2ecf20Sopenharmony_ci						     jiffies -
62338c2ecf20Sopenharmony_ci						     reporter->last_recovery_ts);
62348c2ecf20Sopenharmony_ci		return -ECANCELED;
62358c2ecf20Sopenharmony_ci	}
62368c2ecf20Sopenharmony_ci
62378c2ecf20Sopenharmony_ci	reporter->health_state = DEVLINK_HEALTH_REPORTER_STATE_ERROR;
62388c2ecf20Sopenharmony_ci
62398c2ecf20Sopenharmony_ci	if (reporter->auto_dump) {
62408c2ecf20Sopenharmony_ci		mutex_lock(&reporter->dump_lock);
62418c2ecf20Sopenharmony_ci		/* store current dump of current error, for later analysis */
62428c2ecf20Sopenharmony_ci		devlink_health_do_dump(reporter, priv_ctx, NULL);
62438c2ecf20Sopenharmony_ci		mutex_unlock(&reporter->dump_lock);
62448c2ecf20Sopenharmony_ci	}
62458c2ecf20Sopenharmony_ci
62468c2ecf20Sopenharmony_ci	if (reporter->auto_recover)
62478c2ecf20Sopenharmony_ci		return devlink_health_reporter_recover(reporter,
62488c2ecf20Sopenharmony_ci						       priv_ctx, NULL);
62498c2ecf20Sopenharmony_ci
62508c2ecf20Sopenharmony_ci	return 0;
62518c2ecf20Sopenharmony_ci}
62528c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_health_report);
62538c2ecf20Sopenharmony_ci
62548c2ecf20Sopenharmony_cistatic struct devlink_health_reporter *
62558c2ecf20Sopenharmony_cidevlink_health_reporter_get_from_attrs(struct devlink *devlink,
62568c2ecf20Sopenharmony_ci				       struct nlattr **attrs)
62578c2ecf20Sopenharmony_ci{
62588c2ecf20Sopenharmony_ci	struct devlink_health_reporter *reporter;
62598c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port;
62608c2ecf20Sopenharmony_ci	char *reporter_name;
62618c2ecf20Sopenharmony_ci
62628c2ecf20Sopenharmony_ci	if (!attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME])
62638c2ecf20Sopenharmony_ci		return NULL;
62648c2ecf20Sopenharmony_ci
62658c2ecf20Sopenharmony_ci	reporter_name = nla_data(attrs[DEVLINK_ATTR_HEALTH_REPORTER_NAME]);
62668c2ecf20Sopenharmony_ci	devlink_port = devlink_port_get_from_attrs(devlink, attrs);
62678c2ecf20Sopenharmony_ci	if (IS_ERR(devlink_port)) {
62688c2ecf20Sopenharmony_ci		mutex_lock(&devlink->reporters_lock);
62698c2ecf20Sopenharmony_ci		reporter = devlink_health_reporter_find_by_name(devlink, reporter_name);
62708c2ecf20Sopenharmony_ci		if (reporter)
62718c2ecf20Sopenharmony_ci			refcount_inc(&reporter->refcount);
62728c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->reporters_lock);
62738c2ecf20Sopenharmony_ci	} else {
62748c2ecf20Sopenharmony_ci		mutex_lock(&devlink_port->reporters_lock);
62758c2ecf20Sopenharmony_ci		reporter = devlink_port_health_reporter_find_by_name(devlink_port, reporter_name);
62768c2ecf20Sopenharmony_ci		if (reporter)
62778c2ecf20Sopenharmony_ci			refcount_inc(&reporter->refcount);
62788c2ecf20Sopenharmony_ci		mutex_unlock(&devlink_port->reporters_lock);
62798c2ecf20Sopenharmony_ci	}
62808c2ecf20Sopenharmony_ci
62818c2ecf20Sopenharmony_ci	return reporter;
62828c2ecf20Sopenharmony_ci}
62838c2ecf20Sopenharmony_ci
62848c2ecf20Sopenharmony_cistatic struct devlink_health_reporter *
62858c2ecf20Sopenharmony_cidevlink_health_reporter_get_from_info(struct devlink *devlink,
62868c2ecf20Sopenharmony_ci				      struct genl_info *info)
62878c2ecf20Sopenharmony_ci{
62888c2ecf20Sopenharmony_ci	return devlink_health_reporter_get_from_attrs(devlink, info->attrs);
62898c2ecf20Sopenharmony_ci}
62908c2ecf20Sopenharmony_ci
62918c2ecf20Sopenharmony_cistatic struct devlink_health_reporter *
62928c2ecf20Sopenharmony_cidevlink_health_reporter_get_from_cb(struct netlink_callback *cb)
62938c2ecf20Sopenharmony_ci{
62948c2ecf20Sopenharmony_ci	const struct genl_dumpit_info *info = genl_dumpit_info(cb);
62958c2ecf20Sopenharmony_ci	struct devlink_health_reporter *reporter;
62968c2ecf20Sopenharmony_ci	struct nlattr **attrs = info->attrs;
62978c2ecf20Sopenharmony_ci	struct devlink *devlink;
62988c2ecf20Sopenharmony_ci
62998c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
63008c2ecf20Sopenharmony_ci	devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
63018c2ecf20Sopenharmony_ci	if (IS_ERR(devlink))
63028c2ecf20Sopenharmony_ci		goto unlock;
63038c2ecf20Sopenharmony_ci
63048c2ecf20Sopenharmony_ci	reporter = devlink_health_reporter_get_from_attrs(devlink, attrs);
63058c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
63068c2ecf20Sopenharmony_ci	return reporter;
63078c2ecf20Sopenharmony_ciunlock:
63088c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
63098c2ecf20Sopenharmony_ci	return NULL;
63108c2ecf20Sopenharmony_ci}
63118c2ecf20Sopenharmony_ci
63128c2ecf20Sopenharmony_civoid
63138c2ecf20Sopenharmony_cidevlink_health_reporter_state_update(struct devlink_health_reporter *reporter,
63148c2ecf20Sopenharmony_ci				     enum devlink_health_reporter_state state)
63158c2ecf20Sopenharmony_ci{
63168c2ecf20Sopenharmony_ci	if (WARN_ON(state != DEVLINK_HEALTH_REPORTER_STATE_HEALTHY &&
63178c2ecf20Sopenharmony_ci		    state != DEVLINK_HEALTH_REPORTER_STATE_ERROR))
63188c2ecf20Sopenharmony_ci		return;
63198c2ecf20Sopenharmony_ci
63208c2ecf20Sopenharmony_ci	if (reporter->health_state == state)
63218c2ecf20Sopenharmony_ci		return;
63228c2ecf20Sopenharmony_ci
63238c2ecf20Sopenharmony_ci	reporter->health_state = state;
63248c2ecf20Sopenharmony_ci	trace_devlink_health_reporter_state_update(reporter->devlink,
63258c2ecf20Sopenharmony_ci						   reporter->ops->name, state);
63268c2ecf20Sopenharmony_ci	devlink_recover_notify(reporter, DEVLINK_CMD_HEALTH_REPORTER_RECOVER);
63278c2ecf20Sopenharmony_ci}
63288c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_health_reporter_state_update);
63298c2ecf20Sopenharmony_ci
63308c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_health_reporter_get_doit(struct sk_buff *skb,
63318c2ecf20Sopenharmony_ci						   struct genl_info *info)
63328c2ecf20Sopenharmony_ci{
63338c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
63348c2ecf20Sopenharmony_ci	struct devlink_health_reporter *reporter;
63358c2ecf20Sopenharmony_ci	struct sk_buff *msg;
63368c2ecf20Sopenharmony_ci	int err;
63378c2ecf20Sopenharmony_ci
63388c2ecf20Sopenharmony_ci	reporter = devlink_health_reporter_get_from_info(devlink, info);
63398c2ecf20Sopenharmony_ci	if (!reporter)
63408c2ecf20Sopenharmony_ci		return -EINVAL;
63418c2ecf20Sopenharmony_ci
63428c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
63438c2ecf20Sopenharmony_ci	if (!msg) {
63448c2ecf20Sopenharmony_ci		err = -ENOMEM;
63458c2ecf20Sopenharmony_ci		goto out;
63468c2ecf20Sopenharmony_ci	}
63478c2ecf20Sopenharmony_ci
63488c2ecf20Sopenharmony_ci	err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
63498c2ecf20Sopenharmony_ci					      DEVLINK_CMD_HEALTH_REPORTER_GET,
63508c2ecf20Sopenharmony_ci					      info->snd_portid, info->snd_seq,
63518c2ecf20Sopenharmony_ci					      0);
63528c2ecf20Sopenharmony_ci	if (err) {
63538c2ecf20Sopenharmony_ci		nlmsg_free(msg);
63548c2ecf20Sopenharmony_ci		goto out;
63558c2ecf20Sopenharmony_ci	}
63568c2ecf20Sopenharmony_ci
63578c2ecf20Sopenharmony_ci	err = genlmsg_reply(msg, info);
63588c2ecf20Sopenharmony_ciout:
63598c2ecf20Sopenharmony_ci	devlink_health_reporter_put(reporter);
63608c2ecf20Sopenharmony_ci	return err;
63618c2ecf20Sopenharmony_ci}
63628c2ecf20Sopenharmony_ci
63638c2ecf20Sopenharmony_cistatic int
63648c2ecf20Sopenharmony_cidevlink_nl_cmd_health_reporter_get_dumpit(struct sk_buff *msg,
63658c2ecf20Sopenharmony_ci					  struct netlink_callback *cb)
63668c2ecf20Sopenharmony_ci{
63678c2ecf20Sopenharmony_ci	struct devlink_health_reporter *reporter;
63688c2ecf20Sopenharmony_ci	struct devlink_port *port;
63698c2ecf20Sopenharmony_ci	struct devlink *devlink;
63708c2ecf20Sopenharmony_ci	int start = cb->args[0];
63718c2ecf20Sopenharmony_ci	int idx = 0;
63728c2ecf20Sopenharmony_ci	int err;
63738c2ecf20Sopenharmony_ci
63748c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
63758c2ecf20Sopenharmony_ci	list_for_each_entry(devlink, &devlink_list, list) {
63768c2ecf20Sopenharmony_ci		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
63778c2ecf20Sopenharmony_ci			continue;
63788c2ecf20Sopenharmony_ci		mutex_lock(&devlink->reporters_lock);
63798c2ecf20Sopenharmony_ci		list_for_each_entry(reporter, &devlink->reporter_list,
63808c2ecf20Sopenharmony_ci				    list) {
63818c2ecf20Sopenharmony_ci			if (idx < start) {
63828c2ecf20Sopenharmony_ci				idx++;
63838c2ecf20Sopenharmony_ci				continue;
63848c2ecf20Sopenharmony_ci			}
63858c2ecf20Sopenharmony_ci			err = devlink_nl_health_reporter_fill(msg, devlink,
63868c2ecf20Sopenharmony_ci							      reporter,
63878c2ecf20Sopenharmony_ci							      DEVLINK_CMD_HEALTH_REPORTER_GET,
63888c2ecf20Sopenharmony_ci							      NETLINK_CB(cb->skb).portid,
63898c2ecf20Sopenharmony_ci							      cb->nlh->nlmsg_seq,
63908c2ecf20Sopenharmony_ci							      NLM_F_MULTI);
63918c2ecf20Sopenharmony_ci			if (err) {
63928c2ecf20Sopenharmony_ci				mutex_unlock(&devlink->reporters_lock);
63938c2ecf20Sopenharmony_ci				goto out;
63948c2ecf20Sopenharmony_ci			}
63958c2ecf20Sopenharmony_ci			idx++;
63968c2ecf20Sopenharmony_ci		}
63978c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->reporters_lock);
63988c2ecf20Sopenharmony_ci	}
63998c2ecf20Sopenharmony_ci
64008c2ecf20Sopenharmony_ci	list_for_each_entry(devlink, &devlink_list, list) {
64018c2ecf20Sopenharmony_ci		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
64028c2ecf20Sopenharmony_ci			continue;
64038c2ecf20Sopenharmony_ci		mutex_lock(&devlink->lock);
64048c2ecf20Sopenharmony_ci		list_for_each_entry(port, &devlink->port_list, list) {
64058c2ecf20Sopenharmony_ci			mutex_lock(&port->reporters_lock);
64068c2ecf20Sopenharmony_ci			list_for_each_entry(reporter, &port->reporter_list, list) {
64078c2ecf20Sopenharmony_ci				if (idx < start) {
64088c2ecf20Sopenharmony_ci					idx++;
64098c2ecf20Sopenharmony_ci					continue;
64108c2ecf20Sopenharmony_ci				}
64118c2ecf20Sopenharmony_ci				err = devlink_nl_health_reporter_fill(msg, devlink, reporter,
64128c2ecf20Sopenharmony_ci								      DEVLINK_CMD_HEALTH_REPORTER_GET,
64138c2ecf20Sopenharmony_ci								      NETLINK_CB(cb->skb).portid,
64148c2ecf20Sopenharmony_ci								      cb->nlh->nlmsg_seq,
64158c2ecf20Sopenharmony_ci								      NLM_F_MULTI);
64168c2ecf20Sopenharmony_ci				if (err) {
64178c2ecf20Sopenharmony_ci					mutex_unlock(&port->reporters_lock);
64188c2ecf20Sopenharmony_ci					mutex_unlock(&devlink->lock);
64198c2ecf20Sopenharmony_ci					goto out;
64208c2ecf20Sopenharmony_ci				}
64218c2ecf20Sopenharmony_ci				idx++;
64228c2ecf20Sopenharmony_ci			}
64238c2ecf20Sopenharmony_ci			mutex_unlock(&port->reporters_lock);
64248c2ecf20Sopenharmony_ci		}
64258c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->lock);
64268c2ecf20Sopenharmony_ci	}
64278c2ecf20Sopenharmony_ciout:
64288c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
64298c2ecf20Sopenharmony_ci
64308c2ecf20Sopenharmony_ci	cb->args[0] = idx;
64318c2ecf20Sopenharmony_ci	return msg->len;
64328c2ecf20Sopenharmony_ci}
64338c2ecf20Sopenharmony_ci
64348c2ecf20Sopenharmony_cistatic int
64358c2ecf20Sopenharmony_cidevlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
64368c2ecf20Sopenharmony_ci					struct genl_info *info)
64378c2ecf20Sopenharmony_ci{
64388c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
64398c2ecf20Sopenharmony_ci	struct devlink_health_reporter *reporter;
64408c2ecf20Sopenharmony_ci	int err;
64418c2ecf20Sopenharmony_ci
64428c2ecf20Sopenharmony_ci	reporter = devlink_health_reporter_get_from_info(devlink, info);
64438c2ecf20Sopenharmony_ci	if (!reporter)
64448c2ecf20Sopenharmony_ci		return -EINVAL;
64458c2ecf20Sopenharmony_ci
64468c2ecf20Sopenharmony_ci	if (!reporter->ops->recover &&
64478c2ecf20Sopenharmony_ci	    (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] ||
64488c2ecf20Sopenharmony_ci	     info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])) {
64498c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
64508c2ecf20Sopenharmony_ci		goto out;
64518c2ecf20Sopenharmony_ci	}
64528c2ecf20Sopenharmony_ci	if (!reporter->ops->dump &&
64538c2ecf20Sopenharmony_ci	    info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]) {
64548c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
64558c2ecf20Sopenharmony_ci		goto out;
64568c2ecf20Sopenharmony_ci	}
64578c2ecf20Sopenharmony_ci
64588c2ecf20Sopenharmony_ci	if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
64598c2ecf20Sopenharmony_ci		reporter->graceful_period =
64608c2ecf20Sopenharmony_ci			nla_get_u64(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]);
64618c2ecf20Sopenharmony_ci
64628c2ecf20Sopenharmony_ci	if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
64638c2ecf20Sopenharmony_ci		reporter->auto_recover =
64648c2ecf20Sopenharmony_ci			nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]);
64658c2ecf20Sopenharmony_ci
64668c2ecf20Sopenharmony_ci	if (info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
64678c2ecf20Sopenharmony_ci		reporter->auto_dump =
64688c2ecf20Sopenharmony_ci		nla_get_u8(info->attrs[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]);
64698c2ecf20Sopenharmony_ci
64708c2ecf20Sopenharmony_ci	devlink_health_reporter_put(reporter);
64718c2ecf20Sopenharmony_ci	return 0;
64728c2ecf20Sopenharmony_ciout:
64738c2ecf20Sopenharmony_ci	devlink_health_reporter_put(reporter);
64748c2ecf20Sopenharmony_ci	return err;
64758c2ecf20Sopenharmony_ci}
64768c2ecf20Sopenharmony_ci
64778c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
64788c2ecf20Sopenharmony_ci						       struct genl_info *info)
64798c2ecf20Sopenharmony_ci{
64808c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
64818c2ecf20Sopenharmony_ci	struct devlink_health_reporter *reporter;
64828c2ecf20Sopenharmony_ci	int err;
64838c2ecf20Sopenharmony_ci
64848c2ecf20Sopenharmony_ci	reporter = devlink_health_reporter_get_from_info(devlink, info);
64858c2ecf20Sopenharmony_ci	if (!reporter)
64868c2ecf20Sopenharmony_ci		return -EINVAL;
64878c2ecf20Sopenharmony_ci
64888c2ecf20Sopenharmony_ci	err = devlink_health_reporter_recover(reporter, NULL, info->extack);
64898c2ecf20Sopenharmony_ci
64908c2ecf20Sopenharmony_ci	devlink_health_reporter_put(reporter);
64918c2ecf20Sopenharmony_ci	return err;
64928c2ecf20Sopenharmony_ci}
64938c2ecf20Sopenharmony_ci
64948c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
64958c2ecf20Sopenharmony_ci							struct genl_info *info)
64968c2ecf20Sopenharmony_ci{
64978c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
64988c2ecf20Sopenharmony_ci	struct devlink_health_reporter *reporter;
64998c2ecf20Sopenharmony_ci	struct devlink_fmsg *fmsg;
65008c2ecf20Sopenharmony_ci	int err;
65018c2ecf20Sopenharmony_ci
65028c2ecf20Sopenharmony_ci	reporter = devlink_health_reporter_get_from_info(devlink, info);
65038c2ecf20Sopenharmony_ci	if (!reporter)
65048c2ecf20Sopenharmony_ci		return -EINVAL;
65058c2ecf20Sopenharmony_ci
65068c2ecf20Sopenharmony_ci	if (!reporter->ops->diagnose) {
65078c2ecf20Sopenharmony_ci		devlink_health_reporter_put(reporter);
65088c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
65098c2ecf20Sopenharmony_ci	}
65108c2ecf20Sopenharmony_ci
65118c2ecf20Sopenharmony_ci	fmsg = devlink_fmsg_alloc();
65128c2ecf20Sopenharmony_ci	if (!fmsg) {
65138c2ecf20Sopenharmony_ci		devlink_health_reporter_put(reporter);
65148c2ecf20Sopenharmony_ci		return -ENOMEM;
65158c2ecf20Sopenharmony_ci	}
65168c2ecf20Sopenharmony_ci
65178c2ecf20Sopenharmony_ci	err = devlink_fmsg_obj_nest_start(fmsg);
65188c2ecf20Sopenharmony_ci	if (err)
65198c2ecf20Sopenharmony_ci		goto out;
65208c2ecf20Sopenharmony_ci
65218c2ecf20Sopenharmony_ci	err = reporter->ops->diagnose(reporter, fmsg, info->extack);
65228c2ecf20Sopenharmony_ci	if (err)
65238c2ecf20Sopenharmony_ci		goto out;
65248c2ecf20Sopenharmony_ci
65258c2ecf20Sopenharmony_ci	err = devlink_fmsg_obj_nest_end(fmsg);
65268c2ecf20Sopenharmony_ci	if (err)
65278c2ecf20Sopenharmony_ci		goto out;
65288c2ecf20Sopenharmony_ci
65298c2ecf20Sopenharmony_ci	err = devlink_fmsg_snd(fmsg, info,
65308c2ecf20Sopenharmony_ci			       DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE, 0);
65318c2ecf20Sopenharmony_ci
65328c2ecf20Sopenharmony_ciout:
65338c2ecf20Sopenharmony_ci	devlink_fmsg_free(fmsg);
65348c2ecf20Sopenharmony_ci	devlink_health_reporter_put(reporter);
65358c2ecf20Sopenharmony_ci	return err;
65368c2ecf20Sopenharmony_ci}
65378c2ecf20Sopenharmony_ci
65388c2ecf20Sopenharmony_cistatic int
65398c2ecf20Sopenharmony_cidevlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
65408c2ecf20Sopenharmony_ci					       struct netlink_callback *cb)
65418c2ecf20Sopenharmony_ci{
65428c2ecf20Sopenharmony_ci	struct devlink_health_reporter *reporter;
65438c2ecf20Sopenharmony_ci	u64 start = cb->args[0];
65448c2ecf20Sopenharmony_ci	int err;
65458c2ecf20Sopenharmony_ci
65468c2ecf20Sopenharmony_ci	reporter = devlink_health_reporter_get_from_cb(cb);
65478c2ecf20Sopenharmony_ci	if (!reporter)
65488c2ecf20Sopenharmony_ci		return -EINVAL;
65498c2ecf20Sopenharmony_ci
65508c2ecf20Sopenharmony_ci	if (!reporter->ops->dump) {
65518c2ecf20Sopenharmony_ci		err = -EOPNOTSUPP;
65528c2ecf20Sopenharmony_ci		goto out;
65538c2ecf20Sopenharmony_ci	}
65548c2ecf20Sopenharmony_ci	mutex_lock(&reporter->dump_lock);
65558c2ecf20Sopenharmony_ci	if (!start) {
65568c2ecf20Sopenharmony_ci		err = devlink_health_do_dump(reporter, NULL, cb->extack);
65578c2ecf20Sopenharmony_ci		if (err)
65588c2ecf20Sopenharmony_ci			goto unlock;
65598c2ecf20Sopenharmony_ci		cb->args[1] = reporter->dump_ts;
65608c2ecf20Sopenharmony_ci	}
65618c2ecf20Sopenharmony_ci	if (!reporter->dump_fmsg || cb->args[1] != reporter->dump_ts) {
65628c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(cb->extack, "Dump trampled, please retry");
65638c2ecf20Sopenharmony_ci		err = -EAGAIN;
65648c2ecf20Sopenharmony_ci		goto unlock;
65658c2ecf20Sopenharmony_ci	}
65668c2ecf20Sopenharmony_ci
65678c2ecf20Sopenharmony_ci	err = devlink_fmsg_dumpit(reporter->dump_fmsg, skb, cb,
65688c2ecf20Sopenharmony_ci				  DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET);
65698c2ecf20Sopenharmony_ciunlock:
65708c2ecf20Sopenharmony_ci	mutex_unlock(&reporter->dump_lock);
65718c2ecf20Sopenharmony_ciout:
65728c2ecf20Sopenharmony_ci	devlink_health_reporter_put(reporter);
65738c2ecf20Sopenharmony_ci	return err;
65748c2ecf20Sopenharmony_ci}
65758c2ecf20Sopenharmony_ci
65768c2ecf20Sopenharmony_cistatic int
65778c2ecf20Sopenharmony_cidevlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
65788c2ecf20Sopenharmony_ci					       struct genl_info *info)
65798c2ecf20Sopenharmony_ci{
65808c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
65818c2ecf20Sopenharmony_ci	struct devlink_health_reporter *reporter;
65828c2ecf20Sopenharmony_ci
65838c2ecf20Sopenharmony_ci	reporter = devlink_health_reporter_get_from_info(devlink, info);
65848c2ecf20Sopenharmony_ci	if (!reporter)
65858c2ecf20Sopenharmony_ci		return -EINVAL;
65868c2ecf20Sopenharmony_ci
65878c2ecf20Sopenharmony_ci	if (!reporter->ops->dump) {
65888c2ecf20Sopenharmony_ci		devlink_health_reporter_put(reporter);
65898c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
65908c2ecf20Sopenharmony_ci	}
65918c2ecf20Sopenharmony_ci
65928c2ecf20Sopenharmony_ci	mutex_lock(&reporter->dump_lock);
65938c2ecf20Sopenharmony_ci	devlink_health_dump_clear(reporter);
65948c2ecf20Sopenharmony_ci	mutex_unlock(&reporter->dump_lock);
65958c2ecf20Sopenharmony_ci	devlink_health_reporter_put(reporter);
65968c2ecf20Sopenharmony_ci	return 0;
65978c2ecf20Sopenharmony_ci}
65988c2ecf20Sopenharmony_ci
65998c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_health_reporter_test_doit(struct sk_buff *skb,
66008c2ecf20Sopenharmony_ci						    struct genl_info *info)
66018c2ecf20Sopenharmony_ci{
66028c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
66038c2ecf20Sopenharmony_ci	struct devlink_health_reporter *reporter;
66048c2ecf20Sopenharmony_ci	int err;
66058c2ecf20Sopenharmony_ci
66068c2ecf20Sopenharmony_ci	reporter = devlink_health_reporter_get_from_info(devlink, info);
66078c2ecf20Sopenharmony_ci	if (!reporter)
66088c2ecf20Sopenharmony_ci		return -EINVAL;
66098c2ecf20Sopenharmony_ci
66108c2ecf20Sopenharmony_ci	if (!reporter->ops->test) {
66118c2ecf20Sopenharmony_ci		devlink_health_reporter_put(reporter);
66128c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
66138c2ecf20Sopenharmony_ci	}
66148c2ecf20Sopenharmony_ci
66158c2ecf20Sopenharmony_ci	err = reporter->ops->test(reporter, info->extack);
66168c2ecf20Sopenharmony_ci
66178c2ecf20Sopenharmony_ci	devlink_health_reporter_put(reporter);
66188c2ecf20Sopenharmony_ci	return err;
66198c2ecf20Sopenharmony_ci}
66208c2ecf20Sopenharmony_ci
66218c2ecf20Sopenharmony_cistruct devlink_stats {
66228c2ecf20Sopenharmony_ci	u64 rx_bytes;
66238c2ecf20Sopenharmony_ci	u64 rx_packets;
66248c2ecf20Sopenharmony_ci	struct u64_stats_sync syncp;
66258c2ecf20Sopenharmony_ci};
66268c2ecf20Sopenharmony_ci
66278c2ecf20Sopenharmony_ci/**
66288c2ecf20Sopenharmony_ci * struct devlink_trap_policer_item - Packet trap policer attributes.
66298c2ecf20Sopenharmony_ci * @policer: Immutable packet trap policer attributes.
66308c2ecf20Sopenharmony_ci * @rate: Rate in packets / sec.
66318c2ecf20Sopenharmony_ci * @burst: Burst size in packets.
66328c2ecf20Sopenharmony_ci * @list: trap_policer_list member.
66338c2ecf20Sopenharmony_ci *
66348c2ecf20Sopenharmony_ci * Describes packet trap policer attributes. Created by devlink during trap
66358c2ecf20Sopenharmony_ci * policer registration.
66368c2ecf20Sopenharmony_ci */
66378c2ecf20Sopenharmony_cistruct devlink_trap_policer_item {
66388c2ecf20Sopenharmony_ci	const struct devlink_trap_policer *policer;
66398c2ecf20Sopenharmony_ci	u64 rate;
66408c2ecf20Sopenharmony_ci	u64 burst;
66418c2ecf20Sopenharmony_ci	struct list_head list;
66428c2ecf20Sopenharmony_ci};
66438c2ecf20Sopenharmony_ci
66448c2ecf20Sopenharmony_ci/**
66458c2ecf20Sopenharmony_ci * struct devlink_trap_group_item - Packet trap group attributes.
66468c2ecf20Sopenharmony_ci * @group: Immutable packet trap group attributes.
66478c2ecf20Sopenharmony_ci * @policer_item: Associated policer item. Can be NULL.
66488c2ecf20Sopenharmony_ci * @list: trap_group_list member.
66498c2ecf20Sopenharmony_ci * @stats: Trap group statistics.
66508c2ecf20Sopenharmony_ci *
66518c2ecf20Sopenharmony_ci * Describes packet trap group attributes. Created by devlink during trap
66528c2ecf20Sopenharmony_ci * group registration.
66538c2ecf20Sopenharmony_ci */
66548c2ecf20Sopenharmony_cistruct devlink_trap_group_item {
66558c2ecf20Sopenharmony_ci	const struct devlink_trap_group *group;
66568c2ecf20Sopenharmony_ci	struct devlink_trap_policer_item *policer_item;
66578c2ecf20Sopenharmony_ci	struct list_head list;
66588c2ecf20Sopenharmony_ci	struct devlink_stats __percpu *stats;
66598c2ecf20Sopenharmony_ci};
66608c2ecf20Sopenharmony_ci
66618c2ecf20Sopenharmony_ci/**
66628c2ecf20Sopenharmony_ci * struct devlink_trap_item - Packet trap attributes.
66638c2ecf20Sopenharmony_ci * @trap: Immutable packet trap attributes.
66648c2ecf20Sopenharmony_ci * @group_item: Associated group item.
66658c2ecf20Sopenharmony_ci * @list: trap_list member.
66668c2ecf20Sopenharmony_ci * @action: Trap action.
66678c2ecf20Sopenharmony_ci * @stats: Trap statistics.
66688c2ecf20Sopenharmony_ci * @priv: Driver private information.
66698c2ecf20Sopenharmony_ci *
66708c2ecf20Sopenharmony_ci * Describes both mutable and immutable packet trap attributes. Created by
66718c2ecf20Sopenharmony_ci * devlink during trap registration and used for all trap related operations.
66728c2ecf20Sopenharmony_ci */
66738c2ecf20Sopenharmony_cistruct devlink_trap_item {
66748c2ecf20Sopenharmony_ci	const struct devlink_trap *trap;
66758c2ecf20Sopenharmony_ci	struct devlink_trap_group_item *group_item;
66768c2ecf20Sopenharmony_ci	struct list_head list;
66778c2ecf20Sopenharmony_ci	enum devlink_trap_action action;
66788c2ecf20Sopenharmony_ci	struct devlink_stats __percpu *stats;
66798c2ecf20Sopenharmony_ci	void *priv;
66808c2ecf20Sopenharmony_ci};
66818c2ecf20Sopenharmony_ci
66828c2ecf20Sopenharmony_cistatic struct devlink_trap_policer_item *
66838c2ecf20Sopenharmony_cidevlink_trap_policer_item_lookup(struct devlink *devlink, u32 id)
66848c2ecf20Sopenharmony_ci{
66858c2ecf20Sopenharmony_ci	struct devlink_trap_policer_item *policer_item;
66868c2ecf20Sopenharmony_ci
66878c2ecf20Sopenharmony_ci	list_for_each_entry(policer_item, &devlink->trap_policer_list, list) {
66888c2ecf20Sopenharmony_ci		if (policer_item->policer->id == id)
66898c2ecf20Sopenharmony_ci			return policer_item;
66908c2ecf20Sopenharmony_ci	}
66918c2ecf20Sopenharmony_ci
66928c2ecf20Sopenharmony_ci	return NULL;
66938c2ecf20Sopenharmony_ci}
66948c2ecf20Sopenharmony_ci
66958c2ecf20Sopenharmony_cistatic struct devlink_trap_item *
66968c2ecf20Sopenharmony_cidevlink_trap_item_lookup(struct devlink *devlink, const char *name)
66978c2ecf20Sopenharmony_ci{
66988c2ecf20Sopenharmony_ci	struct devlink_trap_item *trap_item;
66998c2ecf20Sopenharmony_ci
67008c2ecf20Sopenharmony_ci	list_for_each_entry(trap_item, &devlink->trap_list, list) {
67018c2ecf20Sopenharmony_ci		if (!strcmp(trap_item->trap->name, name))
67028c2ecf20Sopenharmony_ci			return trap_item;
67038c2ecf20Sopenharmony_ci	}
67048c2ecf20Sopenharmony_ci
67058c2ecf20Sopenharmony_ci	return NULL;
67068c2ecf20Sopenharmony_ci}
67078c2ecf20Sopenharmony_ci
67088c2ecf20Sopenharmony_cistatic struct devlink_trap_item *
67098c2ecf20Sopenharmony_cidevlink_trap_item_get_from_info(struct devlink *devlink,
67108c2ecf20Sopenharmony_ci				struct genl_info *info)
67118c2ecf20Sopenharmony_ci{
67128c2ecf20Sopenharmony_ci	struct nlattr *attr;
67138c2ecf20Sopenharmony_ci
67148c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_TRAP_NAME])
67158c2ecf20Sopenharmony_ci		return NULL;
67168c2ecf20Sopenharmony_ci	attr = info->attrs[DEVLINK_ATTR_TRAP_NAME];
67178c2ecf20Sopenharmony_ci
67188c2ecf20Sopenharmony_ci	return devlink_trap_item_lookup(devlink, nla_data(attr));
67198c2ecf20Sopenharmony_ci}
67208c2ecf20Sopenharmony_ci
67218c2ecf20Sopenharmony_cistatic int
67228c2ecf20Sopenharmony_cidevlink_trap_action_get_from_info(struct genl_info *info,
67238c2ecf20Sopenharmony_ci				  enum devlink_trap_action *p_trap_action)
67248c2ecf20Sopenharmony_ci{
67258c2ecf20Sopenharmony_ci	u8 val;
67268c2ecf20Sopenharmony_ci
67278c2ecf20Sopenharmony_ci	val = nla_get_u8(info->attrs[DEVLINK_ATTR_TRAP_ACTION]);
67288c2ecf20Sopenharmony_ci	switch (val) {
67298c2ecf20Sopenharmony_ci	case DEVLINK_TRAP_ACTION_DROP:
67308c2ecf20Sopenharmony_ci	case DEVLINK_TRAP_ACTION_TRAP:
67318c2ecf20Sopenharmony_ci	case DEVLINK_TRAP_ACTION_MIRROR:
67328c2ecf20Sopenharmony_ci		*p_trap_action = val;
67338c2ecf20Sopenharmony_ci		break;
67348c2ecf20Sopenharmony_ci	default:
67358c2ecf20Sopenharmony_ci		return -EINVAL;
67368c2ecf20Sopenharmony_ci	}
67378c2ecf20Sopenharmony_ci
67388c2ecf20Sopenharmony_ci	return 0;
67398c2ecf20Sopenharmony_ci}
67408c2ecf20Sopenharmony_ci
67418c2ecf20Sopenharmony_cistatic int devlink_trap_metadata_put(struct sk_buff *msg,
67428c2ecf20Sopenharmony_ci				     const struct devlink_trap *trap)
67438c2ecf20Sopenharmony_ci{
67448c2ecf20Sopenharmony_ci	struct nlattr *attr;
67458c2ecf20Sopenharmony_ci
67468c2ecf20Sopenharmony_ci	attr = nla_nest_start(msg, DEVLINK_ATTR_TRAP_METADATA);
67478c2ecf20Sopenharmony_ci	if (!attr)
67488c2ecf20Sopenharmony_ci		return -EMSGSIZE;
67498c2ecf20Sopenharmony_ci
67508c2ecf20Sopenharmony_ci	if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_IN_PORT) &&
67518c2ecf20Sopenharmony_ci	    nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT))
67528c2ecf20Sopenharmony_ci		goto nla_put_failure;
67538c2ecf20Sopenharmony_ci	if ((trap->metadata_cap & DEVLINK_TRAP_METADATA_TYPE_F_FA_COOKIE) &&
67548c2ecf20Sopenharmony_ci	    nla_put_flag(msg, DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE))
67558c2ecf20Sopenharmony_ci		goto nla_put_failure;
67568c2ecf20Sopenharmony_ci
67578c2ecf20Sopenharmony_ci	nla_nest_end(msg, attr);
67588c2ecf20Sopenharmony_ci
67598c2ecf20Sopenharmony_ci	return 0;
67608c2ecf20Sopenharmony_ci
67618c2ecf20Sopenharmony_cinla_put_failure:
67628c2ecf20Sopenharmony_ci	nla_nest_cancel(msg, attr);
67638c2ecf20Sopenharmony_ci	return -EMSGSIZE;
67648c2ecf20Sopenharmony_ci}
67658c2ecf20Sopenharmony_ci
67668c2ecf20Sopenharmony_cistatic void devlink_trap_stats_read(struct devlink_stats __percpu *trap_stats,
67678c2ecf20Sopenharmony_ci				    struct devlink_stats *stats)
67688c2ecf20Sopenharmony_ci{
67698c2ecf20Sopenharmony_ci	int i;
67708c2ecf20Sopenharmony_ci
67718c2ecf20Sopenharmony_ci	memset(stats, 0, sizeof(*stats));
67728c2ecf20Sopenharmony_ci	for_each_possible_cpu(i) {
67738c2ecf20Sopenharmony_ci		struct devlink_stats *cpu_stats;
67748c2ecf20Sopenharmony_ci		u64 rx_packets, rx_bytes;
67758c2ecf20Sopenharmony_ci		unsigned int start;
67768c2ecf20Sopenharmony_ci
67778c2ecf20Sopenharmony_ci		cpu_stats = per_cpu_ptr(trap_stats, i);
67788c2ecf20Sopenharmony_ci		do {
67798c2ecf20Sopenharmony_ci			start = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
67808c2ecf20Sopenharmony_ci			rx_packets = cpu_stats->rx_packets;
67818c2ecf20Sopenharmony_ci			rx_bytes = cpu_stats->rx_bytes;
67828c2ecf20Sopenharmony_ci		} while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, start));
67838c2ecf20Sopenharmony_ci
67848c2ecf20Sopenharmony_ci		stats->rx_packets += rx_packets;
67858c2ecf20Sopenharmony_ci		stats->rx_bytes += rx_bytes;
67868c2ecf20Sopenharmony_ci	}
67878c2ecf20Sopenharmony_ci}
67888c2ecf20Sopenharmony_ci
67898c2ecf20Sopenharmony_cistatic int devlink_trap_stats_put(struct sk_buff *msg,
67908c2ecf20Sopenharmony_ci				  struct devlink_stats __percpu *trap_stats)
67918c2ecf20Sopenharmony_ci{
67928c2ecf20Sopenharmony_ci	struct devlink_stats stats;
67938c2ecf20Sopenharmony_ci	struct nlattr *attr;
67948c2ecf20Sopenharmony_ci
67958c2ecf20Sopenharmony_ci	devlink_trap_stats_read(trap_stats, &stats);
67968c2ecf20Sopenharmony_ci
67978c2ecf20Sopenharmony_ci	attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
67988c2ecf20Sopenharmony_ci	if (!attr)
67998c2ecf20Sopenharmony_ci		return -EMSGSIZE;
68008c2ecf20Sopenharmony_ci
68018c2ecf20Sopenharmony_ci	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_PACKETS,
68028c2ecf20Sopenharmony_ci			      stats.rx_packets, DEVLINK_ATTR_PAD))
68038c2ecf20Sopenharmony_ci		goto nla_put_failure;
68048c2ecf20Sopenharmony_ci
68058c2ecf20Sopenharmony_ci	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_BYTES,
68068c2ecf20Sopenharmony_ci			      stats.rx_bytes, DEVLINK_ATTR_PAD))
68078c2ecf20Sopenharmony_ci		goto nla_put_failure;
68088c2ecf20Sopenharmony_ci
68098c2ecf20Sopenharmony_ci	nla_nest_end(msg, attr);
68108c2ecf20Sopenharmony_ci
68118c2ecf20Sopenharmony_ci	return 0;
68128c2ecf20Sopenharmony_ci
68138c2ecf20Sopenharmony_cinla_put_failure:
68148c2ecf20Sopenharmony_ci	nla_nest_cancel(msg, attr);
68158c2ecf20Sopenharmony_ci	return -EMSGSIZE;
68168c2ecf20Sopenharmony_ci}
68178c2ecf20Sopenharmony_ci
68188c2ecf20Sopenharmony_cistatic int devlink_nl_trap_fill(struct sk_buff *msg, struct devlink *devlink,
68198c2ecf20Sopenharmony_ci				const struct devlink_trap_item *trap_item,
68208c2ecf20Sopenharmony_ci				enum devlink_command cmd, u32 portid, u32 seq,
68218c2ecf20Sopenharmony_ci				int flags)
68228c2ecf20Sopenharmony_ci{
68238c2ecf20Sopenharmony_ci	struct devlink_trap_group_item *group_item = trap_item->group_item;
68248c2ecf20Sopenharmony_ci	void *hdr;
68258c2ecf20Sopenharmony_ci	int err;
68268c2ecf20Sopenharmony_ci
68278c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
68288c2ecf20Sopenharmony_ci	if (!hdr)
68298c2ecf20Sopenharmony_ci		return -EMSGSIZE;
68308c2ecf20Sopenharmony_ci
68318c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(msg, devlink))
68328c2ecf20Sopenharmony_ci		goto nla_put_failure;
68338c2ecf20Sopenharmony_ci
68348c2ecf20Sopenharmony_ci	if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
68358c2ecf20Sopenharmony_ci			   group_item->group->name))
68368c2ecf20Sopenharmony_ci		goto nla_put_failure;
68378c2ecf20Sopenharmony_ci
68388c2ecf20Sopenharmony_ci	if (nla_put_string(msg, DEVLINK_ATTR_TRAP_NAME, trap_item->trap->name))
68398c2ecf20Sopenharmony_ci		goto nla_put_failure;
68408c2ecf20Sopenharmony_ci
68418c2ecf20Sopenharmony_ci	if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_TYPE, trap_item->trap->type))
68428c2ecf20Sopenharmony_ci		goto nla_put_failure;
68438c2ecf20Sopenharmony_ci
68448c2ecf20Sopenharmony_ci	if (trap_item->trap->generic &&
68458c2ecf20Sopenharmony_ci	    nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
68468c2ecf20Sopenharmony_ci		goto nla_put_failure;
68478c2ecf20Sopenharmony_ci
68488c2ecf20Sopenharmony_ci	if (nla_put_u8(msg, DEVLINK_ATTR_TRAP_ACTION, trap_item->action))
68498c2ecf20Sopenharmony_ci		goto nla_put_failure;
68508c2ecf20Sopenharmony_ci
68518c2ecf20Sopenharmony_ci	err = devlink_trap_metadata_put(msg, trap_item->trap);
68528c2ecf20Sopenharmony_ci	if (err)
68538c2ecf20Sopenharmony_ci		goto nla_put_failure;
68548c2ecf20Sopenharmony_ci
68558c2ecf20Sopenharmony_ci	err = devlink_trap_stats_put(msg, trap_item->stats);
68568c2ecf20Sopenharmony_ci	if (err)
68578c2ecf20Sopenharmony_ci		goto nla_put_failure;
68588c2ecf20Sopenharmony_ci
68598c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
68608c2ecf20Sopenharmony_ci
68618c2ecf20Sopenharmony_ci	return 0;
68628c2ecf20Sopenharmony_ci
68638c2ecf20Sopenharmony_cinla_put_failure:
68648c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
68658c2ecf20Sopenharmony_ci	return -EMSGSIZE;
68668c2ecf20Sopenharmony_ci}
68678c2ecf20Sopenharmony_ci
68688c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_get_doit(struct sk_buff *skb,
68698c2ecf20Sopenharmony_ci					struct genl_info *info)
68708c2ecf20Sopenharmony_ci{
68718c2ecf20Sopenharmony_ci	struct netlink_ext_ack *extack = info->extack;
68728c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
68738c2ecf20Sopenharmony_ci	struct devlink_trap_item *trap_item;
68748c2ecf20Sopenharmony_ci	struct sk_buff *msg;
68758c2ecf20Sopenharmony_ci	int err;
68768c2ecf20Sopenharmony_ci
68778c2ecf20Sopenharmony_ci	if (list_empty(&devlink->trap_list))
68788c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
68798c2ecf20Sopenharmony_ci
68808c2ecf20Sopenharmony_ci	trap_item = devlink_trap_item_get_from_info(devlink, info);
68818c2ecf20Sopenharmony_ci	if (!trap_item) {
68828c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
68838c2ecf20Sopenharmony_ci		return -ENOENT;
68848c2ecf20Sopenharmony_ci	}
68858c2ecf20Sopenharmony_ci
68868c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
68878c2ecf20Sopenharmony_ci	if (!msg)
68888c2ecf20Sopenharmony_ci		return -ENOMEM;
68898c2ecf20Sopenharmony_ci
68908c2ecf20Sopenharmony_ci	err = devlink_nl_trap_fill(msg, devlink, trap_item,
68918c2ecf20Sopenharmony_ci				   DEVLINK_CMD_TRAP_NEW, info->snd_portid,
68928c2ecf20Sopenharmony_ci				   info->snd_seq, 0);
68938c2ecf20Sopenharmony_ci	if (err)
68948c2ecf20Sopenharmony_ci		goto err_trap_fill;
68958c2ecf20Sopenharmony_ci
68968c2ecf20Sopenharmony_ci	return genlmsg_reply(msg, info);
68978c2ecf20Sopenharmony_ci
68988c2ecf20Sopenharmony_cierr_trap_fill:
68998c2ecf20Sopenharmony_ci	nlmsg_free(msg);
69008c2ecf20Sopenharmony_ci	return err;
69018c2ecf20Sopenharmony_ci}
69028c2ecf20Sopenharmony_ci
69038c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_get_dumpit(struct sk_buff *msg,
69048c2ecf20Sopenharmony_ci					  struct netlink_callback *cb)
69058c2ecf20Sopenharmony_ci{
69068c2ecf20Sopenharmony_ci	struct devlink_trap_item *trap_item;
69078c2ecf20Sopenharmony_ci	struct devlink *devlink;
69088c2ecf20Sopenharmony_ci	int start = cb->args[0];
69098c2ecf20Sopenharmony_ci	int idx = 0;
69108c2ecf20Sopenharmony_ci	int err;
69118c2ecf20Sopenharmony_ci
69128c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
69138c2ecf20Sopenharmony_ci	list_for_each_entry(devlink, &devlink_list, list) {
69148c2ecf20Sopenharmony_ci		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
69158c2ecf20Sopenharmony_ci			continue;
69168c2ecf20Sopenharmony_ci		mutex_lock(&devlink->lock);
69178c2ecf20Sopenharmony_ci		list_for_each_entry(trap_item, &devlink->trap_list, list) {
69188c2ecf20Sopenharmony_ci			if (idx < start) {
69198c2ecf20Sopenharmony_ci				idx++;
69208c2ecf20Sopenharmony_ci				continue;
69218c2ecf20Sopenharmony_ci			}
69228c2ecf20Sopenharmony_ci			err = devlink_nl_trap_fill(msg, devlink, trap_item,
69238c2ecf20Sopenharmony_ci						   DEVLINK_CMD_TRAP_NEW,
69248c2ecf20Sopenharmony_ci						   NETLINK_CB(cb->skb).portid,
69258c2ecf20Sopenharmony_ci						   cb->nlh->nlmsg_seq,
69268c2ecf20Sopenharmony_ci						   NLM_F_MULTI);
69278c2ecf20Sopenharmony_ci			if (err) {
69288c2ecf20Sopenharmony_ci				mutex_unlock(&devlink->lock);
69298c2ecf20Sopenharmony_ci				goto out;
69308c2ecf20Sopenharmony_ci			}
69318c2ecf20Sopenharmony_ci			idx++;
69328c2ecf20Sopenharmony_ci		}
69338c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->lock);
69348c2ecf20Sopenharmony_ci	}
69358c2ecf20Sopenharmony_ciout:
69368c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
69378c2ecf20Sopenharmony_ci
69388c2ecf20Sopenharmony_ci	cb->args[0] = idx;
69398c2ecf20Sopenharmony_ci	return msg->len;
69408c2ecf20Sopenharmony_ci}
69418c2ecf20Sopenharmony_ci
69428c2ecf20Sopenharmony_cistatic int __devlink_trap_action_set(struct devlink *devlink,
69438c2ecf20Sopenharmony_ci				     struct devlink_trap_item *trap_item,
69448c2ecf20Sopenharmony_ci				     enum devlink_trap_action trap_action,
69458c2ecf20Sopenharmony_ci				     struct netlink_ext_ack *extack)
69468c2ecf20Sopenharmony_ci{
69478c2ecf20Sopenharmony_ci	int err;
69488c2ecf20Sopenharmony_ci
69498c2ecf20Sopenharmony_ci	if (trap_item->action != trap_action &&
69508c2ecf20Sopenharmony_ci	    trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP) {
69518c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Cannot change action of non-drop traps. Skipping");
69528c2ecf20Sopenharmony_ci		return 0;
69538c2ecf20Sopenharmony_ci	}
69548c2ecf20Sopenharmony_ci
69558c2ecf20Sopenharmony_ci	err = devlink->ops->trap_action_set(devlink, trap_item->trap,
69568c2ecf20Sopenharmony_ci					    trap_action, extack);
69578c2ecf20Sopenharmony_ci	if (err)
69588c2ecf20Sopenharmony_ci		return err;
69598c2ecf20Sopenharmony_ci
69608c2ecf20Sopenharmony_ci	trap_item->action = trap_action;
69618c2ecf20Sopenharmony_ci
69628c2ecf20Sopenharmony_ci	return 0;
69638c2ecf20Sopenharmony_ci}
69648c2ecf20Sopenharmony_ci
69658c2ecf20Sopenharmony_cistatic int devlink_trap_action_set(struct devlink *devlink,
69668c2ecf20Sopenharmony_ci				   struct devlink_trap_item *trap_item,
69678c2ecf20Sopenharmony_ci				   struct genl_info *info)
69688c2ecf20Sopenharmony_ci{
69698c2ecf20Sopenharmony_ci	enum devlink_trap_action trap_action;
69708c2ecf20Sopenharmony_ci	int err;
69718c2ecf20Sopenharmony_ci
69728c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
69738c2ecf20Sopenharmony_ci		return 0;
69748c2ecf20Sopenharmony_ci
69758c2ecf20Sopenharmony_ci	err = devlink_trap_action_get_from_info(info, &trap_action);
69768c2ecf20Sopenharmony_ci	if (err) {
69778c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
69788c2ecf20Sopenharmony_ci		return -EINVAL;
69798c2ecf20Sopenharmony_ci	}
69808c2ecf20Sopenharmony_ci
69818c2ecf20Sopenharmony_ci	return __devlink_trap_action_set(devlink, trap_item, trap_action,
69828c2ecf20Sopenharmony_ci					 info->extack);
69838c2ecf20Sopenharmony_ci}
69848c2ecf20Sopenharmony_ci
69858c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_set_doit(struct sk_buff *skb,
69868c2ecf20Sopenharmony_ci					struct genl_info *info)
69878c2ecf20Sopenharmony_ci{
69888c2ecf20Sopenharmony_ci	struct netlink_ext_ack *extack = info->extack;
69898c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
69908c2ecf20Sopenharmony_ci	struct devlink_trap_item *trap_item;
69918c2ecf20Sopenharmony_ci	int err;
69928c2ecf20Sopenharmony_ci
69938c2ecf20Sopenharmony_ci	if (list_empty(&devlink->trap_list))
69948c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
69958c2ecf20Sopenharmony_ci
69968c2ecf20Sopenharmony_ci	trap_item = devlink_trap_item_get_from_info(devlink, info);
69978c2ecf20Sopenharmony_ci	if (!trap_item) {
69988c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap");
69998c2ecf20Sopenharmony_ci		return -ENOENT;
70008c2ecf20Sopenharmony_ci	}
70018c2ecf20Sopenharmony_ci
70028c2ecf20Sopenharmony_ci	err = devlink_trap_action_set(devlink, trap_item, info);
70038c2ecf20Sopenharmony_ci	if (err)
70048c2ecf20Sopenharmony_ci		return err;
70058c2ecf20Sopenharmony_ci
70068c2ecf20Sopenharmony_ci	return 0;
70078c2ecf20Sopenharmony_ci}
70088c2ecf20Sopenharmony_ci
70098c2ecf20Sopenharmony_cistatic struct devlink_trap_group_item *
70108c2ecf20Sopenharmony_cidevlink_trap_group_item_lookup(struct devlink *devlink, const char *name)
70118c2ecf20Sopenharmony_ci{
70128c2ecf20Sopenharmony_ci	struct devlink_trap_group_item *group_item;
70138c2ecf20Sopenharmony_ci
70148c2ecf20Sopenharmony_ci	list_for_each_entry(group_item, &devlink->trap_group_list, list) {
70158c2ecf20Sopenharmony_ci		if (!strcmp(group_item->group->name, name))
70168c2ecf20Sopenharmony_ci			return group_item;
70178c2ecf20Sopenharmony_ci	}
70188c2ecf20Sopenharmony_ci
70198c2ecf20Sopenharmony_ci	return NULL;
70208c2ecf20Sopenharmony_ci}
70218c2ecf20Sopenharmony_ci
70228c2ecf20Sopenharmony_cistatic struct devlink_trap_group_item *
70238c2ecf20Sopenharmony_cidevlink_trap_group_item_lookup_by_id(struct devlink *devlink, u16 id)
70248c2ecf20Sopenharmony_ci{
70258c2ecf20Sopenharmony_ci	struct devlink_trap_group_item *group_item;
70268c2ecf20Sopenharmony_ci
70278c2ecf20Sopenharmony_ci	list_for_each_entry(group_item, &devlink->trap_group_list, list) {
70288c2ecf20Sopenharmony_ci		if (group_item->group->id == id)
70298c2ecf20Sopenharmony_ci			return group_item;
70308c2ecf20Sopenharmony_ci	}
70318c2ecf20Sopenharmony_ci
70328c2ecf20Sopenharmony_ci	return NULL;
70338c2ecf20Sopenharmony_ci}
70348c2ecf20Sopenharmony_ci
70358c2ecf20Sopenharmony_cistatic struct devlink_trap_group_item *
70368c2ecf20Sopenharmony_cidevlink_trap_group_item_get_from_info(struct devlink *devlink,
70378c2ecf20Sopenharmony_ci				      struct genl_info *info)
70388c2ecf20Sopenharmony_ci{
70398c2ecf20Sopenharmony_ci	char *name;
70408c2ecf20Sopenharmony_ci
70418c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME])
70428c2ecf20Sopenharmony_ci		return NULL;
70438c2ecf20Sopenharmony_ci	name = nla_data(info->attrs[DEVLINK_ATTR_TRAP_GROUP_NAME]);
70448c2ecf20Sopenharmony_ci
70458c2ecf20Sopenharmony_ci	return devlink_trap_group_item_lookup(devlink, name);
70468c2ecf20Sopenharmony_ci}
70478c2ecf20Sopenharmony_ci
70488c2ecf20Sopenharmony_cistatic int
70498c2ecf20Sopenharmony_cidevlink_nl_trap_group_fill(struct sk_buff *msg, struct devlink *devlink,
70508c2ecf20Sopenharmony_ci			   const struct devlink_trap_group_item *group_item,
70518c2ecf20Sopenharmony_ci			   enum devlink_command cmd, u32 portid, u32 seq,
70528c2ecf20Sopenharmony_ci			   int flags)
70538c2ecf20Sopenharmony_ci{
70548c2ecf20Sopenharmony_ci	void *hdr;
70558c2ecf20Sopenharmony_ci	int err;
70568c2ecf20Sopenharmony_ci
70578c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
70588c2ecf20Sopenharmony_ci	if (!hdr)
70598c2ecf20Sopenharmony_ci		return -EMSGSIZE;
70608c2ecf20Sopenharmony_ci
70618c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(msg, devlink))
70628c2ecf20Sopenharmony_ci		goto nla_put_failure;
70638c2ecf20Sopenharmony_ci
70648c2ecf20Sopenharmony_ci	if (nla_put_string(msg, DEVLINK_ATTR_TRAP_GROUP_NAME,
70658c2ecf20Sopenharmony_ci			   group_item->group->name))
70668c2ecf20Sopenharmony_ci		goto nla_put_failure;
70678c2ecf20Sopenharmony_ci
70688c2ecf20Sopenharmony_ci	if (group_item->group->generic &&
70698c2ecf20Sopenharmony_ci	    nla_put_flag(msg, DEVLINK_ATTR_TRAP_GENERIC))
70708c2ecf20Sopenharmony_ci		goto nla_put_failure;
70718c2ecf20Sopenharmony_ci
70728c2ecf20Sopenharmony_ci	if (group_item->policer_item &&
70738c2ecf20Sopenharmony_ci	    nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
70748c2ecf20Sopenharmony_ci			group_item->policer_item->policer->id))
70758c2ecf20Sopenharmony_ci		goto nla_put_failure;
70768c2ecf20Sopenharmony_ci
70778c2ecf20Sopenharmony_ci	err = devlink_trap_stats_put(msg, group_item->stats);
70788c2ecf20Sopenharmony_ci	if (err)
70798c2ecf20Sopenharmony_ci		goto nla_put_failure;
70808c2ecf20Sopenharmony_ci
70818c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
70828c2ecf20Sopenharmony_ci
70838c2ecf20Sopenharmony_ci	return 0;
70848c2ecf20Sopenharmony_ci
70858c2ecf20Sopenharmony_cinla_put_failure:
70868c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
70878c2ecf20Sopenharmony_ci	return -EMSGSIZE;
70888c2ecf20Sopenharmony_ci}
70898c2ecf20Sopenharmony_ci
70908c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_group_get_doit(struct sk_buff *skb,
70918c2ecf20Sopenharmony_ci					      struct genl_info *info)
70928c2ecf20Sopenharmony_ci{
70938c2ecf20Sopenharmony_ci	struct netlink_ext_ack *extack = info->extack;
70948c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
70958c2ecf20Sopenharmony_ci	struct devlink_trap_group_item *group_item;
70968c2ecf20Sopenharmony_ci	struct sk_buff *msg;
70978c2ecf20Sopenharmony_ci	int err;
70988c2ecf20Sopenharmony_ci
70998c2ecf20Sopenharmony_ci	if (list_empty(&devlink->trap_group_list))
71008c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
71018c2ecf20Sopenharmony_ci
71028c2ecf20Sopenharmony_ci	group_item = devlink_trap_group_item_get_from_info(devlink, info);
71038c2ecf20Sopenharmony_ci	if (!group_item) {
71048c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
71058c2ecf20Sopenharmony_ci		return -ENOENT;
71068c2ecf20Sopenharmony_ci	}
71078c2ecf20Sopenharmony_ci
71088c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
71098c2ecf20Sopenharmony_ci	if (!msg)
71108c2ecf20Sopenharmony_ci		return -ENOMEM;
71118c2ecf20Sopenharmony_ci
71128c2ecf20Sopenharmony_ci	err = devlink_nl_trap_group_fill(msg, devlink, group_item,
71138c2ecf20Sopenharmony_ci					 DEVLINK_CMD_TRAP_GROUP_NEW,
71148c2ecf20Sopenharmony_ci					 info->snd_portid, info->snd_seq, 0);
71158c2ecf20Sopenharmony_ci	if (err)
71168c2ecf20Sopenharmony_ci		goto err_trap_group_fill;
71178c2ecf20Sopenharmony_ci
71188c2ecf20Sopenharmony_ci	return genlmsg_reply(msg, info);
71198c2ecf20Sopenharmony_ci
71208c2ecf20Sopenharmony_cierr_trap_group_fill:
71218c2ecf20Sopenharmony_ci	nlmsg_free(msg);
71228c2ecf20Sopenharmony_ci	return err;
71238c2ecf20Sopenharmony_ci}
71248c2ecf20Sopenharmony_ci
71258c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_group_get_dumpit(struct sk_buff *msg,
71268c2ecf20Sopenharmony_ci						struct netlink_callback *cb)
71278c2ecf20Sopenharmony_ci{
71288c2ecf20Sopenharmony_ci	enum devlink_command cmd = DEVLINK_CMD_TRAP_GROUP_NEW;
71298c2ecf20Sopenharmony_ci	struct devlink_trap_group_item *group_item;
71308c2ecf20Sopenharmony_ci	u32 portid = NETLINK_CB(cb->skb).portid;
71318c2ecf20Sopenharmony_ci	struct devlink *devlink;
71328c2ecf20Sopenharmony_ci	int start = cb->args[0];
71338c2ecf20Sopenharmony_ci	int idx = 0;
71348c2ecf20Sopenharmony_ci	int err;
71358c2ecf20Sopenharmony_ci
71368c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
71378c2ecf20Sopenharmony_ci	list_for_each_entry(devlink, &devlink_list, list) {
71388c2ecf20Sopenharmony_ci		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
71398c2ecf20Sopenharmony_ci			continue;
71408c2ecf20Sopenharmony_ci		mutex_lock(&devlink->lock);
71418c2ecf20Sopenharmony_ci		list_for_each_entry(group_item, &devlink->trap_group_list,
71428c2ecf20Sopenharmony_ci				    list) {
71438c2ecf20Sopenharmony_ci			if (idx < start) {
71448c2ecf20Sopenharmony_ci				idx++;
71458c2ecf20Sopenharmony_ci				continue;
71468c2ecf20Sopenharmony_ci			}
71478c2ecf20Sopenharmony_ci			err = devlink_nl_trap_group_fill(msg, devlink,
71488c2ecf20Sopenharmony_ci							 group_item, cmd,
71498c2ecf20Sopenharmony_ci							 portid,
71508c2ecf20Sopenharmony_ci							 cb->nlh->nlmsg_seq,
71518c2ecf20Sopenharmony_ci							 NLM_F_MULTI);
71528c2ecf20Sopenharmony_ci			if (err) {
71538c2ecf20Sopenharmony_ci				mutex_unlock(&devlink->lock);
71548c2ecf20Sopenharmony_ci				goto out;
71558c2ecf20Sopenharmony_ci			}
71568c2ecf20Sopenharmony_ci			idx++;
71578c2ecf20Sopenharmony_ci		}
71588c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->lock);
71598c2ecf20Sopenharmony_ci	}
71608c2ecf20Sopenharmony_ciout:
71618c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
71628c2ecf20Sopenharmony_ci
71638c2ecf20Sopenharmony_ci	cb->args[0] = idx;
71648c2ecf20Sopenharmony_ci	return msg->len;
71658c2ecf20Sopenharmony_ci}
71668c2ecf20Sopenharmony_ci
71678c2ecf20Sopenharmony_cistatic int
71688c2ecf20Sopenharmony_ci__devlink_trap_group_action_set(struct devlink *devlink,
71698c2ecf20Sopenharmony_ci				struct devlink_trap_group_item *group_item,
71708c2ecf20Sopenharmony_ci				enum devlink_trap_action trap_action,
71718c2ecf20Sopenharmony_ci				struct netlink_ext_ack *extack)
71728c2ecf20Sopenharmony_ci{
71738c2ecf20Sopenharmony_ci	const char *group_name = group_item->group->name;
71748c2ecf20Sopenharmony_ci	struct devlink_trap_item *trap_item;
71758c2ecf20Sopenharmony_ci	int err;
71768c2ecf20Sopenharmony_ci
71778c2ecf20Sopenharmony_ci	if (devlink->ops->trap_group_action_set) {
71788c2ecf20Sopenharmony_ci		err = devlink->ops->trap_group_action_set(devlink, group_item->group,
71798c2ecf20Sopenharmony_ci							  trap_action, extack);
71808c2ecf20Sopenharmony_ci		if (err)
71818c2ecf20Sopenharmony_ci			return err;
71828c2ecf20Sopenharmony_ci
71838c2ecf20Sopenharmony_ci		list_for_each_entry(trap_item, &devlink->trap_list, list) {
71848c2ecf20Sopenharmony_ci			if (strcmp(trap_item->group_item->group->name, group_name))
71858c2ecf20Sopenharmony_ci				continue;
71868c2ecf20Sopenharmony_ci			if (trap_item->action != trap_action &&
71878c2ecf20Sopenharmony_ci			    trap_item->trap->type != DEVLINK_TRAP_TYPE_DROP)
71888c2ecf20Sopenharmony_ci				continue;
71898c2ecf20Sopenharmony_ci			trap_item->action = trap_action;
71908c2ecf20Sopenharmony_ci		}
71918c2ecf20Sopenharmony_ci
71928c2ecf20Sopenharmony_ci		return 0;
71938c2ecf20Sopenharmony_ci	}
71948c2ecf20Sopenharmony_ci
71958c2ecf20Sopenharmony_ci	list_for_each_entry(trap_item, &devlink->trap_list, list) {
71968c2ecf20Sopenharmony_ci		if (strcmp(trap_item->group_item->group->name, group_name))
71978c2ecf20Sopenharmony_ci			continue;
71988c2ecf20Sopenharmony_ci		err = __devlink_trap_action_set(devlink, trap_item,
71998c2ecf20Sopenharmony_ci						trap_action, extack);
72008c2ecf20Sopenharmony_ci		if (err)
72018c2ecf20Sopenharmony_ci			return err;
72028c2ecf20Sopenharmony_ci	}
72038c2ecf20Sopenharmony_ci
72048c2ecf20Sopenharmony_ci	return 0;
72058c2ecf20Sopenharmony_ci}
72068c2ecf20Sopenharmony_ci
72078c2ecf20Sopenharmony_cistatic int
72088c2ecf20Sopenharmony_cidevlink_trap_group_action_set(struct devlink *devlink,
72098c2ecf20Sopenharmony_ci			      struct devlink_trap_group_item *group_item,
72108c2ecf20Sopenharmony_ci			      struct genl_info *info, bool *p_modified)
72118c2ecf20Sopenharmony_ci{
72128c2ecf20Sopenharmony_ci	enum devlink_trap_action trap_action;
72138c2ecf20Sopenharmony_ci	int err;
72148c2ecf20Sopenharmony_ci
72158c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_TRAP_ACTION])
72168c2ecf20Sopenharmony_ci		return 0;
72178c2ecf20Sopenharmony_ci
72188c2ecf20Sopenharmony_ci	err = devlink_trap_action_get_from_info(info, &trap_action);
72198c2ecf20Sopenharmony_ci	if (err) {
72208c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(info->extack, "Invalid trap action");
72218c2ecf20Sopenharmony_ci		return -EINVAL;
72228c2ecf20Sopenharmony_ci	}
72238c2ecf20Sopenharmony_ci
72248c2ecf20Sopenharmony_ci	err = __devlink_trap_group_action_set(devlink, group_item, trap_action,
72258c2ecf20Sopenharmony_ci					      info->extack);
72268c2ecf20Sopenharmony_ci	if (err)
72278c2ecf20Sopenharmony_ci		return err;
72288c2ecf20Sopenharmony_ci
72298c2ecf20Sopenharmony_ci	*p_modified = true;
72308c2ecf20Sopenharmony_ci
72318c2ecf20Sopenharmony_ci	return 0;
72328c2ecf20Sopenharmony_ci}
72338c2ecf20Sopenharmony_ci
72348c2ecf20Sopenharmony_cistatic int devlink_trap_group_set(struct devlink *devlink,
72358c2ecf20Sopenharmony_ci				  struct devlink_trap_group_item *group_item,
72368c2ecf20Sopenharmony_ci				  struct genl_info *info)
72378c2ecf20Sopenharmony_ci{
72388c2ecf20Sopenharmony_ci	struct devlink_trap_policer_item *policer_item;
72398c2ecf20Sopenharmony_ci	struct netlink_ext_ack *extack = info->extack;
72408c2ecf20Sopenharmony_ci	const struct devlink_trap_policer *policer;
72418c2ecf20Sopenharmony_ci	struct nlattr **attrs = info->attrs;
72428c2ecf20Sopenharmony_ci	int err;
72438c2ecf20Sopenharmony_ci
72448c2ecf20Sopenharmony_ci	if (!attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
72458c2ecf20Sopenharmony_ci		return 0;
72468c2ecf20Sopenharmony_ci
72478c2ecf20Sopenharmony_ci	if (!devlink->ops->trap_group_set)
72488c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
72498c2ecf20Sopenharmony_ci
72508c2ecf20Sopenharmony_ci	policer_item = group_item->policer_item;
72518c2ecf20Sopenharmony_ci	if (attrs[DEVLINK_ATTR_TRAP_POLICER_ID]) {
72528c2ecf20Sopenharmony_ci		u32 policer_id;
72538c2ecf20Sopenharmony_ci
72548c2ecf20Sopenharmony_ci		policer_id = nla_get_u32(attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
72558c2ecf20Sopenharmony_ci		policer_item = devlink_trap_policer_item_lookup(devlink,
72568c2ecf20Sopenharmony_ci								policer_id);
72578c2ecf20Sopenharmony_ci		if (policer_id && !policer_item) {
72588c2ecf20Sopenharmony_ci			NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
72598c2ecf20Sopenharmony_ci			return -ENOENT;
72608c2ecf20Sopenharmony_ci		}
72618c2ecf20Sopenharmony_ci	}
72628c2ecf20Sopenharmony_ci	policer = policer_item ? policer_item->policer : NULL;
72638c2ecf20Sopenharmony_ci
72648c2ecf20Sopenharmony_ci	err = devlink->ops->trap_group_set(devlink, group_item->group, policer,
72658c2ecf20Sopenharmony_ci					   extack);
72668c2ecf20Sopenharmony_ci	if (err)
72678c2ecf20Sopenharmony_ci		return err;
72688c2ecf20Sopenharmony_ci
72698c2ecf20Sopenharmony_ci	group_item->policer_item = policer_item;
72708c2ecf20Sopenharmony_ci
72718c2ecf20Sopenharmony_ci	return 0;
72728c2ecf20Sopenharmony_ci}
72738c2ecf20Sopenharmony_ci
72748c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb,
72758c2ecf20Sopenharmony_ci					      struct genl_info *info)
72768c2ecf20Sopenharmony_ci{
72778c2ecf20Sopenharmony_ci	struct netlink_ext_ack *extack = info->extack;
72788c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
72798c2ecf20Sopenharmony_ci	struct devlink_trap_group_item *group_item;
72808c2ecf20Sopenharmony_ci	bool modified = false;
72818c2ecf20Sopenharmony_ci	int err;
72828c2ecf20Sopenharmony_ci
72838c2ecf20Sopenharmony_ci	if (list_empty(&devlink->trap_group_list))
72848c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
72858c2ecf20Sopenharmony_ci
72868c2ecf20Sopenharmony_ci	group_item = devlink_trap_group_item_get_from_info(devlink, info);
72878c2ecf20Sopenharmony_ci	if (!group_item) {
72888c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap group");
72898c2ecf20Sopenharmony_ci		return -ENOENT;
72908c2ecf20Sopenharmony_ci	}
72918c2ecf20Sopenharmony_ci
72928c2ecf20Sopenharmony_ci	err = devlink_trap_group_action_set(devlink, group_item, info,
72938c2ecf20Sopenharmony_ci					    &modified);
72948c2ecf20Sopenharmony_ci	if (err)
72958c2ecf20Sopenharmony_ci		return err;
72968c2ecf20Sopenharmony_ci
72978c2ecf20Sopenharmony_ci	err = devlink_trap_group_set(devlink, group_item, info);
72988c2ecf20Sopenharmony_ci	if (err)
72998c2ecf20Sopenharmony_ci		goto err_trap_group_set;
73008c2ecf20Sopenharmony_ci
73018c2ecf20Sopenharmony_ci	return 0;
73028c2ecf20Sopenharmony_ci
73038c2ecf20Sopenharmony_cierr_trap_group_set:
73048c2ecf20Sopenharmony_ci	if (modified)
73058c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Trap group set failed, but some changes were committed already");
73068c2ecf20Sopenharmony_ci	return err;
73078c2ecf20Sopenharmony_ci}
73088c2ecf20Sopenharmony_ci
73098c2ecf20Sopenharmony_cistatic struct devlink_trap_policer_item *
73108c2ecf20Sopenharmony_cidevlink_trap_policer_item_get_from_info(struct devlink *devlink,
73118c2ecf20Sopenharmony_ci					struct genl_info *info)
73128c2ecf20Sopenharmony_ci{
73138c2ecf20Sopenharmony_ci	u32 id;
73148c2ecf20Sopenharmony_ci
73158c2ecf20Sopenharmony_ci	if (!info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID])
73168c2ecf20Sopenharmony_ci		return NULL;
73178c2ecf20Sopenharmony_ci	id = nla_get_u32(info->attrs[DEVLINK_ATTR_TRAP_POLICER_ID]);
73188c2ecf20Sopenharmony_ci
73198c2ecf20Sopenharmony_ci	return devlink_trap_policer_item_lookup(devlink, id);
73208c2ecf20Sopenharmony_ci}
73218c2ecf20Sopenharmony_ci
73228c2ecf20Sopenharmony_cistatic int
73238c2ecf20Sopenharmony_cidevlink_trap_policer_stats_put(struct sk_buff *msg, struct devlink *devlink,
73248c2ecf20Sopenharmony_ci			       const struct devlink_trap_policer *policer)
73258c2ecf20Sopenharmony_ci{
73268c2ecf20Sopenharmony_ci	struct nlattr *attr;
73278c2ecf20Sopenharmony_ci	u64 drops;
73288c2ecf20Sopenharmony_ci	int err;
73298c2ecf20Sopenharmony_ci
73308c2ecf20Sopenharmony_ci	if (!devlink->ops->trap_policer_counter_get)
73318c2ecf20Sopenharmony_ci		return 0;
73328c2ecf20Sopenharmony_ci
73338c2ecf20Sopenharmony_ci	err = devlink->ops->trap_policer_counter_get(devlink, policer, &drops);
73348c2ecf20Sopenharmony_ci	if (err)
73358c2ecf20Sopenharmony_ci		return err;
73368c2ecf20Sopenharmony_ci
73378c2ecf20Sopenharmony_ci	attr = nla_nest_start(msg, DEVLINK_ATTR_STATS);
73388c2ecf20Sopenharmony_ci	if (!attr)
73398c2ecf20Sopenharmony_ci		return -EMSGSIZE;
73408c2ecf20Sopenharmony_ci
73418c2ecf20Sopenharmony_ci	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_STATS_RX_DROPPED, drops,
73428c2ecf20Sopenharmony_ci			      DEVLINK_ATTR_PAD))
73438c2ecf20Sopenharmony_ci		goto nla_put_failure;
73448c2ecf20Sopenharmony_ci
73458c2ecf20Sopenharmony_ci	nla_nest_end(msg, attr);
73468c2ecf20Sopenharmony_ci
73478c2ecf20Sopenharmony_ci	return 0;
73488c2ecf20Sopenharmony_ci
73498c2ecf20Sopenharmony_cinla_put_failure:
73508c2ecf20Sopenharmony_ci	nla_nest_cancel(msg, attr);
73518c2ecf20Sopenharmony_ci	return -EMSGSIZE;
73528c2ecf20Sopenharmony_ci}
73538c2ecf20Sopenharmony_ci
73548c2ecf20Sopenharmony_cistatic int
73558c2ecf20Sopenharmony_cidevlink_nl_trap_policer_fill(struct sk_buff *msg, struct devlink *devlink,
73568c2ecf20Sopenharmony_ci			     const struct devlink_trap_policer_item *policer_item,
73578c2ecf20Sopenharmony_ci			     enum devlink_command cmd, u32 portid, u32 seq,
73588c2ecf20Sopenharmony_ci			     int flags)
73598c2ecf20Sopenharmony_ci{
73608c2ecf20Sopenharmony_ci	void *hdr;
73618c2ecf20Sopenharmony_ci	int err;
73628c2ecf20Sopenharmony_ci
73638c2ecf20Sopenharmony_ci	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
73648c2ecf20Sopenharmony_ci	if (!hdr)
73658c2ecf20Sopenharmony_ci		return -EMSGSIZE;
73668c2ecf20Sopenharmony_ci
73678c2ecf20Sopenharmony_ci	if (devlink_nl_put_handle(msg, devlink))
73688c2ecf20Sopenharmony_ci		goto nla_put_failure;
73698c2ecf20Sopenharmony_ci
73708c2ecf20Sopenharmony_ci	if (nla_put_u32(msg, DEVLINK_ATTR_TRAP_POLICER_ID,
73718c2ecf20Sopenharmony_ci			policer_item->policer->id))
73728c2ecf20Sopenharmony_ci		goto nla_put_failure;
73738c2ecf20Sopenharmony_ci
73748c2ecf20Sopenharmony_ci	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_RATE,
73758c2ecf20Sopenharmony_ci			      policer_item->rate, DEVLINK_ATTR_PAD))
73768c2ecf20Sopenharmony_ci		goto nla_put_failure;
73778c2ecf20Sopenharmony_ci
73788c2ecf20Sopenharmony_ci	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_TRAP_POLICER_BURST,
73798c2ecf20Sopenharmony_ci			      policer_item->burst, DEVLINK_ATTR_PAD))
73808c2ecf20Sopenharmony_ci		goto nla_put_failure;
73818c2ecf20Sopenharmony_ci
73828c2ecf20Sopenharmony_ci	err = devlink_trap_policer_stats_put(msg, devlink,
73838c2ecf20Sopenharmony_ci					     policer_item->policer);
73848c2ecf20Sopenharmony_ci	if (err)
73858c2ecf20Sopenharmony_ci		goto nla_put_failure;
73868c2ecf20Sopenharmony_ci
73878c2ecf20Sopenharmony_ci	genlmsg_end(msg, hdr);
73888c2ecf20Sopenharmony_ci
73898c2ecf20Sopenharmony_ci	return 0;
73908c2ecf20Sopenharmony_ci
73918c2ecf20Sopenharmony_cinla_put_failure:
73928c2ecf20Sopenharmony_ci	genlmsg_cancel(msg, hdr);
73938c2ecf20Sopenharmony_ci	return -EMSGSIZE;
73948c2ecf20Sopenharmony_ci}
73958c2ecf20Sopenharmony_ci
73968c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_policer_get_doit(struct sk_buff *skb,
73978c2ecf20Sopenharmony_ci						struct genl_info *info)
73988c2ecf20Sopenharmony_ci{
73998c2ecf20Sopenharmony_ci	struct devlink_trap_policer_item *policer_item;
74008c2ecf20Sopenharmony_ci	struct netlink_ext_ack *extack = info->extack;
74018c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
74028c2ecf20Sopenharmony_ci	struct sk_buff *msg;
74038c2ecf20Sopenharmony_ci	int err;
74048c2ecf20Sopenharmony_ci
74058c2ecf20Sopenharmony_ci	if (list_empty(&devlink->trap_policer_list))
74068c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
74078c2ecf20Sopenharmony_ci
74088c2ecf20Sopenharmony_ci	policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
74098c2ecf20Sopenharmony_ci	if (!policer_item) {
74108c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
74118c2ecf20Sopenharmony_ci		return -ENOENT;
74128c2ecf20Sopenharmony_ci	}
74138c2ecf20Sopenharmony_ci
74148c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
74158c2ecf20Sopenharmony_ci	if (!msg)
74168c2ecf20Sopenharmony_ci		return -ENOMEM;
74178c2ecf20Sopenharmony_ci
74188c2ecf20Sopenharmony_ci	err = devlink_nl_trap_policer_fill(msg, devlink, policer_item,
74198c2ecf20Sopenharmony_ci					   DEVLINK_CMD_TRAP_POLICER_NEW,
74208c2ecf20Sopenharmony_ci					   info->snd_portid, info->snd_seq, 0);
74218c2ecf20Sopenharmony_ci	if (err)
74228c2ecf20Sopenharmony_ci		goto err_trap_policer_fill;
74238c2ecf20Sopenharmony_ci
74248c2ecf20Sopenharmony_ci	return genlmsg_reply(msg, info);
74258c2ecf20Sopenharmony_ci
74268c2ecf20Sopenharmony_cierr_trap_policer_fill:
74278c2ecf20Sopenharmony_ci	nlmsg_free(msg);
74288c2ecf20Sopenharmony_ci	return err;
74298c2ecf20Sopenharmony_ci}
74308c2ecf20Sopenharmony_ci
74318c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_policer_get_dumpit(struct sk_buff *msg,
74328c2ecf20Sopenharmony_ci						  struct netlink_callback *cb)
74338c2ecf20Sopenharmony_ci{
74348c2ecf20Sopenharmony_ci	enum devlink_command cmd = DEVLINK_CMD_TRAP_POLICER_NEW;
74358c2ecf20Sopenharmony_ci	struct devlink_trap_policer_item *policer_item;
74368c2ecf20Sopenharmony_ci	u32 portid = NETLINK_CB(cb->skb).portid;
74378c2ecf20Sopenharmony_ci	struct devlink *devlink;
74388c2ecf20Sopenharmony_ci	int start = cb->args[0];
74398c2ecf20Sopenharmony_ci	int idx = 0;
74408c2ecf20Sopenharmony_ci	int err;
74418c2ecf20Sopenharmony_ci
74428c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
74438c2ecf20Sopenharmony_ci	list_for_each_entry(devlink, &devlink_list, list) {
74448c2ecf20Sopenharmony_ci		if (!net_eq(devlink_net(devlink), sock_net(msg->sk)))
74458c2ecf20Sopenharmony_ci			continue;
74468c2ecf20Sopenharmony_ci		mutex_lock(&devlink->lock);
74478c2ecf20Sopenharmony_ci		list_for_each_entry(policer_item, &devlink->trap_policer_list,
74488c2ecf20Sopenharmony_ci				    list) {
74498c2ecf20Sopenharmony_ci			if (idx < start) {
74508c2ecf20Sopenharmony_ci				idx++;
74518c2ecf20Sopenharmony_ci				continue;
74528c2ecf20Sopenharmony_ci			}
74538c2ecf20Sopenharmony_ci			err = devlink_nl_trap_policer_fill(msg, devlink,
74548c2ecf20Sopenharmony_ci							   policer_item, cmd,
74558c2ecf20Sopenharmony_ci							   portid,
74568c2ecf20Sopenharmony_ci							   cb->nlh->nlmsg_seq,
74578c2ecf20Sopenharmony_ci							   NLM_F_MULTI);
74588c2ecf20Sopenharmony_ci			if (err) {
74598c2ecf20Sopenharmony_ci				mutex_unlock(&devlink->lock);
74608c2ecf20Sopenharmony_ci				goto out;
74618c2ecf20Sopenharmony_ci			}
74628c2ecf20Sopenharmony_ci			idx++;
74638c2ecf20Sopenharmony_ci		}
74648c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->lock);
74658c2ecf20Sopenharmony_ci	}
74668c2ecf20Sopenharmony_ciout:
74678c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
74688c2ecf20Sopenharmony_ci
74698c2ecf20Sopenharmony_ci	cb->args[0] = idx;
74708c2ecf20Sopenharmony_ci	return msg->len;
74718c2ecf20Sopenharmony_ci}
74728c2ecf20Sopenharmony_ci
74738c2ecf20Sopenharmony_cistatic int
74748c2ecf20Sopenharmony_cidevlink_trap_policer_set(struct devlink *devlink,
74758c2ecf20Sopenharmony_ci			 struct devlink_trap_policer_item *policer_item,
74768c2ecf20Sopenharmony_ci			 struct genl_info *info)
74778c2ecf20Sopenharmony_ci{
74788c2ecf20Sopenharmony_ci	struct netlink_ext_ack *extack = info->extack;
74798c2ecf20Sopenharmony_ci	struct nlattr **attrs = info->attrs;
74808c2ecf20Sopenharmony_ci	u64 rate, burst;
74818c2ecf20Sopenharmony_ci	int err;
74828c2ecf20Sopenharmony_ci
74838c2ecf20Sopenharmony_ci	rate = policer_item->rate;
74848c2ecf20Sopenharmony_ci	burst = policer_item->burst;
74858c2ecf20Sopenharmony_ci
74868c2ecf20Sopenharmony_ci	if (attrs[DEVLINK_ATTR_TRAP_POLICER_RATE])
74878c2ecf20Sopenharmony_ci		rate = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_RATE]);
74888c2ecf20Sopenharmony_ci
74898c2ecf20Sopenharmony_ci	if (attrs[DEVLINK_ATTR_TRAP_POLICER_BURST])
74908c2ecf20Sopenharmony_ci		burst = nla_get_u64(attrs[DEVLINK_ATTR_TRAP_POLICER_BURST]);
74918c2ecf20Sopenharmony_ci
74928c2ecf20Sopenharmony_ci	if (rate < policer_item->policer->min_rate) {
74938c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Policer rate lower than limit");
74948c2ecf20Sopenharmony_ci		return -EINVAL;
74958c2ecf20Sopenharmony_ci	}
74968c2ecf20Sopenharmony_ci
74978c2ecf20Sopenharmony_ci	if (rate > policer_item->policer->max_rate) {
74988c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Policer rate higher than limit");
74998c2ecf20Sopenharmony_ci		return -EINVAL;
75008c2ecf20Sopenharmony_ci	}
75018c2ecf20Sopenharmony_ci
75028c2ecf20Sopenharmony_ci	if (burst < policer_item->policer->min_burst) {
75038c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Policer burst size lower than limit");
75048c2ecf20Sopenharmony_ci		return -EINVAL;
75058c2ecf20Sopenharmony_ci	}
75068c2ecf20Sopenharmony_ci
75078c2ecf20Sopenharmony_ci	if (burst > policer_item->policer->max_burst) {
75088c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Policer burst size higher than limit");
75098c2ecf20Sopenharmony_ci		return -EINVAL;
75108c2ecf20Sopenharmony_ci	}
75118c2ecf20Sopenharmony_ci
75128c2ecf20Sopenharmony_ci	err = devlink->ops->trap_policer_set(devlink, policer_item->policer,
75138c2ecf20Sopenharmony_ci					     rate, burst, info->extack);
75148c2ecf20Sopenharmony_ci	if (err)
75158c2ecf20Sopenharmony_ci		return err;
75168c2ecf20Sopenharmony_ci
75178c2ecf20Sopenharmony_ci	policer_item->rate = rate;
75188c2ecf20Sopenharmony_ci	policer_item->burst = burst;
75198c2ecf20Sopenharmony_ci
75208c2ecf20Sopenharmony_ci	return 0;
75218c2ecf20Sopenharmony_ci}
75228c2ecf20Sopenharmony_ci
75238c2ecf20Sopenharmony_cistatic int devlink_nl_cmd_trap_policer_set_doit(struct sk_buff *skb,
75248c2ecf20Sopenharmony_ci						struct genl_info *info)
75258c2ecf20Sopenharmony_ci{
75268c2ecf20Sopenharmony_ci	struct devlink_trap_policer_item *policer_item;
75278c2ecf20Sopenharmony_ci	struct netlink_ext_ack *extack = info->extack;
75288c2ecf20Sopenharmony_ci	struct devlink *devlink = info->user_ptr[0];
75298c2ecf20Sopenharmony_ci
75308c2ecf20Sopenharmony_ci	if (list_empty(&devlink->trap_policer_list))
75318c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
75328c2ecf20Sopenharmony_ci
75338c2ecf20Sopenharmony_ci	if (!devlink->ops->trap_policer_set)
75348c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
75358c2ecf20Sopenharmony_ci
75368c2ecf20Sopenharmony_ci	policer_item = devlink_trap_policer_item_get_from_info(devlink, info);
75378c2ecf20Sopenharmony_ci	if (!policer_item) {
75388c2ecf20Sopenharmony_ci		NL_SET_ERR_MSG_MOD(extack, "Device did not register this trap policer");
75398c2ecf20Sopenharmony_ci		return -ENOENT;
75408c2ecf20Sopenharmony_ci	}
75418c2ecf20Sopenharmony_ci
75428c2ecf20Sopenharmony_ci	return devlink_trap_policer_set(devlink, policer_item, info);
75438c2ecf20Sopenharmony_ci}
75448c2ecf20Sopenharmony_ci
75458c2ecf20Sopenharmony_cistatic const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
75468c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_UNSPEC] = { .strict_start_type =
75478c2ecf20Sopenharmony_ci		DEVLINK_ATTR_TRAP_POLICER_ID },
75488c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
75498c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
75508c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32 },
75518c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_PORT_TYPE] = NLA_POLICY_RANGE(NLA_U16, DEVLINK_PORT_TYPE_AUTO,
75528c2ecf20Sopenharmony_ci						    DEVLINK_PORT_TYPE_IB),
75538c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_PORT_SPLIT_COUNT] = { .type = NLA_U32 },
75548c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_SB_INDEX] = { .type = NLA_U32 },
75558c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_SB_POOL_INDEX] = { .type = NLA_U16 },
75568c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_SB_POOL_TYPE] = { .type = NLA_U8 },
75578c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_SB_POOL_SIZE] = { .type = NLA_U32 },
75588c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = { .type = NLA_U8 },
75598c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_SB_THRESHOLD] = { .type = NLA_U32 },
75608c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_SB_TC_INDEX] = { .type = NLA_U16 },
75618c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_ESWITCH_MODE] = NLA_POLICY_RANGE(NLA_U16, DEVLINK_ESWITCH_MODE_LEGACY,
75628c2ecf20Sopenharmony_ci						       DEVLINK_ESWITCH_MODE_SWITCHDEV),
75638c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_ESWITCH_INLINE_MODE] = { .type = NLA_U8 },
75648c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = { .type = NLA_U8 },
75658c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_DPIPE_TABLE_NAME] = { .type = NLA_NUL_STRING },
75668c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = { .type = NLA_U8 },
75678c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_RESOURCE_ID] = { .type = NLA_U64},
75688c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_RESOURCE_SIZE] = { .type = NLA_U64},
75698c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_PARAM_NAME] = { .type = NLA_NUL_STRING },
75708c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_PARAM_TYPE] = { .type = NLA_U8 },
75718c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_PARAM_VALUE_CMODE] = { .type = NLA_U8 },
75728c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_REGION_NAME] = { .type = NLA_NUL_STRING },
75738c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_REGION_SNAPSHOT_ID] = { .type = NLA_U32 },
75748c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_REGION_CHUNK_ADDR] = { .type = NLA_U64 },
75758c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_REGION_CHUNK_LEN] = { .type = NLA_U64 },
75768c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_HEALTH_REPORTER_NAME] = { .type = NLA_NUL_STRING },
75778c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = { .type = NLA_U64 },
75788c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER] = { .type = NLA_U8 },
75798c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME] = { .type = NLA_NUL_STRING },
75808c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = { .type = NLA_NUL_STRING },
75818c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK] =
75828c2ecf20Sopenharmony_ci		NLA_POLICY_BITFIELD32(DEVLINK_SUPPORTED_FLASH_OVERWRITE_SECTIONS),
75838c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_TRAP_NAME] = { .type = NLA_NUL_STRING },
75848c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_TRAP_ACTION] = { .type = NLA_U8 },
75858c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_TRAP_GROUP_NAME] = { .type = NLA_NUL_STRING },
75868c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_NETNS_PID] = { .type = NLA_U32 },
75878c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_NETNS_FD] = { .type = NLA_U32 },
75888c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_NETNS_ID] = { .type = NLA_U32 },
75898c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP] = { .type = NLA_U8 },
75908c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_TRAP_POLICER_ID] = { .type = NLA_U32 },
75918c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_TRAP_POLICER_RATE] = { .type = NLA_U64 },
75928c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_TRAP_POLICER_BURST] = { .type = NLA_U64 },
75938c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_PORT_FUNCTION] = { .type = NLA_NESTED },
75948c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
75958c2ecf20Sopenharmony_ci							DEVLINK_RELOAD_ACTION_MAX),
75968c2ecf20Sopenharmony_ci	[DEVLINK_ATTR_RELOAD_LIMITS] = NLA_POLICY_BITFIELD32(DEVLINK_RELOAD_LIMITS_VALID_MASK),
75978c2ecf20Sopenharmony_ci};
75988c2ecf20Sopenharmony_ci
75998c2ecf20Sopenharmony_cistatic const struct genl_small_ops devlink_nl_ops[] = {
76008c2ecf20Sopenharmony_ci	{
76018c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_GET,
76028c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
76038c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_get_doit,
76048c2ecf20Sopenharmony_ci		.dumpit = devlink_nl_cmd_get_dumpit,
76058c2ecf20Sopenharmony_ci		/* can be retrieved by unprivileged users */
76068c2ecf20Sopenharmony_ci	},
76078c2ecf20Sopenharmony_ci	{
76088c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_PORT_GET,
76098c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
76108c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_port_get_doit,
76118c2ecf20Sopenharmony_ci		.dumpit = devlink_nl_cmd_port_get_dumpit,
76128c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
76138c2ecf20Sopenharmony_ci		/* can be retrieved by unprivileged users */
76148c2ecf20Sopenharmony_ci	},
76158c2ecf20Sopenharmony_ci	{
76168c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_PORT_SET,
76178c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
76188c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_port_set_doit,
76198c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
76208c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
76218c2ecf20Sopenharmony_ci	},
76228c2ecf20Sopenharmony_ci	{
76238c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_PORT_SPLIT,
76248c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
76258c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_port_split_doit,
76268c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
76278c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
76288c2ecf20Sopenharmony_ci	},
76298c2ecf20Sopenharmony_ci	{
76308c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_PORT_UNSPLIT,
76318c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
76328c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_port_unsplit_doit,
76338c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
76348c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
76358c2ecf20Sopenharmony_ci	},
76368c2ecf20Sopenharmony_ci	{
76378c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_SB_GET,
76388c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
76398c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_sb_get_doit,
76408c2ecf20Sopenharmony_ci		.dumpit = devlink_nl_cmd_sb_get_dumpit,
76418c2ecf20Sopenharmony_ci		/* can be retrieved by unprivileged users */
76428c2ecf20Sopenharmony_ci	},
76438c2ecf20Sopenharmony_ci	{
76448c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_SB_POOL_GET,
76458c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
76468c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_sb_pool_get_doit,
76478c2ecf20Sopenharmony_ci		.dumpit = devlink_nl_cmd_sb_pool_get_dumpit,
76488c2ecf20Sopenharmony_ci		/* can be retrieved by unprivileged users */
76498c2ecf20Sopenharmony_ci	},
76508c2ecf20Sopenharmony_ci	{
76518c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_SB_POOL_SET,
76528c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
76538c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_sb_pool_set_doit,
76548c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
76558c2ecf20Sopenharmony_ci	},
76568c2ecf20Sopenharmony_ci	{
76578c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_SB_PORT_POOL_GET,
76588c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
76598c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_sb_port_pool_get_doit,
76608c2ecf20Sopenharmony_ci		.dumpit = devlink_nl_cmd_sb_port_pool_get_dumpit,
76618c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
76628c2ecf20Sopenharmony_ci		/* can be retrieved by unprivileged users */
76638c2ecf20Sopenharmony_ci	},
76648c2ecf20Sopenharmony_ci	{
76658c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_SB_PORT_POOL_SET,
76668c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
76678c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_sb_port_pool_set_doit,
76688c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
76698c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
76708c2ecf20Sopenharmony_ci	},
76718c2ecf20Sopenharmony_ci	{
76728c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_SB_TC_POOL_BIND_GET,
76738c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
76748c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_sb_tc_pool_bind_get_doit,
76758c2ecf20Sopenharmony_ci		.dumpit = devlink_nl_cmd_sb_tc_pool_bind_get_dumpit,
76768c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
76778c2ecf20Sopenharmony_ci		/* can be retrieved by unprivileged users */
76788c2ecf20Sopenharmony_ci	},
76798c2ecf20Sopenharmony_ci	{
76808c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_SB_TC_POOL_BIND_SET,
76818c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
76828c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_sb_tc_pool_bind_set_doit,
76838c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
76848c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
76858c2ecf20Sopenharmony_ci	},
76868c2ecf20Sopenharmony_ci	{
76878c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_SB_OCC_SNAPSHOT,
76888c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
76898c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_sb_occ_snapshot_doit,
76908c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
76918c2ecf20Sopenharmony_ci	},
76928c2ecf20Sopenharmony_ci	{
76938c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_SB_OCC_MAX_CLEAR,
76948c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
76958c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_sb_occ_max_clear_doit,
76968c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
76978c2ecf20Sopenharmony_ci	},
76988c2ecf20Sopenharmony_ci	{
76998c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_ESWITCH_GET,
77008c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
77018c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_eswitch_get_doit,
77028c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
77038c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
77048c2ecf20Sopenharmony_ci	},
77058c2ecf20Sopenharmony_ci	{
77068c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_ESWITCH_SET,
77078c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
77088c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_eswitch_set_doit,
77098c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
77108c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
77118c2ecf20Sopenharmony_ci	},
77128c2ecf20Sopenharmony_ci	{
77138c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_DPIPE_TABLE_GET,
77148c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
77158c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_dpipe_table_get,
77168c2ecf20Sopenharmony_ci		/* can be retrieved by unprivileged users */
77178c2ecf20Sopenharmony_ci	},
77188c2ecf20Sopenharmony_ci	{
77198c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_DPIPE_ENTRIES_GET,
77208c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
77218c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_dpipe_entries_get,
77228c2ecf20Sopenharmony_ci		/* can be retrieved by unprivileged users */
77238c2ecf20Sopenharmony_ci	},
77248c2ecf20Sopenharmony_ci	{
77258c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_DPIPE_HEADERS_GET,
77268c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
77278c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_dpipe_headers_get,
77288c2ecf20Sopenharmony_ci		/* can be retrieved by unprivileged users */
77298c2ecf20Sopenharmony_ci	},
77308c2ecf20Sopenharmony_ci	{
77318c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
77328c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
77338c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_dpipe_table_counters_set,
77348c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
77358c2ecf20Sopenharmony_ci	},
77368c2ecf20Sopenharmony_ci	{
77378c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_RESOURCE_SET,
77388c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
77398c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_resource_set,
77408c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
77418c2ecf20Sopenharmony_ci	},
77428c2ecf20Sopenharmony_ci	{
77438c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_RESOURCE_DUMP,
77448c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
77458c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_resource_dump,
77468c2ecf20Sopenharmony_ci		/* can be retrieved by unprivileged users */
77478c2ecf20Sopenharmony_ci	},
77488c2ecf20Sopenharmony_ci	{
77498c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_RELOAD,
77508c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
77518c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_reload,
77528c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
77538c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NO_LOCK,
77548c2ecf20Sopenharmony_ci	},
77558c2ecf20Sopenharmony_ci	{
77568c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_PARAM_GET,
77578c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
77588c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_param_get_doit,
77598c2ecf20Sopenharmony_ci		.dumpit = devlink_nl_cmd_param_get_dumpit,
77608c2ecf20Sopenharmony_ci		/* can be retrieved by unprivileged users */
77618c2ecf20Sopenharmony_ci	},
77628c2ecf20Sopenharmony_ci	{
77638c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_PARAM_SET,
77648c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
77658c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_param_set_doit,
77668c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
77678c2ecf20Sopenharmony_ci	},
77688c2ecf20Sopenharmony_ci	{
77698c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_PORT_PARAM_GET,
77708c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
77718c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_port_param_get_doit,
77728c2ecf20Sopenharmony_ci		.dumpit = devlink_nl_cmd_port_param_get_dumpit,
77738c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
77748c2ecf20Sopenharmony_ci		/* can be retrieved by unprivileged users */
77758c2ecf20Sopenharmony_ci	},
77768c2ecf20Sopenharmony_ci	{
77778c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_PORT_PARAM_SET,
77788c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
77798c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_port_param_set_doit,
77808c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
77818c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NEED_PORT,
77828c2ecf20Sopenharmony_ci	},
77838c2ecf20Sopenharmony_ci	{
77848c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_REGION_GET,
77858c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
77868c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_region_get_doit,
77878c2ecf20Sopenharmony_ci		.dumpit = devlink_nl_cmd_region_get_dumpit,
77888c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
77898c2ecf20Sopenharmony_ci	},
77908c2ecf20Sopenharmony_ci	{
77918c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_REGION_NEW,
77928c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
77938c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_region_new,
77948c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
77958c2ecf20Sopenharmony_ci	},
77968c2ecf20Sopenharmony_ci	{
77978c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_REGION_DEL,
77988c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
77998c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_region_del,
78008c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
78018c2ecf20Sopenharmony_ci	},
78028c2ecf20Sopenharmony_ci	{
78038c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_REGION_READ,
78048c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT |
78058c2ecf20Sopenharmony_ci			    GENL_DONT_VALIDATE_DUMP_STRICT,
78068c2ecf20Sopenharmony_ci		.dumpit = devlink_nl_cmd_region_read_dumpit,
78078c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
78088c2ecf20Sopenharmony_ci	},
78098c2ecf20Sopenharmony_ci	{
78108c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_INFO_GET,
78118c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
78128c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_info_get_doit,
78138c2ecf20Sopenharmony_ci		.dumpit = devlink_nl_cmd_info_get_dumpit,
78148c2ecf20Sopenharmony_ci		/* can be retrieved by unprivileged users */
78158c2ecf20Sopenharmony_ci	},
78168c2ecf20Sopenharmony_ci	{
78178c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_HEALTH_REPORTER_GET,
78188c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
78198c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_health_reporter_get_doit,
78208c2ecf20Sopenharmony_ci		.dumpit = devlink_nl_cmd_health_reporter_get_dumpit,
78218c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
78228c2ecf20Sopenharmony_ci				  DEVLINK_NL_FLAG_NO_LOCK,
78238c2ecf20Sopenharmony_ci		/* can be retrieved by unprivileged users */
78248c2ecf20Sopenharmony_ci	},
78258c2ecf20Sopenharmony_ci	{
78268c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_HEALTH_REPORTER_SET,
78278c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
78288c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_health_reporter_set_doit,
78298c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
78308c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
78318c2ecf20Sopenharmony_ci				  DEVLINK_NL_FLAG_NO_LOCK,
78328c2ecf20Sopenharmony_ci	},
78338c2ecf20Sopenharmony_ci	{
78348c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
78358c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
78368c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_health_reporter_recover_doit,
78378c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
78388c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
78398c2ecf20Sopenharmony_ci				  DEVLINK_NL_FLAG_NO_LOCK,
78408c2ecf20Sopenharmony_ci	},
78418c2ecf20Sopenharmony_ci	{
78428c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
78438c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
78448c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_health_reporter_diagnose_doit,
78458c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
78468c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
78478c2ecf20Sopenharmony_ci				  DEVLINK_NL_FLAG_NO_LOCK,
78488c2ecf20Sopenharmony_ci	},
78498c2ecf20Sopenharmony_ci	{
78508c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
78518c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT |
78528c2ecf20Sopenharmony_ci			    GENL_DONT_VALIDATE_DUMP_STRICT,
78538c2ecf20Sopenharmony_ci		.dumpit = devlink_nl_cmd_health_reporter_dump_get_dumpit,
78548c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
78558c2ecf20Sopenharmony_ci	},
78568c2ecf20Sopenharmony_ci	{
78578c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
78588c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
78598c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_health_reporter_dump_clear_doit,
78608c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
78618c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
78628c2ecf20Sopenharmony_ci				  DEVLINK_NL_FLAG_NO_LOCK,
78638c2ecf20Sopenharmony_ci	},
78648c2ecf20Sopenharmony_ci	{
78658c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_HEALTH_REPORTER_TEST,
78668c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
78678c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_health_reporter_test_doit,
78688c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
78698c2ecf20Sopenharmony_ci		.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT |
78708c2ecf20Sopenharmony_ci				  DEVLINK_NL_FLAG_NO_LOCK,
78718c2ecf20Sopenharmony_ci	},
78728c2ecf20Sopenharmony_ci	{
78738c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_FLASH_UPDATE,
78748c2ecf20Sopenharmony_ci		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
78758c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_flash_update,
78768c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
78778c2ecf20Sopenharmony_ci	},
78788c2ecf20Sopenharmony_ci	{
78798c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_TRAP_GET,
78808c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_trap_get_doit,
78818c2ecf20Sopenharmony_ci		.dumpit = devlink_nl_cmd_trap_get_dumpit,
78828c2ecf20Sopenharmony_ci		/* can be retrieved by unprivileged users */
78838c2ecf20Sopenharmony_ci	},
78848c2ecf20Sopenharmony_ci	{
78858c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_TRAP_SET,
78868c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_trap_set_doit,
78878c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
78888c2ecf20Sopenharmony_ci	},
78898c2ecf20Sopenharmony_ci	{
78908c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_TRAP_GROUP_GET,
78918c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_trap_group_get_doit,
78928c2ecf20Sopenharmony_ci		.dumpit = devlink_nl_cmd_trap_group_get_dumpit,
78938c2ecf20Sopenharmony_ci		/* can be retrieved by unprivileged users */
78948c2ecf20Sopenharmony_ci	},
78958c2ecf20Sopenharmony_ci	{
78968c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_TRAP_GROUP_SET,
78978c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_trap_group_set_doit,
78988c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
78998c2ecf20Sopenharmony_ci	},
79008c2ecf20Sopenharmony_ci	{
79018c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_TRAP_POLICER_GET,
79028c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_trap_policer_get_doit,
79038c2ecf20Sopenharmony_ci		.dumpit = devlink_nl_cmd_trap_policer_get_dumpit,
79048c2ecf20Sopenharmony_ci		/* can be retrieved by unprivileged users */
79058c2ecf20Sopenharmony_ci	},
79068c2ecf20Sopenharmony_ci	{
79078c2ecf20Sopenharmony_ci		.cmd = DEVLINK_CMD_TRAP_POLICER_SET,
79088c2ecf20Sopenharmony_ci		.doit = devlink_nl_cmd_trap_policer_set_doit,
79098c2ecf20Sopenharmony_ci		.flags = GENL_ADMIN_PERM,
79108c2ecf20Sopenharmony_ci	},
79118c2ecf20Sopenharmony_ci};
79128c2ecf20Sopenharmony_ci
79138c2ecf20Sopenharmony_cistatic struct genl_family devlink_nl_family __ro_after_init = {
79148c2ecf20Sopenharmony_ci	.name		= DEVLINK_GENL_NAME,
79158c2ecf20Sopenharmony_ci	.version	= DEVLINK_GENL_VERSION,
79168c2ecf20Sopenharmony_ci	.maxattr	= DEVLINK_ATTR_MAX,
79178c2ecf20Sopenharmony_ci	.policy = devlink_nl_policy,
79188c2ecf20Sopenharmony_ci	.netnsok	= true,
79198c2ecf20Sopenharmony_ci	.pre_doit	= devlink_nl_pre_doit,
79208c2ecf20Sopenharmony_ci	.post_doit	= devlink_nl_post_doit,
79218c2ecf20Sopenharmony_ci	.module		= THIS_MODULE,
79228c2ecf20Sopenharmony_ci	.small_ops	= devlink_nl_ops,
79238c2ecf20Sopenharmony_ci	.n_small_ops	= ARRAY_SIZE(devlink_nl_ops),
79248c2ecf20Sopenharmony_ci	.mcgrps		= devlink_nl_mcgrps,
79258c2ecf20Sopenharmony_ci	.n_mcgrps	= ARRAY_SIZE(devlink_nl_mcgrps),
79268c2ecf20Sopenharmony_ci};
79278c2ecf20Sopenharmony_ci
79288c2ecf20Sopenharmony_cistatic bool devlink_reload_actions_valid(const struct devlink_ops *ops)
79298c2ecf20Sopenharmony_ci{
79308c2ecf20Sopenharmony_ci	const struct devlink_reload_combination *comb;
79318c2ecf20Sopenharmony_ci	int i;
79328c2ecf20Sopenharmony_ci
79338c2ecf20Sopenharmony_ci	if (!devlink_reload_supported(ops)) {
79348c2ecf20Sopenharmony_ci		if (WARN_ON(ops->reload_actions))
79358c2ecf20Sopenharmony_ci			return false;
79368c2ecf20Sopenharmony_ci		return true;
79378c2ecf20Sopenharmony_ci	}
79388c2ecf20Sopenharmony_ci
79398c2ecf20Sopenharmony_ci	if (WARN_ON(!ops->reload_actions ||
79408c2ecf20Sopenharmony_ci		    ops->reload_actions & BIT(DEVLINK_RELOAD_ACTION_UNSPEC) ||
79418c2ecf20Sopenharmony_ci		    ops->reload_actions >= BIT(__DEVLINK_RELOAD_ACTION_MAX)))
79428c2ecf20Sopenharmony_ci		return false;
79438c2ecf20Sopenharmony_ci
79448c2ecf20Sopenharmony_ci	if (WARN_ON(ops->reload_limits & BIT(DEVLINK_RELOAD_LIMIT_UNSPEC) ||
79458c2ecf20Sopenharmony_ci		    ops->reload_limits >= BIT(__DEVLINK_RELOAD_LIMIT_MAX)))
79468c2ecf20Sopenharmony_ci		return false;
79478c2ecf20Sopenharmony_ci
79488c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(devlink_reload_invalid_combinations); i++)  {
79498c2ecf20Sopenharmony_ci		comb = &devlink_reload_invalid_combinations[i];
79508c2ecf20Sopenharmony_ci		if (ops->reload_actions == BIT(comb->action) &&
79518c2ecf20Sopenharmony_ci		    ops->reload_limits == BIT(comb->limit))
79528c2ecf20Sopenharmony_ci			return false;
79538c2ecf20Sopenharmony_ci	}
79548c2ecf20Sopenharmony_ci	return true;
79558c2ecf20Sopenharmony_ci}
79568c2ecf20Sopenharmony_ci
79578c2ecf20Sopenharmony_ci/**
79588c2ecf20Sopenharmony_ci *	devlink_alloc - Allocate new devlink instance resources
79598c2ecf20Sopenharmony_ci *
79608c2ecf20Sopenharmony_ci *	@ops: ops
79618c2ecf20Sopenharmony_ci *	@priv_size: size of user private data
79628c2ecf20Sopenharmony_ci *
79638c2ecf20Sopenharmony_ci *	Allocate new devlink instance resources, including devlink index
79648c2ecf20Sopenharmony_ci *	and name.
79658c2ecf20Sopenharmony_ci */
79668c2ecf20Sopenharmony_cistruct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size)
79678c2ecf20Sopenharmony_ci{
79688c2ecf20Sopenharmony_ci	struct devlink *devlink;
79698c2ecf20Sopenharmony_ci
79708c2ecf20Sopenharmony_ci	if (WARN_ON(!ops))
79718c2ecf20Sopenharmony_ci		return NULL;
79728c2ecf20Sopenharmony_ci
79738c2ecf20Sopenharmony_ci	if (!devlink_reload_actions_valid(ops))
79748c2ecf20Sopenharmony_ci		return NULL;
79758c2ecf20Sopenharmony_ci
79768c2ecf20Sopenharmony_ci	devlink = kzalloc(sizeof(*devlink) + priv_size, GFP_KERNEL);
79778c2ecf20Sopenharmony_ci	if (!devlink)
79788c2ecf20Sopenharmony_ci		return NULL;
79798c2ecf20Sopenharmony_ci	devlink->ops = ops;
79808c2ecf20Sopenharmony_ci	xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC);
79818c2ecf20Sopenharmony_ci	__devlink_net_set(devlink, &init_net);
79828c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&devlink->port_list);
79838c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&devlink->sb_list);
79848c2ecf20Sopenharmony_ci	INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list);
79858c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&devlink->resource_list);
79868c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&devlink->param_list);
79878c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&devlink->region_list);
79888c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&devlink->reporter_list);
79898c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&devlink->trap_list);
79908c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&devlink->trap_group_list);
79918c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&devlink->trap_policer_list);
79928c2ecf20Sopenharmony_ci	mutex_init(&devlink->lock);
79938c2ecf20Sopenharmony_ci	mutex_init(&devlink->reporters_lock);
79948c2ecf20Sopenharmony_ci	return devlink;
79958c2ecf20Sopenharmony_ci}
79968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_alloc);
79978c2ecf20Sopenharmony_ci
79988c2ecf20Sopenharmony_ci/**
79998c2ecf20Sopenharmony_ci *	devlink_register - Register devlink instance
80008c2ecf20Sopenharmony_ci *
80018c2ecf20Sopenharmony_ci *	@devlink: devlink
80028c2ecf20Sopenharmony_ci *	@dev: parent device
80038c2ecf20Sopenharmony_ci */
80048c2ecf20Sopenharmony_ciint devlink_register(struct devlink *devlink, struct device *dev)
80058c2ecf20Sopenharmony_ci{
80068c2ecf20Sopenharmony_ci	devlink->dev = dev;
80078c2ecf20Sopenharmony_ci	devlink->registered = true;
80088c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
80098c2ecf20Sopenharmony_ci	list_add_tail(&devlink->list, &devlink_list);
80108c2ecf20Sopenharmony_ci	devlink_notify(devlink, DEVLINK_CMD_NEW);
80118c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
80128c2ecf20Sopenharmony_ci	return 0;
80138c2ecf20Sopenharmony_ci}
80148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_register);
80158c2ecf20Sopenharmony_ci
80168c2ecf20Sopenharmony_ci/**
80178c2ecf20Sopenharmony_ci *	devlink_unregister - Unregister devlink instance
80188c2ecf20Sopenharmony_ci *
80198c2ecf20Sopenharmony_ci *	@devlink: devlink
80208c2ecf20Sopenharmony_ci */
80218c2ecf20Sopenharmony_civoid devlink_unregister(struct devlink *devlink)
80228c2ecf20Sopenharmony_ci{
80238c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
80248c2ecf20Sopenharmony_ci	WARN_ON(devlink_reload_supported(devlink->ops) &&
80258c2ecf20Sopenharmony_ci		devlink->reload_enabled);
80268c2ecf20Sopenharmony_ci	devlink_notify(devlink, DEVLINK_CMD_DEL);
80278c2ecf20Sopenharmony_ci	list_del(&devlink->list);
80288c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
80298c2ecf20Sopenharmony_ci}
80308c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_unregister);
80318c2ecf20Sopenharmony_ci
80328c2ecf20Sopenharmony_ci/**
80338c2ecf20Sopenharmony_ci *	devlink_reload_enable - Enable reload of devlink instance
80348c2ecf20Sopenharmony_ci *
80358c2ecf20Sopenharmony_ci *	@devlink: devlink
80368c2ecf20Sopenharmony_ci *
80378c2ecf20Sopenharmony_ci *	Should be called at end of device initialization
80388c2ecf20Sopenharmony_ci *	process when reload operation is supported.
80398c2ecf20Sopenharmony_ci */
80408c2ecf20Sopenharmony_civoid devlink_reload_enable(struct devlink *devlink)
80418c2ecf20Sopenharmony_ci{
80428c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
80438c2ecf20Sopenharmony_ci	devlink->reload_enabled = true;
80448c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
80458c2ecf20Sopenharmony_ci}
80468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_reload_enable);
80478c2ecf20Sopenharmony_ci
80488c2ecf20Sopenharmony_ci/**
80498c2ecf20Sopenharmony_ci *	devlink_reload_disable - Disable reload of devlink instance
80508c2ecf20Sopenharmony_ci *
80518c2ecf20Sopenharmony_ci *	@devlink: devlink
80528c2ecf20Sopenharmony_ci *
80538c2ecf20Sopenharmony_ci *	Should be called at the beginning of device cleanup
80548c2ecf20Sopenharmony_ci *	process when reload operation is supported.
80558c2ecf20Sopenharmony_ci */
80568c2ecf20Sopenharmony_civoid devlink_reload_disable(struct devlink *devlink)
80578c2ecf20Sopenharmony_ci{
80588c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
80598c2ecf20Sopenharmony_ci	/* Mutex is taken which ensures that no reload operation is in
80608c2ecf20Sopenharmony_ci	 * progress while setting up forbidded flag.
80618c2ecf20Sopenharmony_ci	 */
80628c2ecf20Sopenharmony_ci	devlink->reload_enabled = false;
80638c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
80648c2ecf20Sopenharmony_ci}
80658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_reload_disable);
80668c2ecf20Sopenharmony_ci
80678c2ecf20Sopenharmony_ci/**
80688c2ecf20Sopenharmony_ci *	devlink_free - Free devlink instance resources
80698c2ecf20Sopenharmony_ci *
80708c2ecf20Sopenharmony_ci *	@devlink: devlink
80718c2ecf20Sopenharmony_ci */
80728c2ecf20Sopenharmony_civoid devlink_free(struct devlink *devlink)
80738c2ecf20Sopenharmony_ci{
80748c2ecf20Sopenharmony_ci	mutex_destroy(&devlink->reporters_lock);
80758c2ecf20Sopenharmony_ci	mutex_destroy(&devlink->lock);
80768c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&devlink->trap_policer_list));
80778c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&devlink->trap_group_list));
80788c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&devlink->trap_list));
80798c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&devlink->reporter_list));
80808c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&devlink->region_list));
80818c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&devlink->param_list));
80828c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&devlink->resource_list));
80838c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&devlink->dpipe_table_list));
80848c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&devlink->sb_list));
80858c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&devlink->port_list));
80868c2ecf20Sopenharmony_ci
80878c2ecf20Sopenharmony_ci	xa_destroy(&devlink->snapshot_ids);
80888c2ecf20Sopenharmony_ci
80898c2ecf20Sopenharmony_ci	kfree(devlink);
80908c2ecf20Sopenharmony_ci}
80918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_free);
80928c2ecf20Sopenharmony_ci
80938c2ecf20Sopenharmony_cistatic void devlink_port_type_warn(struct work_struct *work)
80948c2ecf20Sopenharmony_ci{
80958c2ecf20Sopenharmony_ci	struct devlink_port *port = container_of(to_delayed_work(work),
80968c2ecf20Sopenharmony_ci						 struct devlink_port,
80978c2ecf20Sopenharmony_ci						 type_warn_dw);
80988c2ecf20Sopenharmony_ci	dev_warn(port->devlink->dev, "Type was not set for devlink port.");
80998c2ecf20Sopenharmony_ci}
81008c2ecf20Sopenharmony_ci
81018c2ecf20Sopenharmony_cistatic bool devlink_port_type_should_warn(struct devlink_port *devlink_port)
81028c2ecf20Sopenharmony_ci{
81038c2ecf20Sopenharmony_ci	/* Ignore CPU and DSA flavours. */
81048c2ecf20Sopenharmony_ci	return devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_CPU &&
81058c2ecf20Sopenharmony_ci	       devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_DSA &&
81068c2ecf20Sopenharmony_ci	       devlink_port->attrs.flavour != DEVLINK_PORT_FLAVOUR_UNUSED;
81078c2ecf20Sopenharmony_ci}
81088c2ecf20Sopenharmony_ci
81098c2ecf20Sopenharmony_ci#define DEVLINK_PORT_TYPE_WARN_TIMEOUT (HZ * 3600)
81108c2ecf20Sopenharmony_ci
81118c2ecf20Sopenharmony_cistatic void devlink_port_type_warn_schedule(struct devlink_port *devlink_port)
81128c2ecf20Sopenharmony_ci{
81138c2ecf20Sopenharmony_ci	if (!devlink_port_type_should_warn(devlink_port))
81148c2ecf20Sopenharmony_ci		return;
81158c2ecf20Sopenharmony_ci	/* Schedule a work to WARN in case driver does not set port
81168c2ecf20Sopenharmony_ci	 * type within timeout.
81178c2ecf20Sopenharmony_ci	 */
81188c2ecf20Sopenharmony_ci	schedule_delayed_work(&devlink_port->type_warn_dw,
81198c2ecf20Sopenharmony_ci			      DEVLINK_PORT_TYPE_WARN_TIMEOUT);
81208c2ecf20Sopenharmony_ci}
81218c2ecf20Sopenharmony_ci
81228c2ecf20Sopenharmony_cistatic void devlink_port_type_warn_cancel(struct devlink_port *devlink_port)
81238c2ecf20Sopenharmony_ci{
81248c2ecf20Sopenharmony_ci	if (!devlink_port_type_should_warn(devlink_port))
81258c2ecf20Sopenharmony_ci		return;
81268c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&devlink_port->type_warn_dw);
81278c2ecf20Sopenharmony_ci}
81288c2ecf20Sopenharmony_ci
81298c2ecf20Sopenharmony_ci/**
81308c2ecf20Sopenharmony_ci *	devlink_port_register - Register devlink port
81318c2ecf20Sopenharmony_ci *
81328c2ecf20Sopenharmony_ci *	@devlink: devlink
81338c2ecf20Sopenharmony_ci *	@devlink_port: devlink port
81348c2ecf20Sopenharmony_ci *	@port_index: driver-specific numerical identifier of the port
81358c2ecf20Sopenharmony_ci *
81368c2ecf20Sopenharmony_ci *	Register devlink port with provided port index. User can use
81378c2ecf20Sopenharmony_ci *	any indexing, even hw-related one. devlink_port structure
81388c2ecf20Sopenharmony_ci *	is convenient to be embedded inside user driver private structure.
81398c2ecf20Sopenharmony_ci *	Note that the caller should take care of zeroing the devlink_port
81408c2ecf20Sopenharmony_ci *	structure.
81418c2ecf20Sopenharmony_ci */
81428c2ecf20Sopenharmony_ciint devlink_port_register(struct devlink *devlink,
81438c2ecf20Sopenharmony_ci			  struct devlink_port *devlink_port,
81448c2ecf20Sopenharmony_ci			  unsigned int port_index)
81458c2ecf20Sopenharmony_ci{
81468c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
81478c2ecf20Sopenharmony_ci	if (devlink_port_index_exists(devlink, port_index)) {
81488c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->lock);
81498c2ecf20Sopenharmony_ci		return -EEXIST;
81508c2ecf20Sopenharmony_ci	}
81518c2ecf20Sopenharmony_ci	devlink_port->devlink = devlink;
81528c2ecf20Sopenharmony_ci	devlink_port->index = port_index;
81538c2ecf20Sopenharmony_ci	devlink_port->registered = true;
81548c2ecf20Sopenharmony_ci	spin_lock_init(&devlink_port->type_lock);
81558c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&devlink_port->reporter_list);
81568c2ecf20Sopenharmony_ci	mutex_init(&devlink_port->reporters_lock);
81578c2ecf20Sopenharmony_ci	list_add_tail(&devlink_port->list, &devlink->port_list);
81588c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&devlink_port->param_list);
81598c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&devlink_port->region_list);
81608c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
81618c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&devlink_port->type_warn_dw, &devlink_port_type_warn);
81628c2ecf20Sopenharmony_ci	devlink_port_type_warn_schedule(devlink_port);
81638c2ecf20Sopenharmony_ci	devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
81648c2ecf20Sopenharmony_ci	return 0;
81658c2ecf20Sopenharmony_ci}
81668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_register);
81678c2ecf20Sopenharmony_ci
81688c2ecf20Sopenharmony_ci/**
81698c2ecf20Sopenharmony_ci *	devlink_port_unregister - Unregister devlink port
81708c2ecf20Sopenharmony_ci *
81718c2ecf20Sopenharmony_ci *	@devlink_port: devlink port
81728c2ecf20Sopenharmony_ci */
81738c2ecf20Sopenharmony_civoid devlink_port_unregister(struct devlink_port *devlink_port)
81748c2ecf20Sopenharmony_ci{
81758c2ecf20Sopenharmony_ci	struct devlink *devlink = devlink_port->devlink;
81768c2ecf20Sopenharmony_ci
81778c2ecf20Sopenharmony_ci	devlink_port_type_warn_cancel(devlink_port);
81788c2ecf20Sopenharmony_ci	devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_DEL);
81798c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
81808c2ecf20Sopenharmony_ci	list_del(&devlink_port->list);
81818c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
81828c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&devlink_port->reporter_list));
81838c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&devlink_port->region_list));
81848c2ecf20Sopenharmony_ci	mutex_destroy(&devlink_port->reporters_lock);
81858c2ecf20Sopenharmony_ci}
81868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_unregister);
81878c2ecf20Sopenharmony_ci
81888c2ecf20Sopenharmony_cistatic void __devlink_port_type_set(struct devlink_port *devlink_port,
81898c2ecf20Sopenharmony_ci				    enum devlink_port_type type,
81908c2ecf20Sopenharmony_ci				    void *type_dev)
81918c2ecf20Sopenharmony_ci{
81928c2ecf20Sopenharmony_ci	if (WARN_ON(!devlink_port->registered))
81938c2ecf20Sopenharmony_ci		return;
81948c2ecf20Sopenharmony_ci	devlink_port_type_warn_cancel(devlink_port);
81958c2ecf20Sopenharmony_ci	spin_lock_bh(&devlink_port->type_lock);
81968c2ecf20Sopenharmony_ci	devlink_port->type = type;
81978c2ecf20Sopenharmony_ci	devlink_port->type_dev = type_dev;
81988c2ecf20Sopenharmony_ci	spin_unlock_bh(&devlink_port->type_lock);
81998c2ecf20Sopenharmony_ci	devlink_port_notify(devlink_port, DEVLINK_CMD_PORT_NEW);
82008c2ecf20Sopenharmony_ci}
82018c2ecf20Sopenharmony_ci
82028c2ecf20Sopenharmony_cistatic void devlink_port_type_netdev_checks(struct devlink_port *devlink_port,
82038c2ecf20Sopenharmony_ci					    struct net_device *netdev)
82048c2ecf20Sopenharmony_ci{
82058c2ecf20Sopenharmony_ci	const struct net_device_ops *ops = netdev->netdev_ops;
82068c2ecf20Sopenharmony_ci
82078c2ecf20Sopenharmony_ci	/* If driver registers devlink port, it should set devlink port
82088c2ecf20Sopenharmony_ci	 * attributes accordingly so the compat functions are called
82098c2ecf20Sopenharmony_ci	 * and the original ops are not used.
82108c2ecf20Sopenharmony_ci	 */
82118c2ecf20Sopenharmony_ci	if (ops->ndo_get_phys_port_name) {
82128c2ecf20Sopenharmony_ci		/* Some drivers use the same set of ndos for netdevs
82138c2ecf20Sopenharmony_ci		 * that have devlink_port registered and also for
82148c2ecf20Sopenharmony_ci		 * those who don't. Make sure that ndo_get_phys_port_name
82158c2ecf20Sopenharmony_ci		 * returns -EOPNOTSUPP here in case it is defined.
82168c2ecf20Sopenharmony_ci		 * Warn if not.
82178c2ecf20Sopenharmony_ci		 */
82188c2ecf20Sopenharmony_ci		char name[IFNAMSIZ];
82198c2ecf20Sopenharmony_ci		int err;
82208c2ecf20Sopenharmony_ci
82218c2ecf20Sopenharmony_ci		err = ops->ndo_get_phys_port_name(netdev, name, sizeof(name));
82228c2ecf20Sopenharmony_ci		WARN_ON(err != -EOPNOTSUPP);
82238c2ecf20Sopenharmony_ci	}
82248c2ecf20Sopenharmony_ci	if (ops->ndo_get_port_parent_id) {
82258c2ecf20Sopenharmony_ci		/* Some drivers use the same set of ndos for netdevs
82268c2ecf20Sopenharmony_ci		 * that have devlink_port registered and also for
82278c2ecf20Sopenharmony_ci		 * those who don't. Make sure that ndo_get_port_parent_id
82288c2ecf20Sopenharmony_ci		 * returns -EOPNOTSUPP here in case it is defined.
82298c2ecf20Sopenharmony_ci		 * Warn if not.
82308c2ecf20Sopenharmony_ci		 */
82318c2ecf20Sopenharmony_ci		struct netdev_phys_item_id ppid;
82328c2ecf20Sopenharmony_ci		int err;
82338c2ecf20Sopenharmony_ci
82348c2ecf20Sopenharmony_ci		err = ops->ndo_get_port_parent_id(netdev, &ppid);
82358c2ecf20Sopenharmony_ci		WARN_ON(err != -EOPNOTSUPP);
82368c2ecf20Sopenharmony_ci	}
82378c2ecf20Sopenharmony_ci}
82388c2ecf20Sopenharmony_ci
82398c2ecf20Sopenharmony_ci/**
82408c2ecf20Sopenharmony_ci *	devlink_port_type_eth_set - Set port type to Ethernet
82418c2ecf20Sopenharmony_ci *
82428c2ecf20Sopenharmony_ci *	@devlink_port: devlink port
82438c2ecf20Sopenharmony_ci *	@netdev: related netdevice
82448c2ecf20Sopenharmony_ci */
82458c2ecf20Sopenharmony_civoid devlink_port_type_eth_set(struct devlink_port *devlink_port,
82468c2ecf20Sopenharmony_ci			       struct net_device *netdev)
82478c2ecf20Sopenharmony_ci{
82488c2ecf20Sopenharmony_ci	if (netdev)
82498c2ecf20Sopenharmony_ci		devlink_port_type_netdev_checks(devlink_port, netdev);
82508c2ecf20Sopenharmony_ci	else
82518c2ecf20Sopenharmony_ci		dev_warn(devlink_port->devlink->dev,
82528c2ecf20Sopenharmony_ci			 "devlink port type for port %d set to Ethernet without a software interface reference, device type not supported by the kernel?\n",
82538c2ecf20Sopenharmony_ci			 devlink_port->index);
82548c2ecf20Sopenharmony_ci
82558c2ecf20Sopenharmony_ci	__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_ETH, netdev);
82568c2ecf20Sopenharmony_ci}
82578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_type_eth_set);
82588c2ecf20Sopenharmony_ci
82598c2ecf20Sopenharmony_ci/**
82608c2ecf20Sopenharmony_ci *	devlink_port_type_ib_set - Set port type to InfiniBand
82618c2ecf20Sopenharmony_ci *
82628c2ecf20Sopenharmony_ci *	@devlink_port: devlink port
82638c2ecf20Sopenharmony_ci *	@ibdev: related IB device
82648c2ecf20Sopenharmony_ci */
82658c2ecf20Sopenharmony_civoid devlink_port_type_ib_set(struct devlink_port *devlink_port,
82668c2ecf20Sopenharmony_ci			      struct ib_device *ibdev)
82678c2ecf20Sopenharmony_ci{
82688c2ecf20Sopenharmony_ci	__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_IB, ibdev);
82698c2ecf20Sopenharmony_ci}
82708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_type_ib_set);
82718c2ecf20Sopenharmony_ci
82728c2ecf20Sopenharmony_ci/**
82738c2ecf20Sopenharmony_ci *	devlink_port_type_clear - Clear port type
82748c2ecf20Sopenharmony_ci *
82758c2ecf20Sopenharmony_ci *	@devlink_port: devlink port
82768c2ecf20Sopenharmony_ci */
82778c2ecf20Sopenharmony_civoid devlink_port_type_clear(struct devlink_port *devlink_port)
82788c2ecf20Sopenharmony_ci{
82798c2ecf20Sopenharmony_ci	__devlink_port_type_set(devlink_port, DEVLINK_PORT_TYPE_NOTSET, NULL);
82808c2ecf20Sopenharmony_ci	devlink_port_type_warn_schedule(devlink_port);
82818c2ecf20Sopenharmony_ci}
82828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_type_clear);
82838c2ecf20Sopenharmony_ci
82848c2ecf20Sopenharmony_cistatic int __devlink_port_attrs_set(struct devlink_port *devlink_port,
82858c2ecf20Sopenharmony_ci				    enum devlink_port_flavour flavour)
82868c2ecf20Sopenharmony_ci{
82878c2ecf20Sopenharmony_ci	struct devlink_port_attrs *attrs = &devlink_port->attrs;
82888c2ecf20Sopenharmony_ci
82898c2ecf20Sopenharmony_ci	devlink_port->attrs_set = true;
82908c2ecf20Sopenharmony_ci	attrs->flavour = flavour;
82918c2ecf20Sopenharmony_ci	if (attrs->switch_id.id_len) {
82928c2ecf20Sopenharmony_ci		devlink_port->switch_port = true;
82938c2ecf20Sopenharmony_ci		if (WARN_ON(attrs->switch_id.id_len > MAX_PHYS_ITEM_ID_LEN))
82948c2ecf20Sopenharmony_ci			attrs->switch_id.id_len = MAX_PHYS_ITEM_ID_LEN;
82958c2ecf20Sopenharmony_ci	} else {
82968c2ecf20Sopenharmony_ci		devlink_port->switch_port = false;
82978c2ecf20Sopenharmony_ci	}
82988c2ecf20Sopenharmony_ci	return 0;
82998c2ecf20Sopenharmony_ci}
83008c2ecf20Sopenharmony_ci
83018c2ecf20Sopenharmony_ci/**
83028c2ecf20Sopenharmony_ci *	devlink_port_attrs_set - Set port attributes
83038c2ecf20Sopenharmony_ci *
83048c2ecf20Sopenharmony_ci *	@devlink_port: devlink port
83058c2ecf20Sopenharmony_ci *	@attrs: devlink port attrs
83068c2ecf20Sopenharmony_ci */
83078c2ecf20Sopenharmony_civoid devlink_port_attrs_set(struct devlink_port *devlink_port,
83088c2ecf20Sopenharmony_ci			    struct devlink_port_attrs *attrs)
83098c2ecf20Sopenharmony_ci{
83108c2ecf20Sopenharmony_ci	int ret;
83118c2ecf20Sopenharmony_ci
83128c2ecf20Sopenharmony_ci	if (WARN_ON(devlink_port->registered))
83138c2ecf20Sopenharmony_ci		return;
83148c2ecf20Sopenharmony_ci	devlink_port->attrs = *attrs;
83158c2ecf20Sopenharmony_ci	ret = __devlink_port_attrs_set(devlink_port, attrs->flavour);
83168c2ecf20Sopenharmony_ci	if (ret)
83178c2ecf20Sopenharmony_ci		return;
83188c2ecf20Sopenharmony_ci	WARN_ON(attrs->splittable && attrs->split);
83198c2ecf20Sopenharmony_ci}
83208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_attrs_set);
83218c2ecf20Sopenharmony_ci
83228c2ecf20Sopenharmony_ci/**
83238c2ecf20Sopenharmony_ci *	devlink_port_attrs_pci_pf_set - Set PCI PF port attributes
83248c2ecf20Sopenharmony_ci *
83258c2ecf20Sopenharmony_ci *	@devlink_port: devlink port
83268c2ecf20Sopenharmony_ci *	@controller: associated controller number for the devlink port instance
83278c2ecf20Sopenharmony_ci *	@pf: associated PF for the devlink port instance
83288c2ecf20Sopenharmony_ci *	@external: indicates if the port is for an external controller
83298c2ecf20Sopenharmony_ci */
83308c2ecf20Sopenharmony_civoid devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 controller,
83318c2ecf20Sopenharmony_ci				   u16 pf, bool external)
83328c2ecf20Sopenharmony_ci{
83338c2ecf20Sopenharmony_ci	struct devlink_port_attrs *attrs = &devlink_port->attrs;
83348c2ecf20Sopenharmony_ci	int ret;
83358c2ecf20Sopenharmony_ci
83368c2ecf20Sopenharmony_ci	if (WARN_ON(devlink_port->registered))
83378c2ecf20Sopenharmony_ci		return;
83388c2ecf20Sopenharmony_ci	ret = __devlink_port_attrs_set(devlink_port,
83398c2ecf20Sopenharmony_ci				       DEVLINK_PORT_FLAVOUR_PCI_PF);
83408c2ecf20Sopenharmony_ci	if (ret)
83418c2ecf20Sopenharmony_ci		return;
83428c2ecf20Sopenharmony_ci	attrs->pci_pf.controller = controller;
83438c2ecf20Sopenharmony_ci	attrs->pci_pf.pf = pf;
83448c2ecf20Sopenharmony_ci	attrs->pci_pf.external = external;
83458c2ecf20Sopenharmony_ci}
83468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_attrs_pci_pf_set);
83478c2ecf20Sopenharmony_ci
83488c2ecf20Sopenharmony_ci/**
83498c2ecf20Sopenharmony_ci *	devlink_port_attrs_pci_vf_set - Set PCI VF port attributes
83508c2ecf20Sopenharmony_ci *
83518c2ecf20Sopenharmony_ci *	@devlink_port: devlink port
83528c2ecf20Sopenharmony_ci *	@controller: associated controller number for the devlink port instance
83538c2ecf20Sopenharmony_ci *	@pf: associated PF for the devlink port instance
83548c2ecf20Sopenharmony_ci *	@vf: associated VF of a PF for the devlink port instance
83558c2ecf20Sopenharmony_ci *	@external: indicates if the port is for an external controller
83568c2ecf20Sopenharmony_ci */
83578c2ecf20Sopenharmony_civoid devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 controller,
83588c2ecf20Sopenharmony_ci				   u16 pf, u16 vf, bool external)
83598c2ecf20Sopenharmony_ci{
83608c2ecf20Sopenharmony_ci	struct devlink_port_attrs *attrs = &devlink_port->attrs;
83618c2ecf20Sopenharmony_ci	int ret;
83628c2ecf20Sopenharmony_ci
83638c2ecf20Sopenharmony_ci	if (WARN_ON(devlink_port->registered))
83648c2ecf20Sopenharmony_ci		return;
83658c2ecf20Sopenharmony_ci	ret = __devlink_port_attrs_set(devlink_port,
83668c2ecf20Sopenharmony_ci				       DEVLINK_PORT_FLAVOUR_PCI_VF);
83678c2ecf20Sopenharmony_ci	if (ret)
83688c2ecf20Sopenharmony_ci		return;
83698c2ecf20Sopenharmony_ci	attrs->pci_vf.controller = controller;
83708c2ecf20Sopenharmony_ci	attrs->pci_vf.pf = pf;
83718c2ecf20Sopenharmony_ci	attrs->pci_vf.vf = vf;
83728c2ecf20Sopenharmony_ci	attrs->pci_vf.external = external;
83738c2ecf20Sopenharmony_ci}
83748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set);
83758c2ecf20Sopenharmony_ci
83768c2ecf20Sopenharmony_cistatic int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port,
83778c2ecf20Sopenharmony_ci					     char *name, size_t len)
83788c2ecf20Sopenharmony_ci{
83798c2ecf20Sopenharmony_ci	struct devlink_port_attrs *attrs = &devlink_port->attrs;
83808c2ecf20Sopenharmony_ci	int n = 0;
83818c2ecf20Sopenharmony_ci
83828c2ecf20Sopenharmony_ci	if (!devlink_port->attrs_set)
83838c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
83848c2ecf20Sopenharmony_ci
83858c2ecf20Sopenharmony_ci	switch (attrs->flavour) {
83868c2ecf20Sopenharmony_ci	case DEVLINK_PORT_FLAVOUR_PHYSICAL:
83878c2ecf20Sopenharmony_ci		if (!attrs->split)
83888c2ecf20Sopenharmony_ci			n = snprintf(name, len, "p%u", attrs->phys.port_number);
83898c2ecf20Sopenharmony_ci		else
83908c2ecf20Sopenharmony_ci			n = snprintf(name, len, "p%us%u",
83918c2ecf20Sopenharmony_ci				     attrs->phys.port_number,
83928c2ecf20Sopenharmony_ci				     attrs->phys.split_subport_number);
83938c2ecf20Sopenharmony_ci		break;
83948c2ecf20Sopenharmony_ci	case DEVLINK_PORT_FLAVOUR_CPU:
83958c2ecf20Sopenharmony_ci	case DEVLINK_PORT_FLAVOUR_DSA:
83968c2ecf20Sopenharmony_ci	case DEVLINK_PORT_FLAVOUR_UNUSED:
83978c2ecf20Sopenharmony_ci		/* As CPU and DSA ports do not have a netdevice associated
83988c2ecf20Sopenharmony_ci		 * case should not ever happen.
83998c2ecf20Sopenharmony_ci		 */
84008c2ecf20Sopenharmony_ci		WARN_ON(1);
84018c2ecf20Sopenharmony_ci		return -EINVAL;
84028c2ecf20Sopenharmony_ci	case DEVLINK_PORT_FLAVOUR_PCI_PF:
84038c2ecf20Sopenharmony_ci		if (attrs->pci_pf.external) {
84048c2ecf20Sopenharmony_ci			n = snprintf(name, len, "c%u", attrs->pci_pf.controller);
84058c2ecf20Sopenharmony_ci			if (n >= len)
84068c2ecf20Sopenharmony_ci				return -EINVAL;
84078c2ecf20Sopenharmony_ci			len -= n;
84088c2ecf20Sopenharmony_ci			name += n;
84098c2ecf20Sopenharmony_ci		}
84108c2ecf20Sopenharmony_ci		n = snprintf(name, len, "pf%u", attrs->pci_pf.pf);
84118c2ecf20Sopenharmony_ci		break;
84128c2ecf20Sopenharmony_ci	case DEVLINK_PORT_FLAVOUR_PCI_VF:
84138c2ecf20Sopenharmony_ci		if (attrs->pci_vf.external) {
84148c2ecf20Sopenharmony_ci			n = snprintf(name, len, "c%u", attrs->pci_vf.controller);
84158c2ecf20Sopenharmony_ci			if (n >= len)
84168c2ecf20Sopenharmony_ci				return -EINVAL;
84178c2ecf20Sopenharmony_ci			len -= n;
84188c2ecf20Sopenharmony_ci			name += n;
84198c2ecf20Sopenharmony_ci		}
84208c2ecf20Sopenharmony_ci		n = snprintf(name, len, "pf%uvf%u",
84218c2ecf20Sopenharmony_ci			     attrs->pci_vf.pf, attrs->pci_vf.vf);
84228c2ecf20Sopenharmony_ci		break;
84238c2ecf20Sopenharmony_ci	case DEVLINK_PORT_FLAVOUR_VIRTUAL:
84248c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
84258c2ecf20Sopenharmony_ci	}
84268c2ecf20Sopenharmony_ci
84278c2ecf20Sopenharmony_ci	if (n >= len)
84288c2ecf20Sopenharmony_ci		return -EINVAL;
84298c2ecf20Sopenharmony_ci
84308c2ecf20Sopenharmony_ci	return 0;
84318c2ecf20Sopenharmony_ci}
84328c2ecf20Sopenharmony_ci
84338c2ecf20Sopenharmony_ciint devlink_sb_register(struct devlink *devlink, unsigned int sb_index,
84348c2ecf20Sopenharmony_ci			u32 size, u16 ingress_pools_count,
84358c2ecf20Sopenharmony_ci			u16 egress_pools_count, u16 ingress_tc_count,
84368c2ecf20Sopenharmony_ci			u16 egress_tc_count)
84378c2ecf20Sopenharmony_ci{
84388c2ecf20Sopenharmony_ci	struct devlink_sb *devlink_sb;
84398c2ecf20Sopenharmony_ci	int err = 0;
84408c2ecf20Sopenharmony_ci
84418c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
84428c2ecf20Sopenharmony_ci	if (devlink_sb_index_exists(devlink, sb_index)) {
84438c2ecf20Sopenharmony_ci		err = -EEXIST;
84448c2ecf20Sopenharmony_ci		goto unlock;
84458c2ecf20Sopenharmony_ci	}
84468c2ecf20Sopenharmony_ci
84478c2ecf20Sopenharmony_ci	devlink_sb = kzalloc(sizeof(*devlink_sb), GFP_KERNEL);
84488c2ecf20Sopenharmony_ci	if (!devlink_sb) {
84498c2ecf20Sopenharmony_ci		err = -ENOMEM;
84508c2ecf20Sopenharmony_ci		goto unlock;
84518c2ecf20Sopenharmony_ci	}
84528c2ecf20Sopenharmony_ci	devlink_sb->index = sb_index;
84538c2ecf20Sopenharmony_ci	devlink_sb->size = size;
84548c2ecf20Sopenharmony_ci	devlink_sb->ingress_pools_count = ingress_pools_count;
84558c2ecf20Sopenharmony_ci	devlink_sb->egress_pools_count = egress_pools_count;
84568c2ecf20Sopenharmony_ci	devlink_sb->ingress_tc_count = ingress_tc_count;
84578c2ecf20Sopenharmony_ci	devlink_sb->egress_tc_count = egress_tc_count;
84588c2ecf20Sopenharmony_ci	list_add_tail(&devlink_sb->list, &devlink->sb_list);
84598c2ecf20Sopenharmony_ciunlock:
84608c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
84618c2ecf20Sopenharmony_ci	return err;
84628c2ecf20Sopenharmony_ci}
84638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_sb_register);
84648c2ecf20Sopenharmony_ci
84658c2ecf20Sopenharmony_civoid devlink_sb_unregister(struct devlink *devlink, unsigned int sb_index)
84668c2ecf20Sopenharmony_ci{
84678c2ecf20Sopenharmony_ci	struct devlink_sb *devlink_sb;
84688c2ecf20Sopenharmony_ci
84698c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
84708c2ecf20Sopenharmony_ci	devlink_sb = devlink_sb_get_by_index(devlink, sb_index);
84718c2ecf20Sopenharmony_ci	WARN_ON(!devlink_sb);
84728c2ecf20Sopenharmony_ci	list_del(&devlink_sb->list);
84738c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
84748c2ecf20Sopenharmony_ci	kfree(devlink_sb);
84758c2ecf20Sopenharmony_ci}
84768c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_sb_unregister);
84778c2ecf20Sopenharmony_ci
84788c2ecf20Sopenharmony_ci/**
84798c2ecf20Sopenharmony_ci *	devlink_dpipe_headers_register - register dpipe headers
84808c2ecf20Sopenharmony_ci *
84818c2ecf20Sopenharmony_ci *	@devlink: devlink
84828c2ecf20Sopenharmony_ci *	@dpipe_headers: dpipe header array
84838c2ecf20Sopenharmony_ci *
84848c2ecf20Sopenharmony_ci *	Register the headers supported by hardware.
84858c2ecf20Sopenharmony_ci */
84868c2ecf20Sopenharmony_ciint devlink_dpipe_headers_register(struct devlink *devlink,
84878c2ecf20Sopenharmony_ci				   struct devlink_dpipe_headers *dpipe_headers)
84888c2ecf20Sopenharmony_ci{
84898c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
84908c2ecf20Sopenharmony_ci	devlink->dpipe_headers = dpipe_headers;
84918c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
84928c2ecf20Sopenharmony_ci	return 0;
84938c2ecf20Sopenharmony_ci}
84948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_headers_register);
84958c2ecf20Sopenharmony_ci
84968c2ecf20Sopenharmony_ci/**
84978c2ecf20Sopenharmony_ci *	devlink_dpipe_headers_unregister - unregister dpipe headers
84988c2ecf20Sopenharmony_ci *
84998c2ecf20Sopenharmony_ci *	@devlink: devlink
85008c2ecf20Sopenharmony_ci *
85018c2ecf20Sopenharmony_ci *	Unregister the headers supported by hardware.
85028c2ecf20Sopenharmony_ci */
85038c2ecf20Sopenharmony_civoid devlink_dpipe_headers_unregister(struct devlink *devlink)
85048c2ecf20Sopenharmony_ci{
85058c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
85068c2ecf20Sopenharmony_ci	devlink->dpipe_headers = NULL;
85078c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
85088c2ecf20Sopenharmony_ci}
85098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_headers_unregister);
85108c2ecf20Sopenharmony_ci
85118c2ecf20Sopenharmony_ci/**
85128c2ecf20Sopenharmony_ci *	devlink_dpipe_table_counter_enabled - check if counter allocation
85138c2ecf20Sopenharmony_ci *					      required
85148c2ecf20Sopenharmony_ci *	@devlink: devlink
85158c2ecf20Sopenharmony_ci *	@table_name: tables name
85168c2ecf20Sopenharmony_ci *
85178c2ecf20Sopenharmony_ci *	Used by driver to check if counter allocation is required.
85188c2ecf20Sopenharmony_ci *	After counter allocation is turned on the table entries
85198c2ecf20Sopenharmony_ci *	are updated to include counter statistics.
85208c2ecf20Sopenharmony_ci *
85218c2ecf20Sopenharmony_ci *	After that point on the driver must respect the counter
85228c2ecf20Sopenharmony_ci *	state so that each entry added to the table is added
85238c2ecf20Sopenharmony_ci *	with a counter.
85248c2ecf20Sopenharmony_ci */
85258c2ecf20Sopenharmony_cibool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
85268c2ecf20Sopenharmony_ci					 const char *table_name)
85278c2ecf20Sopenharmony_ci{
85288c2ecf20Sopenharmony_ci	struct devlink_dpipe_table *table;
85298c2ecf20Sopenharmony_ci	bool enabled;
85308c2ecf20Sopenharmony_ci
85318c2ecf20Sopenharmony_ci	rcu_read_lock();
85328c2ecf20Sopenharmony_ci	table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
85338c2ecf20Sopenharmony_ci					 table_name, devlink);
85348c2ecf20Sopenharmony_ci	enabled = false;
85358c2ecf20Sopenharmony_ci	if (table)
85368c2ecf20Sopenharmony_ci		enabled = table->counters_enabled;
85378c2ecf20Sopenharmony_ci	rcu_read_unlock();
85388c2ecf20Sopenharmony_ci	return enabled;
85398c2ecf20Sopenharmony_ci}
85408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
85418c2ecf20Sopenharmony_ci
85428c2ecf20Sopenharmony_ci/**
85438c2ecf20Sopenharmony_ci *	devlink_dpipe_table_register - register dpipe table
85448c2ecf20Sopenharmony_ci *
85458c2ecf20Sopenharmony_ci *	@devlink: devlink
85468c2ecf20Sopenharmony_ci *	@table_name: table name
85478c2ecf20Sopenharmony_ci *	@table_ops: table ops
85488c2ecf20Sopenharmony_ci *	@priv: priv
85498c2ecf20Sopenharmony_ci *	@counter_control_extern: external control for counters
85508c2ecf20Sopenharmony_ci */
85518c2ecf20Sopenharmony_ciint devlink_dpipe_table_register(struct devlink *devlink,
85528c2ecf20Sopenharmony_ci				 const char *table_name,
85538c2ecf20Sopenharmony_ci				 struct devlink_dpipe_table_ops *table_ops,
85548c2ecf20Sopenharmony_ci				 void *priv, bool counter_control_extern)
85558c2ecf20Sopenharmony_ci{
85568c2ecf20Sopenharmony_ci	struct devlink_dpipe_table *table;
85578c2ecf20Sopenharmony_ci	int err = 0;
85588c2ecf20Sopenharmony_ci
85598c2ecf20Sopenharmony_ci	if (WARN_ON(!table_ops->size_get))
85608c2ecf20Sopenharmony_ci		return -EINVAL;
85618c2ecf20Sopenharmony_ci
85628c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
85638c2ecf20Sopenharmony_ci
85648c2ecf20Sopenharmony_ci	if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name,
85658c2ecf20Sopenharmony_ci				     devlink)) {
85668c2ecf20Sopenharmony_ci		err = -EEXIST;
85678c2ecf20Sopenharmony_ci		goto unlock;
85688c2ecf20Sopenharmony_ci	}
85698c2ecf20Sopenharmony_ci
85708c2ecf20Sopenharmony_ci	table = kzalloc(sizeof(*table), GFP_KERNEL);
85718c2ecf20Sopenharmony_ci	if (!table) {
85728c2ecf20Sopenharmony_ci		err = -ENOMEM;
85738c2ecf20Sopenharmony_ci		goto unlock;
85748c2ecf20Sopenharmony_ci	}
85758c2ecf20Sopenharmony_ci
85768c2ecf20Sopenharmony_ci	table->name = table_name;
85778c2ecf20Sopenharmony_ci	table->table_ops = table_ops;
85788c2ecf20Sopenharmony_ci	table->priv = priv;
85798c2ecf20Sopenharmony_ci	table->counter_control_extern = counter_control_extern;
85808c2ecf20Sopenharmony_ci
85818c2ecf20Sopenharmony_ci	list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
85828c2ecf20Sopenharmony_ciunlock:
85838c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
85848c2ecf20Sopenharmony_ci	return err;
85858c2ecf20Sopenharmony_ci}
85868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_table_register);
85878c2ecf20Sopenharmony_ci
85888c2ecf20Sopenharmony_ci/**
85898c2ecf20Sopenharmony_ci *	devlink_dpipe_table_unregister - unregister dpipe table
85908c2ecf20Sopenharmony_ci *
85918c2ecf20Sopenharmony_ci *	@devlink: devlink
85928c2ecf20Sopenharmony_ci *	@table_name: table name
85938c2ecf20Sopenharmony_ci */
85948c2ecf20Sopenharmony_civoid devlink_dpipe_table_unregister(struct devlink *devlink,
85958c2ecf20Sopenharmony_ci				    const char *table_name)
85968c2ecf20Sopenharmony_ci{
85978c2ecf20Sopenharmony_ci	struct devlink_dpipe_table *table;
85988c2ecf20Sopenharmony_ci
85998c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
86008c2ecf20Sopenharmony_ci	table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
86018c2ecf20Sopenharmony_ci					 table_name, devlink);
86028c2ecf20Sopenharmony_ci	if (!table)
86038c2ecf20Sopenharmony_ci		goto unlock;
86048c2ecf20Sopenharmony_ci	list_del_rcu(&table->list);
86058c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
86068c2ecf20Sopenharmony_ci	kfree_rcu(table, rcu);
86078c2ecf20Sopenharmony_ci	return;
86088c2ecf20Sopenharmony_ciunlock:
86098c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
86108c2ecf20Sopenharmony_ci}
86118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_table_unregister);
86128c2ecf20Sopenharmony_ci
86138c2ecf20Sopenharmony_ci/**
86148c2ecf20Sopenharmony_ci *	devlink_resource_register - devlink resource register
86158c2ecf20Sopenharmony_ci *
86168c2ecf20Sopenharmony_ci *	@devlink: devlink
86178c2ecf20Sopenharmony_ci *	@resource_name: resource's name
86188c2ecf20Sopenharmony_ci *	@resource_size: resource's size
86198c2ecf20Sopenharmony_ci *	@resource_id: resource's id
86208c2ecf20Sopenharmony_ci *	@parent_resource_id: resource's parent id
86218c2ecf20Sopenharmony_ci *	@size_params: size parameters
86228c2ecf20Sopenharmony_ci */
86238c2ecf20Sopenharmony_ciint devlink_resource_register(struct devlink *devlink,
86248c2ecf20Sopenharmony_ci			      const char *resource_name,
86258c2ecf20Sopenharmony_ci			      u64 resource_size,
86268c2ecf20Sopenharmony_ci			      u64 resource_id,
86278c2ecf20Sopenharmony_ci			      u64 parent_resource_id,
86288c2ecf20Sopenharmony_ci			      const struct devlink_resource_size_params *size_params)
86298c2ecf20Sopenharmony_ci{
86308c2ecf20Sopenharmony_ci	struct devlink_resource *resource;
86318c2ecf20Sopenharmony_ci	struct list_head *resource_list;
86328c2ecf20Sopenharmony_ci	bool top_hierarchy;
86338c2ecf20Sopenharmony_ci	int err = 0;
86348c2ecf20Sopenharmony_ci
86358c2ecf20Sopenharmony_ci	top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
86368c2ecf20Sopenharmony_ci
86378c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
86388c2ecf20Sopenharmony_ci	resource = devlink_resource_find(devlink, NULL, resource_id);
86398c2ecf20Sopenharmony_ci	if (resource) {
86408c2ecf20Sopenharmony_ci		err = -EINVAL;
86418c2ecf20Sopenharmony_ci		goto out;
86428c2ecf20Sopenharmony_ci	}
86438c2ecf20Sopenharmony_ci
86448c2ecf20Sopenharmony_ci	resource = kzalloc(sizeof(*resource), GFP_KERNEL);
86458c2ecf20Sopenharmony_ci	if (!resource) {
86468c2ecf20Sopenharmony_ci		err = -ENOMEM;
86478c2ecf20Sopenharmony_ci		goto out;
86488c2ecf20Sopenharmony_ci	}
86498c2ecf20Sopenharmony_ci
86508c2ecf20Sopenharmony_ci	if (top_hierarchy) {
86518c2ecf20Sopenharmony_ci		resource_list = &devlink->resource_list;
86528c2ecf20Sopenharmony_ci	} else {
86538c2ecf20Sopenharmony_ci		struct devlink_resource *parent_resource;
86548c2ecf20Sopenharmony_ci
86558c2ecf20Sopenharmony_ci		parent_resource = devlink_resource_find(devlink, NULL,
86568c2ecf20Sopenharmony_ci							parent_resource_id);
86578c2ecf20Sopenharmony_ci		if (parent_resource) {
86588c2ecf20Sopenharmony_ci			resource_list = &parent_resource->resource_list;
86598c2ecf20Sopenharmony_ci			resource->parent = parent_resource;
86608c2ecf20Sopenharmony_ci		} else {
86618c2ecf20Sopenharmony_ci			kfree(resource);
86628c2ecf20Sopenharmony_ci			err = -EINVAL;
86638c2ecf20Sopenharmony_ci			goto out;
86648c2ecf20Sopenharmony_ci		}
86658c2ecf20Sopenharmony_ci	}
86668c2ecf20Sopenharmony_ci
86678c2ecf20Sopenharmony_ci	resource->name = resource_name;
86688c2ecf20Sopenharmony_ci	resource->size = resource_size;
86698c2ecf20Sopenharmony_ci	resource->size_new = resource_size;
86708c2ecf20Sopenharmony_ci	resource->id = resource_id;
86718c2ecf20Sopenharmony_ci	resource->size_valid = true;
86728c2ecf20Sopenharmony_ci	memcpy(&resource->size_params, size_params,
86738c2ecf20Sopenharmony_ci	       sizeof(resource->size_params));
86748c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&resource->resource_list);
86758c2ecf20Sopenharmony_ci	list_add_tail(&resource->list, resource_list);
86768c2ecf20Sopenharmony_ciout:
86778c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
86788c2ecf20Sopenharmony_ci	return err;
86798c2ecf20Sopenharmony_ci}
86808c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_resource_register);
86818c2ecf20Sopenharmony_ci
86828c2ecf20Sopenharmony_ci/**
86838c2ecf20Sopenharmony_ci *	devlink_resources_unregister - free all resources
86848c2ecf20Sopenharmony_ci *
86858c2ecf20Sopenharmony_ci *	@devlink: devlink
86868c2ecf20Sopenharmony_ci *	@resource: resource
86878c2ecf20Sopenharmony_ci */
86888c2ecf20Sopenharmony_civoid devlink_resources_unregister(struct devlink *devlink,
86898c2ecf20Sopenharmony_ci				  struct devlink_resource *resource)
86908c2ecf20Sopenharmony_ci{
86918c2ecf20Sopenharmony_ci	struct devlink_resource *tmp, *child_resource;
86928c2ecf20Sopenharmony_ci	struct list_head *resource_list;
86938c2ecf20Sopenharmony_ci
86948c2ecf20Sopenharmony_ci	if (resource)
86958c2ecf20Sopenharmony_ci		resource_list = &resource->resource_list;
86968c2ecf20Sopenharmony_ci	else
86978c2ecf20Sopenharmony_ci		resource_list = &devlink->resource_list;
86988c2ecf20Sopenharmony_ci
86998c2ecf20Sopenharmony_ci	if (!resource)
87008c2ecf20Sopenharmony_ci		mutex_lock(&devlink->lock);
87018c2ecf20Sopenharmony_ci
87028c2ecf20Sopenharmony_ci	list_for_each_entry_safe(child_resource, tmp, resource_list, list) {
87038c2ecf20Sopenharmony_ci		devlink_resources_unregister(devlink, child_resource);
87048c2ecf20Sopenharmony_ci		list_del(&child_resource->list);
87058c2ecf20Sopenharmony_ci		kfree(child_resource);
87068c2ecf20Sopenharmony_ci	}
87078c2ecf20Sopenharmony_ci
87088c2ecf20Sopenharmony_ci	if (!resource)
87098c2ecf20Sopenharmony_ci		mutex_unlock(&devlink->lock);
87108c2ecf20Sopenharmony_ci}
87118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_resources_unregister);
87128c2ecf20Sopenharmony_ci
87138c2ecf20Sopenharmony_ci/**
87148c2ecf20Sopenharmony_ci *	devlink_resource_size_get - get and update size
87158c2ecf20Sopenharmony_ci *
87168c2ecf20Sopenharmony_ci *	@devlink: devlink
87178c2ecf20Sopenharmony_ci *	@resource_id: the requested resource id
87188c2ecf20Sopenharmony_ci *	@p_resource_size: ptr to update
87198c2ecf20Sopenharmony_ci */
87208c2ecf20Sopenharmony_ciint devlink_resource_size_get(struct devlink *devlink,
87218c2ecf20Sopenharmony_ci			      u64 resource_id,
87228c2ecf20Sopenharmony_ci			      u64 *p_resource_size)
87238c2ecf20Sopenharmony_ci{
87248c2ecf20Sopenharmony_ci	struct devlink_resource *resource;
87258c2ecf20Sopenharmony_ci	int err = 0;
87268c2ecf20Sopenharmony_ci
87278c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
87288c2ecf20Sopenharmony_ci	resource = devlink_resource_find(devlink, NULL, resource_id);
87298c2ecf20Sopenharmony_ci	if (!resource) {
87308c2ecf20Sopenharmony_ci		err = -EINVAL;
87318c2ecf20Sopenharmony_ci		goto out;
87328c2ecf20Sopenharmony_ci	}
87338c2ecf20Sopenharmony_ci	*p_resource_size = resource->size_new;
87348c2ecf20Sopenharmony_ci	resource->size = resource->size_new;
87358c2ecf20Sopenharmony_ciout:
87368c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
87378c2ecf20Sopenharmony_ci	return err;
87388c2ecf20Sopenharmony_ci}
87398c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_resource_size_get);
87408c2ecf20Sopenharmony_ci
87418c2ecf20Sopenharmony_ci/**
87428c2ecf20Sopenharmony_ci *	devlink_dpipe_table_resource_set - set the resource id
87438c2ecf20Sopenharmony_ci *
87448c2ecf20Sopenharmony_ci *	@devlink: devlink
87458c2ecf20Sopenharmony_ci *	@table_name: table name
87468c2ecf20Sopenharmony_ci *	@resource_id: resource id
87478c2ecf20Sopenharmony_ci *	@resource_units: number of resource's units consumed per table's entry
87488c2ecf20Sopenharmony_ci */
87498c2ecf20Sopenharmony_ciint devlink_dpipe_table_resource_set(struct devlink *devlink,
87508c2ecf20Sopenharmony_ci				     const char *table_name, u64 resource_id,
87518c2ecf20Sopenharmony_ci				     u64 resource_units)
87528c2ecf20Sopenharmony_ci{
87538c2ecf20Sopenharmony_ci	struct devlink_dpipe_table *table;
87548c2ecf20Sopenharmony_ci	int err = 0;
87558c2ecf20Sopenharmony_ci
87568c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
87578c2ecf20Sopenharmony_ci	table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
87588c2ecf20Sopenharmony_ci					 table_name, devlink);
87598c2ecf20Sopenharmony_ci	if (!table) {
87608c2ecf20Sopenharmony_ci		err = -EINVAL;
87618c2ecf20Sopenharmony_ci		goto out;
87628c2ecf20Sopenharmony_ci	}
87638c2ecf20Sopenharmony_ci	table->resource_id = resource_id;
87648c2ecf20Sopenharmony_ci	table->resource_units = resource_units;
87658c2ecf20Sopenharmony_ci	table->resource_valid = true;
87668c2ecf20Sopenharmony_ciout:
87678c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
87688c2ecf20Sopenharmony_ci	return err;
87698c2ecf20Sopenharmony_ci}
87708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_dpipe_table_resource_set);
87718c2ecf20Sopenharmony_ci
87728c2ecf20Sopenharmony_ci/**
87738c2ecf20Sopenharmony_ci *	devlink_resource_occ_get_register - register occupancy getter
87748c2ecf20Sopenharmony_ci *
87758c2ecf20Sopenharmony_ci *	@devlink: devlink
87768c2ecf20Sopenharmony_ci *	@resource_id: resource id
87778c2ecf20Sopenharmony_ci *	@occ_get: occupancy getter callback
87788c2ecf20Sopenharmony_ci *	@occ_get_priv: occupancy getter callback priv
87798c2ecf20Sopenharmony_ci */
87808c2ecf20Sopenharmony_civoid devlink_resource_occ_get_register(struct devlink *devlink,
87818c2ecf20Sopenharmony_ci				       u64 resource_id,
87828c2ecf20Sopenharmony_ci				       devlink_resource_occ_get_t *occ_get,
87838c2ecf20Sopenharmony_ci				       void *occ_get_priv)
87848c2ecf20Sopenharmony_ci{
87858c2ecf20Sopenharmony_ci	struct devlink_resource *resource;
87868c2ecf20Sopenharmony_ci
87878c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
87888c2ecf20Sopenharmony_ci	resource = devlink_resource_find(devlink, NULL, resource_id);
87898c2ecf20Sopenharmony_ci	if (WARN_ON(!resource))
87908c2ecf20Sopenharmony_ci		goto out;
87918c2ecf20Sopenharmony_ci	WARN_ON(resource->occ_get);
87928c2ecf20Sopenharmony_ci
87938c2ecf20Sopenharmony_ci	resource->occ_get = occ_get;
87948c2ecf20Sopenharmony_ci	resource->occ_get_priv = occ_get_priv;
87958c2ecf20Sopenharmony_ciout:
87968c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
87978c2ecf20Sopenharmony_ci}
87988c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_resource_occ_get_register);
87998c2ecf20Sopenharmony_ci
88008c2ecf20Sopenharmony_ci/**
88018c2ecf20Sopenharmony_ci *	devlink_resource_occ_get_unregister - unregister occupancy getter
88028c2ecf20Sopenharmony_ci *
88038c2ecf20Sopenharmony_ci *	@devlink: devlink
88048c2ecf20Sopenharmony_ci *	@resource_id: resource id
88058c2ecf20Sopenharmony_ci */
88068c2ecf20Sopenharmony_civoid devlink_resource_occ_get_unregister(struct devlink *devlink,
88078c2ecf20Sopenharmony_ci					 u64 resource_id)
88088c2ecf20Sopenharmony_ci{
88098c2ecf20Sopenharmony_ci	struct devlink_resource *resource;
88108c2ecf20Sopenharmony_ci
88118c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
88128c2ecf20Sopenharmony_ci	resource = devlink_resource_find(devlink, NULL, resource_id);
88138c2ecf20Sopenharmony_ci	if (WARN_ON(!resource))
88148c2ecf20Sopenharmony_ci		goto out;
88158c2ecf20Sopenharmony_ci	WARN_ON(!resource->occ_get);
88168c2ecf20Sopenharmony_ci
88178c2ecf20Sopenharmony_ci	resource->occ_get = NULL;
88188c2ecf20Sopenharmony_ci	resource->occ_get_priv = NULL;
88198c2ecf20Sopenharmony_ciout:
88208c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
88218c2ecf20Sopenharmony_ci}
88228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_resource_occ_get_unregister);
88238c2ecf20Sopenharmony_ci
88248c2ecf20Sopenharmony_cistatic int devlink_param_verify(const struct devlink_param *param)
88258c2ecf20Sopenharmony_ci{
88268c2ecf20Sopenharmony_ci	if (!param || !param->name || !param->supported_cmodes)
88278c2ecf20Sopenharmony_ci		return -EINVAL;
88288c2ecf20Sopenharmony_ci	if (param->generic)
88298c2ecf20Sopenharmony_ci		return devlink_param_generic_verify(param);
88308c2ecf20Sopenharmony_ci	else
88318c2ecf20Sopenharmony_ci		return devlink_param_driver_verify(param);
88328c2ecf20Sopenharmony_ci}
88338c2ecf20Sopenharmony_ci
88348c2ecf20Sopenharmony_cistatic int __devlink_params_register(struct devlink *devlink,
88358c2ecf20Sopenharmony_ci				     unsigned int port_index,
88368c2ecf20Sopenharmony_ci				     struct list_head *param_list,
88378c2ecf20Sopenharmony_ci				     const struct devlink_param *params,
88388c2ecf20Sopenharmony_ci				     size_t params_count,
88398c2ecf20Sopenharmony_ci				     enum devlink_command reg_cmd,
88408c2ecf20Sopenharmony_ci				     enum devlink_command unreg_cmd)
88418c2ecf20Sopenharmony_ci{
88428c2ecf20Sopenharmony_ci	const struct devlink_param *param = params;
88438c2ecf20Sopenharmony_ci	int i;
88448c2ecf20Sopenharmony_ci	int err;
88458c2ecf20Sopenharmony_ci
88468c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
88478c2ecf20Sopenharmony_ci	for (i = 0; i < params_count; i++, param++) {
88488c2ecf20Sopenharmony_ci		err = devlink_param_verify(param);
88498c2ecf20Sopenharmony_ci		if (err)
88508c2ecf20Sopenharmony_ci			goto rollback;
88518c2ecf20Sopenharmony_ci
88528c2ecf20Sopenharmony_ci		err = devlink_param_register_one(devlink, port_index,
88538c2ecf20Sopenharmony_ci						 param_list, param, reg_cmd);
88548c2ecf20Sopenharmony_ci		if (err)
88558c2ecf20Sopenharmony_ci			goto rollback;
88568c2ecf20Sopenharmony_ci	}
88578c2ecf20Sopenharmony_ci
88588c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
88598c2ecf20Sopenharmony_ci	return 0;
88608c2ecf20Sopenharmony_ci
88618c2ecf20Sopenharmony_cirollback:
88628c2ecf20Sopenharmony_ci	if (!i)
88638c2ecf20Sopenharmony_ci		goto unlock;
88648c2ecf20Sopenharmony_ci	for (param--; i > 0; i--, param--)
88658c2ecf20Sopenharmony_ci		devlink_param_unregister_one(devlink, port_index, param_list,
88668c2ecf20Sopenharmony_ci					     param, unreg_cmd);
88678c2ecf20Sopenharmony_ciunlock:
88688c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
88698c2ecf20Sopenharmony_ci	return err;
88708c2ecf20Sopenharmony_ci}
88718c2ecf20Sopenharmony_ci
88728c2ecf20Sopenharmony_cistatic void __devlink_params_unregister(struct devlink *devlink,
88738c2ecf20Sopenharmony_ci					unsigned int port_index,
88748c2ecf20Sopenharmony_ci					struct list_head *param_list,
88758c2ecf20Sopenharmony_ci					const struct devlink_param *params,
88768c2ecf20Sopenharmony_ci					size_t params_count,
88778c2ecf20Sopenharmony_ci					enum devlink_command cmd)
88788c2ecf20Sopenharmony_ci{
88798c2ecf20Sopenharmony_ci	const struct devlink_param *param = params;
88808c2ecf20Sopenharmony_ci	int i;
88818c2ecf20Sopenharmony_ci
88828c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
88838c2ecf20Sopenharmony_ci	for (i = 0; i < params_count; i++, param++)
88848c2ecf20Sopenharmony_ci		devlink_param_unregister_one(devlink, 0, param_list, param,
88858c2ecf20Sopenharmony_ci					     cmd);
88868c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
88878c2ecf20Sopenharmony_ci}
88888c2ecf20Sopenharmony_ci
88898c2ecf20Sopenharmony_ci/**
88908c2ecf20Sopenharmony_ci *	devlink_params_register - register configuration parameters
88918c2ecf20Sopenharmony_ci *
88928c2ecf20Sopenharmony_ci *	@devlink: devlink
88938c2ecf20Sopenharmony_ci *	@params: configuration parameters array
88948c2ecf20Sopenharmony_ci *	@params_count: number of parameters provided
88958c2ecf20Sopenharmony_ci *
88968c2ecf20Sopenharmony_ci *	Register the configuration parameters supported by the driver.
88978c2ecf20Sopenharmony_ci */
88988c2ecf20Sopenharmony_ciint devlink_params_register(struct devlink *devlink,
88998c2ecf20Sopenharmony_ci			    const struct devlink_param *params,
89008c2ecf20Sopenharmony_ci			    size_t params_count)
89018c2ecf20Sopenharmony_ci{
89028c2ecf20Sopenharmony_ci	return __devlink_params_register(devlink, 0, &devlink->param_list,
89038c2ecf20Sopenharmony_ci					 params, params_count,
89048c2ecf20Sopenharmony_ci					 DEVLINK_CMD_PARAM_NEW,
89058c2ecf20Sopenharmony_ci					 DEVLINK_CMD_PARAM_DEL);
89068c2ecf20Sopenharmony_ci}
89078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_params_register);
89088c2ecf20Sopenharmony_ci
89098c2ecf20Sopenharmony_ci/**
89108c2ecf20Sopenharmony_ci *	devlink_params_unregister - unregister configuration parameters
89118c2ecf20Sopenharmony_ci *	@devlink: devlink
89128c2ecf20Sopenharmony_ci *	@params: configuration parameters to unregister
89138c2ecf20Sopenharmony_ci *	@params_count: number of parameters provided
89148c2ecf20Sopenharmony_ci */
89158c2ecf20Sopenharmony_civoid devlink_params_unregister(struct devlink *devlink,
89168c2ecf20Sopenharmony_ci			       const struct devlink_param *params,
89178c2ecf20Sopenharmony_ci			       size_t params_count)
89188c2ecf20Sopenharmony_ci{
89198c2ecf20Sopenharmony_ci	return __devlink_params_unregister(devlink, 0, &devlink->param_list,
89208c2ecf20Sopenharmony_ci					   params, params_count,
89218c2ecf20Sopenharmony_ci					   DEVLINK_CMD_PARAM_DEL);
89228c2ecf20Sopenharmony_ci}
89238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_params_unregister);
89248c2ecf20Sopenharmony_ci
89258c2ecf20Sopenharmony_ci/**
89268c2ecf20Sopenharmony_ci *	devlink_params_publish - publish configuration parameters
89278c2ecf20Sopenharmony_ci *
89288c2ecf20Sopenharmony_ci *	@devlink: devlink
89298c2ecf20Sopenharmony_ci *
89308c2ecf20Sopenharmony_ci *	Publish previously registered configuration parameters.
89318c2ecf20Sopenharmony_ci */
89328c2ecf20Sopenharmony_civoid devlink_params_publish(struct devlink *devlink)
89338c2ecf20Sopenharmony_ci{
89348c2ecf20Sopenharmony_ci	struct devlink_param_item *param_item;
89358c2ecf20Sopenharmony_ci
89368c2ecf20Sopenharmony_ci	list_for_each_entry(param_item, &devlink->param_list, list) {
89378c2ecf20Sopenharmony_ci		if (param_item->published)
89388c2ecf20Sopenharmony_ci			continue;
89398c2ecf20Sopenharmony_ci		param_item->published = true;
89408c2ecf20Sopenharmony_ci		devlink_param_notify(devlink, 0, param_item,
89418c2ecf20Sopenharmony_ci				     DEVLINK_CMD_PARAM_NEW);
89428c2ecf20Sopenharmony_ci	}
89438c2ecf20Sopenharmony_ci}
89448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_params_publish);
89458c2ecf20Sopenharmony_ci
89468c2ecf20Sopenharmony_ci/**
89478c2ecf20Sopenharmony_ci *	devlink_params_unpublish - unpublish configuration parameters
89488c2ecf20Sopenharmony_ci *
89498c2ecf20Sopenharmony_ci *	@devlink: devlink
89508c2ecf20Sopenharmony_ci *
89518c2ecf20Sopenharmony_ci *	Unpublish previously registered configuration parameters.
89528c2ecf20Sopenharmony_ci */
89538c2ecf20Sopenharmony_civoid devlink_params_unpublish(struct devlink *devlink)
89548c2ecf20Sopenharmony_ci{
89558c2ecf20Sopenharmony_ci	struct devlink_param_item *param_item;
89568c2ecf20Sopenharmony_ci
89578c2ecf20Sopenharmony_ci	list_for_each_entry(param_item, &devlink->param_list, list) {
89588c2ecf20Sopenharmony_ci		if (!param_item->published)
89598c2ecf20Sopenharmony_ci			continue;
89608c2ecf20Sopenharmony_ci		param_item->published = false;
89618c2ecf20Sopenharmony_ci		devlink_param_notify(devlink, 0, param_item,
89628c2ecf20Sopenharmony_ci				     DEVLINK_CMD_PARAM_DEL);
89638c2ecf20Sopenharmony_ci	}
89648c2ecf20Sopenharmony_ci}
89658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_params_unpublish);
89668c2ecf20Sopenharmony_ci
89678c2ecf20Sopenharmony_ci/**
89688c2ecf20Sopenharmony_ci *	devlink_port_params_register - register port configuration parameters
89698c2ecf20Sopenharmony_ci *
89708c2ecf20Sopenharmony_ci *	@devlink_port: devlink port
89718c2ecf20Sopenharmony_ci *	@params: configuration parameters array
89728c2ecf20Sopenharmony_ci *	@params_count: number of parameters provided
89738c2ecf20Sopenharmony_ci *
89748c2ecf20Sopenharmony_ci *	Register the configuration parameters supported by the port.
89758c2ecf20Sopenharmony_ci */
89768c2ecf20Sopenharmony_ciint devlink_port_params_register(struct devlink_port *devlink_port,
89778c2ecf20Sopenharmony_ci				 const struct devlink_param *params,
89788c2ecf20Sopenharmony_ci				 size_t params_count)
89798c2ecf20Sopenharmony_ci{
89808c2ecf20Sopenharmony_ci	return __devlink_params_register(devlink_port->devlink,
89818c2ecf20Sopenharmony_ci					 devlink_port->index,
89828c2ecf20Sopenharmony_ci					 &devlink_port->param_list, params,
89838c2ecf20Sopenharmony_ci					 params_count,
89848c2ecf20Sopenharmony_ci					 DEVLINK_CMD_PORT_PARAM_NEW,
89858c2ecf20Sopenharmony_ci					 DEVLINK_CMD_PORT_PARAM_DEL);
89868c2ecf20Sopenharmony_ci}
89878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_params_register);
89888c2ecf20Sopenharmony_ci
89898c2ecf20Sopenharmony_ci/**
89908c2ecf20Sopenharmony_ci *	devlink_port_params_unregister - unregister port configuration
89918c2ecf20Sopenharmony_ci *	parameters
89928c2ecf20Sopenharmony_ci *
89938c2ecf20Sopenharmony_ci *	@devlink_port: devlink port
89948c2ecf20Sopenharmony_ci *	@params: configuration parameters array
89958c2ecf20Sopenharmony_ci *	@params_count: number of parameters provided
89968c2ecf20Sopenharmony_ci */
89978c2ecf20Sopenharmony_civoid devlink_port_params_unregister(struct devlink_port *devlink_port,
89988c2ecf20Sopenharmony_ci				    const struct devlink_param *params,
89998c2ecf20Sopenharmony_ci				    size_t params_count)
90008c2ecf20Sopenharmony_ci{
90018c2ecf20Sopenharmony_ci	return __devlink_params_unregister(devlink_port->devlink,
90028c2ecf20Sopenharmony_ci					   devlink_port->index,
90038c2ecf20Sopenharmony_ci					   &devlink_port->param_list,
90048c2ecf20Sopenharmony_ci					   params, params_count,
90058c2ecf20Sopenharmony_ci					   DEVLINK_CMD_PORT_PARAM_DEL);
90068c2ecf20Sopenharmony_ci}
90078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_params_unregister);
90088c2ecf20Sopenharmony_ci
90098c2ecf20Sopenharmony_cistatic int
90108c2ecf20Sopenharmony_ci__devlink_param_driverinit_value_get(struct list_head *param_list, u32 param_id,
90118c2ecf20Sopenharmony_ci				     union devlink_param_value *init_val)
90128c2ecf20Sopenharmony_ci{
90138c2ecf20Sopenharmony_ci	struct devlink_param_item *param_item;
90148c2ecf20Sopenharmony_ci
90158c2ecf20Sopenharmony_ci	param_item = devlink_param_find_by_id(param_list, param_id);
90168c2ecf20Sopenharmony_ci	if (!param_item)
90178c2ecf20Sopenharmony_ci		return -EINVAL;
90188c2ecf20Sopenharmony_ci
90198c2ecf20Sopenharmony_ci	if (!param_item->driverinit_value_valid ||
90208c2ecf20Sopenharmony_ci	    !devlink_param_cmode_is_supported(param_item->param,
90218c2ecf20Sopenharmony_ci					      DEVLINK_PARAM_CMODE_DRIVERINIT))
90228c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
90238c2ecf20Sopenharmony_ci
90248c2ecf20Sopenharmony_ci	if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
90258c2ecf20Sopenharmony_ci		strcpy(init_val->vstr, param_item->driverinit_value.vstr);
90268c2ecf20Sopenharmony_ci	else
90278c2ecf20Sopenharmony_ci		*init_val = param_item->driverinit_value;
90288c2ecf20Sopenharmony_ci
90298c2ecf20Sopenharmony_ci	return 0;
90308c2ecf20Sopenharmony_ci}
90318c2ecf20Sopenharmony_ci
90328c2ecf20Sopenharmony_cistatic int
90338c2ecf20Sopenharmony_ci__devlink_param_driverinit_value_set(struct devlink *devlink,
90348c2ecf20Sopenharmony_ci				     unsigned int port_index,
90358c2ecf20Sopenharmony_ci				     struct list_head *param_list, u32 param_id,
90368c2ecf20Sopenharmony_ci				     union devlink_param_value init_val,
90378c2ecf20Sopenharmony_ci				     enum devlink_command cmd)
90388c2ecf20Sopenharmony_ci{
90398c2ecf20Sopenharmony_ci	struct devlink_param_item *param_item;
90408c2ecf20Sopenharmony_ci
90418c2ecf20Sopenharmony_ci	param_item = devlink_param_find_by_id(param_list, param_id);
90428c2ecf20Sopenharmony_ci	if (!param_item)
90438c2ecf20Sopenharmony_ci		return -EINVAL;
90448c2ecf20Sopenharmony_ci
90458c2ecf20Sopenharmony_ci	if (!devlink_param_cmode_is_supported(param_item->param,
90468c2ecf20Sopenharmony_ci					      DEVLINK_PARAM_CMODE_DRIVERINIT))
90478c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
90488c2ecf20Sopenharmony_ci
90498c2ecf20Sopenharmony_ci	if (param_item->param->type == DEVLINK_PARAM_TYPE_STRING)
90508c2ecf20Sopenharmony_ci		strcpy(param_item->driverinit_value.vstr, init_val.vstr);
90518c2ecf20Sopenharmony_ci	else
90528c2ecf20Sopenharmony_ci		param_item->driverinit_value = init_val;
90538c2ecf20Sopenharmony_ci	param_item->driverinit_value_valid = true;
90548c2ecf20Sopenharmony_ci
90558c2ecf20Sopenharmony_ci	devlink_param_notify(devlink, port_index, param_item, cmd);
90568c2ecf20Sopenharmony_ci	return 0;
90578c2ecf20Sopenharmony_ci}
90588c2ecf20Sopenharmony_ci
90598c2ecf20Sopenharmony_ci/**
90608c2ecf20Sopenharmony_ci *	devlink_param_driverinit_value_get - get configuration parameter
90618c2ecf20Sopenharmony_ci *					     value for driver initializing
90628c2ecf20Sopenharmony_ci *
90638c2ecf20Sopenharmony_ci *	@devlink: devlink
90648c2ecf20Sopenharmony_ci *	@param_id: parameter ID
90658c2ecf20Sopenharmony_ci *	@init_val: value of parameter in driverinit configuration mode
90668c2ecf20Sopenharmony_ci *
90678c2ecf20Sopenharmony_ci *	This function should be used by the driver to get driverinit
90688c2ecf20Sopenharmony_ci *	configuration for initialization after reload command.
90698c2ecf20Sopenharmony_ci */
90708c2ecf20Sopenharmony_ciint devlink_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
90718c2ecf20Sopenharmony_ci				       union devlink_param_value *init_val)
90728c2ecf20Sopenharmony_ci{
90738c2ecf20Sopenharmony_ci	if (!devlink_reload_supported(devlink->ops))
90748c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
90758c2ecf20Sopenharmony_ci
90768c2ecf20Sopenharmony_ci	return __devlink_param_driverinit_value_get(&devlink->param_list,
90778c2ecf20Sopenharmony_ci						    param_id, init_val);
90788c2ecf20Sopenharmony_ci}
90798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_param_driverinit_value_get);
90808c2ecf20Sopenharmony_ci
90818c2ecf20Sopenharmony_ci/**
90828c2ecf20Sopenharmony_ci *	devlink_param_driverinit_value_set - set value of configuration
90838c2ecf20Sopenharmony_ci *					     parameter for driverinit
90848c2ecf20Sopenharmony_ci *					     configuration mode
90858c2ecf20Sopenharmony_ci *
90868c2ecf20Sopenharmony_ci *	@devlink: devlink
90878c2ecf20Sopenharmony_ci *	@param_id: parameter ID
90888c2ecf20Sopenharmony_ci *	@init_val: value of parameter to set for driverinit configuration mode
90898c2ecf20Sopenharmony_ci *
90908c2ecf20Sopenharmony_ci *	This function should be used by the driver to set driverinit
90918c2ecf20Sopenharmony_ci *	configuration mode default value.
90928c2ecf20Sopenharmony_ci */
90938c2ecf20Sopenharmony_ciint devlink_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
90948c2ecf20Sopenharmony_ci				       union devlink_param_value init_val)
90958c2ecf20Sopenharmony_ci{
90968c2ecf20Sopenharmony_ci	return __devlink_param_driverinit_value_set(devlink, 0,
90978c2ecf20Sopenharmony_ci						    &devlink->param_list,
90988c2ecf20Sopenharmony_ci						    param_id, init_val,
90998c2ecf20Sopenharmony_ci						    DEVLINK_CMD_PARAM_NEW);
91008c2ecf20Sopenharmony_ci}
91018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_param_driverinit_value_set);
91028c2ecf20Sopenharmony_ci
91038c2ecf20Sopenharmony_ci/**
91048c2ecf20Sopenharmony_ci *	devlink_port_param_driverinit_value_get - get configuration parameter
91058c2ecf20Sopenharmony_ci *						value for driver initializing
91068c2ecf20Sopenharmony_ci *
91078c2ecf20Sopenharmony_ci *	@devlink_port: devlink_port
91088c2ecf20Sopenharmony_ci *	@param_id: parameter ID
91098c2ecf20Sopenharmony_ci *	@init_val: value of parameter in driverinit configuration mode
91108c2ecf20Sopenharmony_ci *
91118c2ecf20Sopenharmony_ci *	This function should be used by the driver to get driverinit
91128c2ecf20Sopenharmony_ci *	configuration for initialization after reload command.
91138c2ecf20Sopenharmony_ci */
91148c2ecf20Sopenharmony_ciint devlink_port_param_driverinit_value_get(struct devlink_port *devlink_port,
91158c2ecf20Sopenharmony_ci					    u32 param_id,
91168c2ecf20Sopenharmony_ci					    union devlink_param_value *init_val)
91178c2ecf20Sopenharmony_ci{
91188c2ecf20Sopenharmony_ci	struct devlink *devlink = devlink_port->devlink;
91198c2ecf20Sopenharmony_ci
91208c2ecf20Sopenharmony_ci	if (!devlink_reload_supported(devlink->ops))
91218c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
91228c2ecf20Sopenharmony_ci
91238c2ecf20Sopenharmony_ci	return __devlink_param_driverinit_value_get(&devlink_port->param_list,
91248c2ecf20Sopenharmony_ci						    param_id, init_val);
91258c2ecf20Sopenharmony_ci}
91268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_get);
91278c2ecf20Sopenharmony_ci
91288c2ecf20Sopenharmony_ci/**
91298c2ecf20Sopenharmony_ci *     devlink_port_param_driverinit_value_set - set value of configuration
91308c2ecf20Sopenharmony_ci *                                               parameter for driverinit
91318c2ecf20Sopenharmony_ci *                                               configuration mode
91328c2ecf20Sopenharmony_ci *
91338c2ecf20Sopenharmony_ci *     @devlink_port: devlink_port
91348c2ecf20Sopenharmony_ci *     @param_id: parameter ID
91358c2ecf20Sopenharmony_ci *     @init_val: value of parameter to set for driverinit configuration mode
91368c2ecf20Sopenharmony_ci *
91378c2ecf20Sopenharmony_ci *     This function should be used by the driver to set driverinit
91388c2ecf20Sopenharmony_ci *     configuration mode default value.
91398c2ecf20Sopenharmony_ci */
91408c2ecf20Sopenharmony_ciint devlink_port_param_driverinit_value_set(struct devlink_port *devlink_port,
91418c2ecf20Sopenharmony_ci					    u32 param_id,
91428c2ecf20Sopenharmony_ci					    union devlink_param_value init_val)
91438c2ecf20Sopenharmony_ci{
91448c2ecf20Sopenharmony_ci	return __devlink_param_driverinit_value_set(devlink_port->devlink,
91458c2ecf20Sopenharmony_ci						    devlink_port->index,
91468c2ecf20Sopenharmony_ci						    &devlink_port->param_list,
91478c2ecf20Sopenharmony_ci						    param_id, init_val,
91488c2ecf20Sopenharmony_ci						    DEVLINK_CMD_PORT_PARAM_NEW);
91498c2ecf20Sopenharmony_ci}
91508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_param_driverinit_value_set);
91518c2ecf20Sopenharmony_ci
91528c2ecf20Sopenharmony_ci/**
91538c2ecf20Sopenharmony_ci *	devlink_param_value_changed - notify devlink on a parameter's value
91548c2ecf20Sopenharmony_ci *				      change. Should be called by the driver
91558c2ecf20Sopenharmony_ci *				      right after the change.
91568c2ecf20Sopenharmony_ci *
91578c2ecf20Sopenharmony_ci *	@devlink: devlink
91588c2ecf20Sopenharmony_ci *	@param_id: parameter ID
91598c2ecf20Sopenharmony_ci *
91608c2ecf20Sopenharmony_ci *	This function should be used by the driver to notify devlink on value
91618c2ecf20Sopenharmony_ci *	change, excluding driverinit configuration mode.
91628c2ecf20Sopenharmony_ci *	For driverinit configuration mode driver should use the function
91638c2ecf20Sopenharmony_ci */
91648c2ecf20Sopenharmony_civoid devlink_param_value_changed(struct devlink *devlink, u32 param_id)
91658c2ecf20Sopenharmony_ci{
91668c2ecf20Sopenharmony_ci	struct devlink_param_item *param_item;
91678c2ecf20Sopenharmony_ci
91688c2ecf20Sopenharmony_ci	param_item = devlink_param_find_by_id(&devlink->param_list, param_id);
91698c2ecf20Sopenharmony_ci	WARN_ON(!param_item);
91708c2ecf20Sopenharmony_ci
91718c2ecf20Sopenharmony_ci	devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
91728c2ecf20Sopenharmony_ci}
91738c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_param_value_changed);
91748c2ecf20Sopenharmony_ci
91758c2ecf20Sopenharmony_ci/**
91768c2ecf20Sopenharmony_ci *     devlink_port_param_value_changed - notify devlink on a parameter's value
91778c2ecf20Sopenharmony_ci *                                      change. Should be called by the driver
91788c2ecf20Sopenharmony_ci *                                      right after the change.
91798c2ecf20Sopenharmony_ci *
91808c2ecf20Sopenharmony_ci *     @devlink_port: devlink_port
91818c2ecf20Sopenharmony_ci *     @param_id: parameter ID
91828c2ecf20Sopenharmony_ci *
91838c2ecf20Sopenharmony_ci *     This function should be used by the driver to notify devlink on value
91848c2ecf20Sopenharmony_ci *     change, excluding driverinit configuration mode.
91858c2ecf20Sopenharmony_ci *     For driverinit configuration mode driver should use the function
91868c2ecf20Sopenharmony_ci *     devlink_port_param_driverinit_value_set() instead.
91878c2ecf20Sopenharmony_ci */
91888c2ecf20Sopenharmony_civoid devlink_port_param_value_changed(struct devlink_port *devlink_port,
91898c2ecf20Sopenharmony_ci				      u32 param_id)
91908c2ecf20Sopenharmony_ci{
91918c2ecf20Sopenharmony_ci	struct devlink_param_item *param_item;
91928c2ecf20Sopenharmony_ci
91938c2ecf20Sopenharmony_ci	param_item = devlink_param_find_by_id(&devlink_port->param_list,
91948c2ecf20Sopenharmony_ci					      param_id);
91958c2ecf20Sopenharmony_ci	WARN_ON(!param_item);
91968c2ecf20Sopenharmony_ci
91978c2ecf20Sopenharmony_ci	devlink_param_notify(devlink_port->devlink, devlink_port->index,
91988c2ecf20Sopenharmony_ci			     param_item, DEVLINK_CMD_PORT_PARAM_NEW);
91998c2ecf20Sopenharmony_ci}
92008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_param_value_changed);
92018c2ecf20Sopenharmony_ci
92028c2ecf20Sopenharmony_ci/**
92038c2ecf20Sopenharmony_ci *	devlink_param_value_str_fill - Safely fill-up the string preventing
92048c2ecf20Sopenharmony_ci *				       from overflow of the preallocated buffer
92058c2ecf20Sopenharmony_ci *
92068c2ecf20Sopenharmony_ci *	@dst_val: destination devlink_param_value
92078c2ecf20Sopenharmony_ci *	@src: source buffer
92088c2ecf20Sopenharmony_ci */
92098c2ecf20Sopenharmony_civoid devlink_param_value_str_fill(union devlink_param_value *dst_val,
92108c2ecf20Sopenharmony_ci				  const char *src)
92118c2ecf20Sopenharmony_ci{
92128c2ecf20Sopenharmony_ci	size_t len;
92138c2ecf20Sopenharmony_ci
92148c2ecf20Sopenharmony_ci	len = strlcpy(dst_val->vstr, src, __DEVLINK_PARAM_MAX_STRING_VALUE);
92158c2ecf20Sopenharmony_ci	WARN_ON(len >= __DEVLINK_PARAM_MAX_STRING_VALUE);
92168c2ecf20Sopenharmony_ci}
92178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_param_value_str_fill);
92188c2ecf20Sopenharmony_ci
92198c2ecf20Sopenharmony_ci/**
92208c2ecf20Sopenharmony_ci *	devlink_region_create - create a new address region
92218c2ecf20Sopenharmony_ci *
92228c2ecf20Sopenharmony_ci *	@devlink: devlink
92238c2ecf20Sopenharmony_ci *	@ops: region operations and name
92248c2ecf20Sopenharmony_ci *	@region_max_snapshots: Maximum supported number of snapshots for region
92258c2ecf20Sopenharmony_ci *	@region_size: size of region
92268c2ecf20Sopenharmony_ci */
92278c2ecf20Sopenharmony_cistruct devlink_region *
92288c2ecf20Sopenharmony_cidevlink_region_create(struct devlink *devlink,
92298c2ecf20Sopenharmony_ci		      const struct devlink_region_ops *ops,
92308c2ecf20Sopenharmony_ci		      u32 region_max_snapshots, u64 region_size)
92318c2ecf20Sopenharmony_ci{
92328c2ecf20Sopenharmony_ci	struct devlink_region *region;
92338c2ecf20Sopenharmony_ci	int err = 0;
92348c2ecf20Sopenharmony_ci
92358c2ecf20Sopenharmony_ci	if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
92368c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
92378c2ecf20Sopenharmony_ci
92388c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
92398c2ecf20Sopenharmony_ci
92408c2ecf20Sopenharmony_ci	if (devlink_region_get_by_name(devlink, ops->name)) {
92418c2ecf20Sopenharmony_ci		err = -EEXIST;
92428c2ecf20Sopenharmony_ci		goto unlock;
92438c2ecf20Sopenharmony_ci	}
92448c2ecf20Sopenharmony_ci
92458c2ecf20Sopenharmony_ci	region = kzalloc(sizeof(*region), GFP_KERNEL);
92468c2ecf20Sopenharmony_ci	if (!region) {
92478c2ecf20Sopenharmony_ci		err = -ENOMEM;
92488c2ecf20Sopenharmony_ci		goto unlock;
92498c2ecf20Sopenharmony_ci	}
92508c2ecf20Sopenharmony_ci
92518c2ecf20Sopenharmony_ci	region->devlink = devlink;
92528c2ecf20Sopenharmony_ci	region->max_snapshots = region_max_snapshots;
92538c2ecf20Sopenharmony_ci	region->ops = ops;
92548c2ecf20Sopenharmony_ci	region->size = region_size;
92558c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&region->snapshot_list);
92568c2ecf20Sopenharmony_ci	list_add_tail(&region->list, &devlink->region_list);
92578c2ecf20Sopenharmony_ci	devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
92588c2ecf20Sopenharmony_ci
92598c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
92608c2ecf20Sopenharmony_ci	return region;
92618c2ecf20Sopenharmony_ci
92628c2ecf20Sopenharmony_ciunlock:
92638c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
92648c2ecf20Sopenharmony_ci	return ERR_PTR(err);
92658c2ecf20Sopenharmony_ci}
92668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_region_create);
92678c2ecf20Sopenharmony_ci
92688c2ecf20Sopenharmony_ci/**
92698c2ecf20Sopenharmony_ci *	devlink_port_region_create - create a new address region for a port
92708c2ecf20Sopenharmony_ci *
92718c2ecf20Sopenharmony_ci *	@port: devlink port
92728c2ecf20Sopenharmony_ci *	@ops: region operations and name
92738c2ecf20Sopenharmony_ci *	@region_max_snapshots: Maximum supported number of snapshots for region
92748c2ecf20Sopenharmony_ci *	@region_size: size of region
92758c2ecf20Sopenharmony_ci */
92768c2ecf20Sopenharmony_cistruct devlink_region *
92778c2ecf20Sopenharmony_cidevlink_port_region_create(struct devlink_port *port,
92788c2ecf20Sopenharmony_ci			   const struct devlink_port_region_ops *ops,
92798c2ecf20Sopenharmony_ci			   u32 region_max_snapshots, u64 region_size)
92808c2ecf20Sopenharmony_ci{
92818c2ecf20Sopenharmony_ci	struct devlink *devlink = port->devlink;
92828c2ecf20Sopenharmony_ci	struct devlink_region *region;
92838c2ecf20Sopenharmony_ci	int err = 0;
92848c2ecf20Sopenharmony_ci
92858c2ecf20Sopenharmony_ci	if (WARN_ON(!ops) || WARN_ON(!ops->destructor))
92868c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
92878c2ecf20Sopenharmony_ci
92888c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
92898c2ecf20Sopenharmony_ci
92908c2ecf20Sopenharmony_ci	if (devlink_port_region_get_by_name(port, ops->name)) {
92918c2ecf20Sopenharmony_ci		err = -EEXIST;
92928c2ecf20Sopenharmony_ci		goto unlock;
92938c2ecf20Sopenharmony_ci	}
92948c2ecf20Sopenharmony_ci
92958c2ecf20Sopenharmony_ci	region = kzalloc(sizeof(*region), GFP_KERNEL);
92968c2ecf20Sopenharmony_ci	if (!region) {
92978c2ecf20Sopenharmony_ci		err = -ENOMEM;
92988c2ecf20Sopenharmony_ci		goto unlock;
92998c2ecf20Sopenharmony_ci	}
93008c2ecf20Sopenharmony_ci
93018c2ecf20Sopenharmony_ci	region->devlink = devlink;
93028c2ecf20Sopenharmony_ci	region->port = port;
93038c2ecf20Sopenharmony_ci	region->max_snapshots = region_max_snapshots;
93048c2ecf20Sopenharmony_ci	region->port_ops = ops;
93058c2ecf20Sopenharmony_ci	region->size = region_size;
93068c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&region->snapshot_list);
93078c2ecf20Sopenharmony_ci	list_add_tail(&region->list, &port->region_list);
93088c2ecf20Sopenharmony_ci	devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_NEW);
93098c2ecf20Sopenharmony_ci
93108c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
93118c2ecf20Sopenharmony_ci	return region;
93128c2ecf20Sopenharmony_ci
93138c2ecf20Sopenharmony_ciunlock:
93148c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
93158c2ecf20Sopenharmony_ci	return ERR_PTR(err);
93168c2ecf20Sopenharmony_ci}
93178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_port_region_create);
93188c2ecf20Sopenharmony_ci
93198c2ecf20Sopenharmony_ci/**
93208c2ecf20Sopenharmony_ci *	devlink_region_destroy - destroy address region
93218c2ecf20Sopenharmony_ci *
93228c2ecf20Sopenharmony_ci *	@region: devlink region to destroy
93238c2ecf20Sopenharmony_ci */
93248c2ecf20Sopenharmony_civoid devlink_region_destroy(struct devlink_region *region)
93258c2ecf20Sopenharmony_ci{
93268c2ecf20Sopenharmony_ci	struct devlink *devlink = region->devlink;
93278c2ecf20Sopenharmony_ci	struct devlink_snapshot *snapshot, *ts;
93288c2ecf20Sopenharmony_ci
93298c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
93308c2ecf20Sopenharmony_ci
93318c2ecf20Sopenharmony_ci	/* Free all snapshots of region */
93328c2ecf20Sopenharmony_ci	list_for_each_entry_safe(snapshot, ts, &region->snapshot_list, list)
93338c2ecf20Sopenharmony_ci		devlink_region_snapshot_del(region, snapshot);
93348c2ecf20Sopenharmony_ci
93358c2ecf20Sopenharmony_ci	list_del(&region->list);
93368c2ecf20Sopenharmony_ci
93378c2ecf20Sopenharmony_ci	devlink_nl_region_notify(region, NULL, DEVLINK_CMD_REGION_DEL);
93388c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
93398c2ecf20Sopenharmony_ci	kfree(region);
93408c2ecf20Sopenharmony_ci}
93418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_region_destroy);
93428c2ecf20Sopenharmony_ci
93438c2ecf20Sopenharmony_ci/**
93448c2ecf20Sopenharmony_ci *	devlink_region_snapshot_id_get - get snapshot ID
93458c2ecf20Sopenharmony_ci *
93468c2ecf20Sopenharmony_ci *	This callback should be called when adding a new snapshot,
93478c2ecf20Sopenharmony_ci *	Driver should use the same id for multiple snapshots taken
93488c2ecf20Sopenharmony_ci *	on multiple regions at the same time/by the same trigger.
93498c2ecf20Sopenharmony_ci *
93508c2ecf20Sopenharmony_ci *	The caller of this function must use devlink_region_snapshot_id_put
93518c2ecf20Sopenharmony_ci *	when finished creating regions using this id.
93528c2ecf20Sopenharmony_ci *
93538c2ecf20Sopenharmony_ci *	Returns zero on success, or a negative error code on failure.
93548c2ecf20Sopenharmony_ci *
93558c2ecf20Sopenharmony_ci *	@devlink: devlink
93568c2ecf20Sopenharmony_ci *	@id: storage to return id
93578c2ecf20Sopenharmony_ci */
93588c2ecf20Sopenharmony_ciint devlink_region_snapshot_id_get(struct devlink *devlink, u32 *id)
93598c2ecf20Sopenharmony_ci{
93608c2ecf20Sopenharmony_ci	int err;
93618c2ecf20Sopenharmony_ci
93628c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
93638c2ecf20Sopenharmony_ci	err = __devlink_region_snapshot_id_get(devlink, id);
93648c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
93658c2ecf20Sopenharmony_ci
93668c2ecf20Sopenharmony_ci	return err;
93678c2ecf20Sopenharmony_ci}
93688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_region_snapshot_id_get);
93698c2ecf20Sopenharmony_ci
93708c2ecf20Sopenharmony_ci/**
93718c2ecf20Sopenharmony_ci *	devlink_region_snapshot_id_put - put snapshot ID reference
93728c2ecf20Sopenharmony_ci *
93738c2ecf20Sopenharmony_ci *	This should be called by a driver after finishing creating snapshots
93748c2ecf20Sopenharmony_ci *	with an id. Doing so ensures that the ID can later be released in the
93758c2ecf20Sopenharmony_ci *	event that all snapshots using it have been destroyed.
93768c2ecf20Sopenharmony_ci *
93778c2ecf20Sopenharmony_ci *	@devlink: devlink
93788c2ecf20Sopenharmony_ci *	@id: id to release reference on
93798c2ecf20Sopenharmony_ci */
93808c2ecf20Sopenharmony_civoid devlink_region_snapshot_id_put(struct devlink *devlink, u32 id)
93818c2ecf20Sopenharmony_ci{
93828c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
93838c2ecf20Sopenharmony_ci	__devlink_snapshot_id_decrement(devlink, id);
93848c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
93858c2ecf20Sopenharmony_ci}
93868c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_region_snapshot_id_put);
93878c2ecf20Sopenharmony_ci
93888c2ecf20Sopenharmony_ci/**
93898c2ecf20Sopenharmony_ci *	devlink_region_snapshot_create - create a new snapshot
93908c2ecf20Sopenharmony_ci *	This will add a new snapshot of a region. The snapshot
93918c2ecf20Sopenharmony_ci *	will be stored on the region struct and can be accessed
93928c2ecf20Sopenharmony_ci *	from devlink. This is useful for future analyses of snapshots.
93938c2ecf20Sopenharmony_ci *	Multiple snapshots can be created on a region.
93948c2ecf20Sopenharmony_ci *	The @snapshot_id should be obtained using the getter function.
93958c2ecf20Sopenharmony_ci *
93968c2ecf20Sopenharmony_ci *	@region: devlink region of the snapshot
93978c2ecf20Sopenharmony_ci *	@data: snapshot data
93988c2ecf20Sopenharmony_ci *	@snapshot_id: snapshot id to be created
93998c2ecf20Sopenharmony_ci */
94008c2ecf20Sopenharmony_ciint devlink_region_snapshot_create(struct devlink_region *region,
94018c2ecf20Sopenharmony_ci				   u8 *data, u32 snapshot_id)
94028c2ecf20Sopenharmony_ci{
94038c2ecf20Sopenharmony_ci	struct devlink *devlink = region->devlink;
94048c2ecf20Sopenharmony_ci	int err;
94058c2ecf20Sopenharmony_ci
94068c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
94078c2ecf20Sopenharmony_ci	err = __devlink_region_snapshot_create(region, data, snapshot_id);
94088c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
94098c2ecf20Sopenharmony_ci
94108c2ecf20Sopenharmony_ci	return err;
94118c2ecf20Sopenharmony_ci}
94128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_region_snapshot_create);
94138c2ecf20Sopenharmony_ci
94148c2ecf20Sopenharmony_ci#define DEVLINK_TRAP(_id, _type)					      \
94158c2ecf20Sopenharmony_ci	{								      \
94168c2ecf20Sopenharmony_ci		.type = DEVLINK_TRAP_TYPE_##_type,			      \
94178c2ecf20Sopenharmony_ci		.id = DEVLINK_TRAP_GENERIC_ID_##_id,			      \
94188c2ecf20Sopenharmony_ci		.name = DEVLINK_TRAP_GENERIC_NAME_##_id,		      \
94198c2ecf20Sopenharmony_ci	}
94208c2ecf20Sopenharmony_ci
94218c2ecf20Sopenharmony_cistatic const struct devlink_trap devlink_trap_generic[] = {
94228c2ecf20Sopenharmony_ci	DEVLINK_TRAP(SMAC_MC, DROP),
94238c2ecf20Sopenharmony_ci	DEVLINK_TRAP(VLAN_TAG_MISMATCH, DROP),
94248c2ecf20Sopenharmony_ci	DEVLINK_TRAP(INGRESS_VLAN_FILTER, DROP),
94258c2ecf20Sopenharmony_ci	DEVLINK_TRAP(INGRESS_STP_FILTER, DROP),
94268c2ecf20Sopenharmony_ci	DEVLINK_TRAP(EMPTY_TX_LIST, DROP),
94278c2ecf20Sopenharmony_ci	DEVLINK_TRAP(PORT_LOOPBACK_FILTER, DROP),
94288c2ecf20Sopenharmony_ci	DEVLINK_TRAP(BLACKHOLE_ROUTE, DROP),
94298c2ecf20Sopenharmony_ci	DEVLINK_TRAP(TTL_ERROR, EXCEPTION),
94308c2ecf20Sopenharmony_ci	DEVLINK_TRAP(TAIL_DROP, DROP),
94318c2ecf20Sopenharmony_ci	DEVLINK_TRAP(NON_IP_PACKET, DROP),
94328c2ecf20Sopenharmony_ci	DEVLINK_TRAP(UC_DIP_MC_DMAC, DROP),
94338c2ecf20Sopenharmony_ci	DEVLINK_TRAP(DIP_LB, DROP),
94348c2ecf20Sopenharmony_ci	DEVLINK_TRAP(SIP_MC, DROP),
94358c2ecf20Sopenharmony_ci	DEVLINK_TRAP(SIP_LB, DROP),
94368c2ecf20Sopenharmony_ci	DEVLINK_TRAP(CORRUPTED_IP_HDR, DROP),
94378c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV4_SIP_BC, DROP),
94388c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_MC_DIP_RESERVED_SCOPE, DROP),
94398c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_MC_DIP_INTERFACE_LOCAL_SCOPE, DROP),
94408c2ecf20Sopenharmony_ci	DEVLINK_TRAP(MTU_ERROR, EXCEPTION),
94418c2ecf20Sopenharmony_ci	DEVLINK_TRAP(UNRESOLVED_NEIGH, EXCEPTION),
94428c2ecf20Sopenharmony_ci	DEVLINK_TRAP(RPF, EXCEPTION),
94438c2ecf20Sopenharmony_ci	DEVLINK_TRAP(REJECT_ROUTE, EXCEPTION),
94448c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV4_LPM_UNICAST_MISS, EXCEPTION),
94458c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_LPM_UNICAST_MISS, EXCEPTION),
94468c2ecf20Sopenharmony_ci	DEVLINK_TRAP(NON_ROUTABLE, DROP),
94478c2ecf20Sopenharmony_ci	DEVLINK_TRAP(DECAP_ERROR, EXCEPTION),
94488c2ecf20Sopenharmony_ci	DEVLINK_TRAP(OVERLAY_SMAC_MC, DROP),
94498c2ecf20Sopenharmony_ci	DEVLINK_TRAP(INGRESS_FLOW_ACTION_DROP, DROP),
94508c2ecf20Sopenharmony_ci	DEVLINK_TRAP(EGRESS_FLOW_ACTION_DROP, DROP),
94518c2ecf20Sopenharmony_ci	DEVLINK_TRAP(STP, CONTROL),
94528c2ecf20Sopenharmony_ci	DEVLINK_TRAP(LACP, CONTROL),
94538c2ecf20Sopenharmony_ci	DEVLINK_TRAP(LLDP, CONTROL),
94548c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IGMP_QUERY, CONTROL),
94558c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IGMP_V1_REPORT, CONTROL),
94568c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IGMP_V2_REPORT, CONTROL),
94578c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IGMP_V3_REPORT, CONTROL),
94588c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IGMP_V2_LEAVE, CONTROL),
94598c2ecf20Sopenharmony_ci	DEVLINK_TRAP(MLD_QUERY, CONTROL),
94608c2ecf20Sopenharmony_ci	DEVLINK_TRAP(MLD_V1_REPORT, CONTROL),
94618c2ecf20Sopenharmony_ci	DEVLINK_TRAP(MLD_V2_REPORT, CONTROL),
94628c2ecf20Sopenharmony_ci	DEVLINK_TRAP(MLD_V1_DONE, CONTROL),
94638c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV4_DHCP, CONTROL),
94648c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_DHCP, CONTROL),
94658c2ecf20Sopenharmony_ci	DEVLINK_TRAP(ARP_REQUEST, CONTROL),
94668c2ecf20Sopenharmony_ci	DEVLINK_TRAP(ARP_RESPONSE, CONTROL),
94678c2ecf20Sopenharmony_ci	DEVLINK_TRAP(ARP_OVERLAY, CONTROL),
94688c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_NEIGH_SOLICIT, CONTROL),
94698c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_NEIGH_ADVERT, CONTROL),
94708c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV4_BFD, CONTROL),
94718c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_BFD, CONTROL),
94728c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV4_OSPF, CONTROL),
94738c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_OSPF, CONTROL),
94748c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV4_BGP, CONTROL),
94758c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_BGP, CONTROL),
94768c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV4_VRRP, CONTROL),
94778c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_VRRP, CONTROL),
94788c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV4_PIM, CONTROL),
94798c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_PIM, CONTROL),
94808c2ecf20Sopenharmony_ci	DEVLINK_TRAP(UC_LB, CONTROL),
94818c2ecf20Sopenharmony_ci	DEVLINK_TRAP(LOCAL_ROUTE, CONTROL),
94828c2ecf20Sopenharmony_ci	DEVLINK_TRAP(EXTERNAL_ROUTE, CONTROL),
94838c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_UC_DIP_LINK_LOCAL_SCOPE, CONTROL),
94848c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_DIP_ALL_NODES, CONTROL),
94858c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_DIP_ALL_ROUTERS, CONTROL),
94868c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_ROUTER_SOLICIT, CONTROL),
94878c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_ROUTER_ADVERT, CONTROL),
94888c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_REDIRECT, CONTROL),
94898c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV4_ROUTER_ALERT, CONTROL),
94908c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPV6_ROUTER_ALERT, CONTROL),
94918c2ecf20Sopenharmony_ci	DEVLINK_TRAP(PTP_EVENT, CONTROL),
94928c2ecf20Sopenharmony_ci	DEVLINK_TRAP(PTP_GENERAL, CONTROL),
94938c2ecf20Sopenharmony_ci	DEVLINK_TRAP(FLOW_ACTION_SAMPLE, CONTROL),
94948c2ecf20Sopenharmony_ci	DEVLINK_TRAP(FLOW_ACTION_TRAP, CONTROL),
94958c2ecf20Sopenharmony_ci	DEVLINK_TRAP(EARLY_DROP, DROP),
94968c2ecf20Sopenharmony_ci	DEVLINK_TRAP(VXLAN_PARSING, DROP),
94978c2ecf20Sopenharmony_ci	DEVLINK_TRAP(LLC_SNAP_PARSING, DROP),
94988c2ecf20Sopenharmony_ci	DEVLINK_TRAP(VLAN_PARSING, DROP),
94998c2ecf20Sopenharmony_ci	DEVLINK_TRAP(PPPOE_PPP_PARSING, DROP),
95008c2ecf20Sopenharmony_ci	DEVLINK_TRAP(MPLS_PARSING, DROP),
95018c2ecf20Sopenharmony_ci	DEVLINK_TRAP(ARP_PARSING, DROP),
95028c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IP_1_PARSING, DROP),
95038c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IP_N_PARSING, DROP),
95048c2ecf20Sopenharmony_ci	DEVLINK_TRAP(GRE_PARSING, DROP),
95058c2ecf20Sopenharmony_ci	DEVLINK_TRAP(UDP_PARSING, DROP),
95068c2ecf20Sopenharmony_ci	DEVLINK_TRAP(TCP_PARSING, DROP),
95078c2ecf20Sopenharmony_ci	DEVLINK_TRAP(IPSEC_PARSING, DROP),
95088c2ecf20Sopenharmony_ci	DEVLINK_TRAP(SCTP_PARSING, DROP),
95098c2ecf20Sopenharmony_ci	DEVLINK_TRAP(DCCP_PARSING, DROP),
95108c2ecf20Sopenharmony_ci	DEVLINK_TRAP(GTP_PARSING, DROP),
95118c2ecf20Sopenharmony_ci	DEVLINK_TRAP(ESP_PARSING, DROP),
95128c2ecf20Sopenharmony_ci};
95138c2ecf20Sopenharmony_ci
95148c2ecf20Sopenharmony_ci#define DEVLINK_TRAP_GROUP(_id)						      \
95158c2ecf20Sopenharmony_ci	{								      \
95168c2ecf20Sopenharmony_ci		.id = DEVLINK_TRAP_GROUP_GENERIC_ID_##_id,		      \
95178c2ecf20Sopenharmony_ci		.name = DEVLINK_TRAP_GROUP_GENERIC_NAME_##_id,		      \
95188c2ecf20Sopenharmony_ci	}
95198c2ecf20Sopenharmony_ci
95208c2ecf20Sopenharmony_cistatic const struct devlink_trap_group devlink_trap_group_generic[] = {
95218c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(L2_DROPS),
95228c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(L3_DROPS),
95238c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(L3_EXCEPTIONS),
95248c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(BUFFER_DROPS),
95258c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(TUNNEL_DROPS),
95268c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(ACL_DROPS),
95278c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(STP),
95288c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(LACP),
95298c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(LLDP),
95308c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(MC_SNOOPING),
95318c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(DHCP),
95328c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(NEIGH_DISCOVERY),
95338c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(BFD),
95348c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(OSPF),
95358c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(BGP),
95368c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(VRRP),
95378c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(PIM),
95388c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(UC_LB),
95398c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(LOCAL_DELIVERY),
95408c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(EXTERNAL_DELIVERY),
95418c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(IPV6),
95428c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(PTP_EVENT),
95438c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(PTP_GENERAL),
95448c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(ACL_SAMPLE),
95458c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(ACL_TRAP),
95468c2ecf20Sopenharmony_ci	DEVLINK_TRAP_GROUP(PARSER_ERROR_DROPS),
95478c2ecf20Sopenharmony_ci};
95488c2ecf20Sopenharmony_ci
95498c2ecf20Sopenharmony_cistatic int devlink_trap_generic_verify(const struct devlink_trap *trap)
95508c2ecf20Sopenharmony_ci{
95518c2ecf20Sopenharmony_ci	if (trap->id > DEVLINK_TRAP_GENERIC_ID_MAX)
95528c2ecf20Sopenharmony_ci		return -EINVAL;
95538c2ecf20Sopenharmony_ci
95548c2ecf20Sopenharmony_ci	if (strcmp(trap->name, devlink_trap_generic[trap->id].name))
95558c2ecf20Sopenharmony_ci		return -EINVAL;
95568c2ecf20Sopenharmony_ci
95578c2ecf20Sopenharmony_ci	if (trap->type != devlink_trap_generic[trap->id].type)
95588c2ecf20Sopenharmony_ci		return -EINVAL;
95598c2ecf20Sopenharmony_ci
95608c2ecf20Sopenharmony_ci	return 0;
95618c2ecf20Sopenharmony_ci}
95628c2ecf20Sopenharmony_ci
95638c2ecf20Sopenharmony_cistatic int devlink_trap_driver_verify(const struct devlink_trap *trap)
95648c2ecf20Sopenharmony_ci{
95658c2ecf20Sopenharmony_ci	int i;
95668c2ecf20Sopenharmony_ci
95678c2ecf20Sopenharmony_ci	if (trap->id <= DEVLINK_TRAP_GENERIC_ID_MAX)
95688c2ecf20Sopenharmony_ci		return -EINVAL;
95698c2ecf20Sopenharmony_ci
95708c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(devlink_trap_generic); i++) {
95718c2ecf20Sopenharmony_ci		if (!strcmp(trap->name, devlink_trap_generic[i].name))
95728c2ecf20Sopenharmony_ci			return -EEXIST;
95738c2ecf20Sopenharmony_ci	}
95748c2ecf20Sopenharmony_ci
95758c2ecf20Sopenharmony_ci	return 0;
95768c2ecf20Sopenharmony_ci}
95778c2ecf20Sopenharmony_ci
95788c2ecf20Sopenharmony_cistatic int devlink_trap_verify(const struct devlink_trap *trap)
95798c2ecf20Sopenharmony_ci{
95808c2ecf20Sopenharmony_ci	if (!trap || !trap->name)
95818c2ecf20Sopenharmony_ci		return -EINVAL;
95828c2ecf20Sopenharmony_ci
95838c2ecf20Sopenharmony_ci	if (trap->generic)
95848c2ecf20Sopenharmony_ci		return devlink_trap_generic_verify(trap);
95858c2ecf20Sopenharmony_ci	else
95868c2ecf20Sopenharmony_ci		return devlink_trap_driver_verify(trap);
95878c2ecf20Sopenharmony_ci}
95888c2ecf20Sopenharmony_ci
95898c2ecf20Sopenharmony_cistatic int
95908c2ecf20Sopenharmony_cidevlink_trap_group_generic_verify(const struct devlink_trap_group *group)
95918c2ecf20Sopenharmony_ci{
95928c2ecf20Sopenharmony_ci	if (group->id > DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
95938c2ecf20Sopenharmony_ci		return -EINVAL;
95948c2ecf20Sopenharmony_ci
95958c2ecf20Sopenharmony_ci	if (strcmp(group->name, devlink_trap_group_generic[group->id].name))
95968c2ecf20Sopenharmony_ci		return -EINVAL;
95978c2ecf20Sopenharmony_ci
95988c2ecf20Sopenharmony_ci	return 0;
95998c2ecf20Sopenharmony_ci}
96008c2ecf20Sopenharmony_ci
96018c2ecf20Sopenharmony_cistatic int
96028c2ecf20Sopenharmony_cidevlink_trap_group_driver_verify(const struct devlink_trap_group *group)
96038c2ecf20Sopenharmony_ci{
96048c2ecf20Sopenharmony_ci	int i;
96058c2ecf20Sopenharmony_ci
96068c2ecf20Sopenharmony_ci	if (group->id <= DEVLINK_TRAP_GROUP_GENERIC_ID_MAX)
96078c2ecf20Sopenharmony_ci		return -EINVAL;
96088c2ecf20Sopenharmony_ci
96098c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(devlink_trap_group_generic); i++) {
96108c2ecf20Sopenharmony_ci		if (!strcmp(group->name, devlink_trap_group_generic[i].name))
96118c2ecf20Sopenharmony_ci			return -EEXIST;
96128c2ecf20Sopenharmony_ci	}
96138c2ecf20Sopenharmony_ci
96148c2ecf20Sopenharmony_ci	return 0;
96158c2ecf20Sopenharmony_ci}
96168c2ecf20Sopenharmony_ci
96178c2ecf20Sopenharmony_cistatic int devlink_trap_group_verify(const struct devlink_trap_group *group)
96188c2ecf20Sopenharmony_ci{
96198c2ecf20Sopenharmony_ci	if (group->generic)
96208c2ecf20Sopenharmony_ci		return devlink_trap_group_generic_verify(group);
96218c2ecf20Sopenharmony_ci	else
96228c2ecf20Sopenharmony_ci		return devlink_trap_group_driver_verify(group);
96238c2ecf20Sopenharmony_ci}
96248c2ecf20Sopenharmony_ci
96258c2ecf20Sopenharmony_cistatic void
96268c2ecf20Sopenharmony_cidevlink_trap_group_notify(struct devlink *devlink,
96278c2ecf20Sopenharmony_ci			  const struct devlink_trap_group_item *group_item,
96288c2ecf20Sopenharmony_ci			  enum devlink_command cmd)
96298c2ecf20Sopenharmony_ci{
96308c2ecf20Sopenharmony_ci	struct sk_buff *msg;
96318c2ecf20Sopenharmony_ci	int err;
96328c2ecf20Sopenharmony_ci
96338c2ecf20Sopenharmony_ci	WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_GROUP_NEW &&
96348c2ecf20Sopenharmony_ci		     cmd != DEVLINK_CMD_TRAP_GROUP_DEL);
96358c2ecf20Sopenharmony_ci
96368c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
96378c2ecf20Sopenharmony_ci	if (!msg)
96388c2ecf20Sopenharmony_ci		return;
96398c2ecf20Sopenharmony_ci
96408c2ecf20Sopenharmony_ci	err = devlink_nl_trap_group_fill(msg, devlink, group_item, cmd, 0, 0,
96418c2ecf20Sopenharmony_ci					 0);
96428c2ecf20Sopenharmony_ci	if (err) {
96438c2ecf20Sopenharmony_ci		nlmsg_free(msg);
96448c2ecf20Sopenharmony_ci		return;
96458c2ecf20Sopenharmony_ci	}
96468c2ecf20Sopenharmony_ci
96478c2ecf20Sopenharmony_ci	genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
96488c2ecf20Sopenharmony_ci				msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
96498c2ecf20Sopenharmony_ci}
96508c2ecf20Sopenharmony_ci
96518c2ecf20Sopenharmony_cistatic int
96528c2ecf20Sopenharmony_cidevlink_trap_item_group_link(struct devlink *devlink,
96538c2ecf20Sopenharmony_ci			     struct devlink_trap_item *trap_item)
96548c2ecf20Sopenharmony_ci{
96558c2ecf20Sopenharmony_ci	u16 group_id = trap_item->trap->init_group_id;
96568c2ecf20Sopenharmony_ci	struct devlink_trap_group_item *group_item;
96578c2ecf20Sopenharmony_ci
96588c2ecf20Sopenharmony_ci	group_item = devlink_trap_group_item_lookup_by_id(devlink, group_id);
96598c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(!group_item))
96608c2ecf20Sopenharmony_ci		return -EINVAL;
96618c2ecf20Sopenharmony_ci
96628c2ecf20Sopenharmony_ci	trap_item->group_item = group_item;
96638c2ecf20Sopenharmony_ci
96648c2ecf20Sopenharmony_ci	return 0;
96658c2ecf20Sopenharmony_ci}
96668c2ecf20Sopenharmony_ci
96678c2ecf20Sopenharmony_cistatic void devlink_trap_notify(struct devlink *devlink,
96688c2ecf20Sopenharmony_ci				const struct devlink_trap_item *trap_item,
96698c2ecf20Sopenharmony_ci				enum devlink_command cmd)
96708c2ecf20Sopenharmony_ci{
96718c2ecf20Sopenharmony_ci	struct sk_buff *msg;
96728c2ecf20Sopenharmony_ci	int err;
96738c2ecf20Sopenharmony_ci
96748c2ecf20Sopenharmony_ci	WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_NEW &&
96758c2ecf20Sopenharmony_ci		     cmd != DEVLINK_CMD_TRAP_DEL);
96768c2ecf20Sopenharmony_ci
96778c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
96788c2ecf20Sopenharmony_ci	if (!msg)
96798c2ecf20Sopenharmony_ci		return;
96808c2ecf20Sopenharmony_ci
96818c2ecf20Sopenharmony_ci	err = devlink_nl_trap_fill(msg, devlink, trap_item, cmd, 0, 0, 0);
96828c2ecf20Sopenharmony_ci	if (err) {
96838c2ecf20Sopenharmony_ci		nlmsg_free(msg);
96848c2ecf20Sopenharmony_ci		return;
96858c2ecf20Sopenharmony_ci	}
96868c2ecf20Sopenharmony_ci
96878c2ecf20Sopenharmony_ci	genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
96888c2ecf20Sopenharmony_ci				msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
96898c2ecf20Sopenharmony_ci}
96908c2ecf20Sopenharmony_ci
96918c2ecf20Sopenharmony_cistatic int
96928c2ecf20Sopenharmony_cidevlink_trap_register(struct devlink *devlink,
96938c2ecf20Sopenharmony_ci		      const struct devlink_trap *trap, void *priv)
96948c2ecf20Sopenharmony_ci{
96958c2ecf20Sopenharmony_ci	struct devlink_trap_item *trap_item;
96968c2ecf20Sopenharmony_ci	int err;
96978c2ecf20Sopenharmony_ci
96988c2ecf20Sopenharmony_ci	if (devlink_trap_item_lookup(devlink, trap->name))
96998c2ecf20Sopenharmony_ci		return -EEXIST;
97008c2ecf20Sopenharmony_ci
97018c2ecf20Sopenharmony_ci	trap_item = kzalloc(sizeof(*trap_item), GFP_KERNEL);
97028c2ecf20Sopenharmony_ci	if (!trap_item)
97038c2ecf20Sopenharmony_ci		return -ENOMEM;
97048c2ecf20Sopenharmony_ci
97058c2ecf20Sopenharmony_ci	trap_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
97068c2ecf20Sopenharmony_ci	if (!trap_item->stats) {
97078c2ecf20Sopenharmony_ci		err = -ENOMEM;
97088c2ecf20Sopenharmony_ci		goto err_stats_alloc;
97098c2ecf20Sopenharmony_ci	}
97108c2ecf20Sopenharmony_ci
97118c2ecf20Sopenharmony_ci	trap_item->trap = trap;
97128c2ecf20Sopenharmony_ci	trap_item->action = trap->init_action;
97138c2ecf20Sopenharmony_ci	trap_item->priv = priv;
97148c2ecf20Sopenharmony_ci
97158c2ecf20Sopenharmony_ci	err = devlink_trap_item_group_link(devlink, trap_item);
97168c2ecf20Sopenharmony_ci	if (err)
97178c2ecf20Sopenharmony_ci		goto err_group_link;
97188c2ecf20Sopenharmony_ci
97198c2ecf20Sopenharmony_ci	err = devlink->ops->trap_init(devlink, trap, trap_item);
97208c2ecf20Sopenharmony_ci	if (err)
97218c2ecf20Sopenharmony_ci		goto err_trap_init;
97228c2ecf20Sopenharmony_ci
97238c2ecf20Sopenharmony_ci	list_add_tail(&trap_item->list, &devlink->trap_list);
97248c2ecf20Sopenharmony_ci	devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_NEW);
97258c2ecf20Sopenharmony_ci
97268c2ecf20Sopenharmony_ci	return 0;
97278c2ecf20Sopenharmony_ci
97288c2ecf20Sopenharmony_cierr_trap_init:
97298c2ecf20Sopenharmony_cierr_group_link:
97308c2ecf20Sopenharmony_ci	free_percpu(trap_item->stats);
97318c2ecf20Sopenharmony_cierr_stats_alloc:
97328c2ecf20Sopenharmony_ci	kfree(trap_item);
97338c2ecf20Sopenharmony_ci	return err;
97348c2ecf20Sopenharmony_ci}
97358c2ecf20Sopenharmony_ci
97368c2ecf20Sopenharmony_cistatic void devlink_trap_unregister(struct devlink *devlink,
97378c2ecf20Sopenharmony_ci				    const struct devlink_trap *trap)
97388c2ecf20Sopenharmony_ci{
97398c2ecf20Sopenharmony_ci	struct devlink_trap_item *trap_item;
97408c2ecf20Sopenharmony_ci
97418c2ecf20Sopenharmony_ci	trap_item = devlink_trap_item_lookup(devlink, trap->name);
97428c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(!trap_item))
97438c2ecf20Sopenharmony_ci		return;
97448c2ecf20Sopenharmony_ci
97458c2ecf20Sopenharmony_ci	devlink_trap_notify(devlink, trap_item, DEVLINK_CMD_TRAP_DEL);
97468c2ecf20Sopenharmony_ci	list_del(&trap_item->list);
97478c2ecf20Sopenharmony_ci	if (devlink->ops->trap_fini)
97488c2ecf20Sopenharmony_ci		devlink->ops->trap_fini(devlink, trap, trap_item);
97498c2ecf20Sopenharmony_ci	free_percpu(trap_item->stats);
97508c2ecf20Sopenharmony_ci	kfree(trap_item);
97518c2ecf20Sopenharmony_ci}
97528c2ecf20Sopenharmony_ci
97538c2ecf20Sopenharmony_cistatic void devlink_trap_disable(struct devlink *devlink,
97548c2ecf20Sopenharmony_ci				 const struct devlink_trap *trap)
97558c2ecf20Sopenharmony_ci{
97568c2ecf20Sopenharmony_ci	struct devlink_trap_item *trap_item;
97578c2ecf20Sopenharmony_ci
97588c2ecf20Sopenharmony_ci	trap_item = devlink_trap_item_lookup(devlink, trap->name);
97598c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(!trap_item))
97608c2ecf20Sopenharmony_ci		return;
97618c2ecf20Sopenharmony_ci
97628c2ecf20Sopenharmony_ci	devlink->ops->trap_action_set(devlink, trap, DEVLINK_TRAP_ACTION_DROP,
97638c2ecf20Sopenharmony_ci				      NULL);
97648c2ecf20Sopenharmony_ci	trap_item->action = DEVLINK_TRAP_ACTION_DROP;
97658c2ecf20Sopenharmony_ci}
97668c2ecf20Sopenharmony_ci
97678c2ecf20Sopenharmony_ci/**
97688c2ecf20Sopenharmony_ci * devlink_traps_register - Register packet traps with devlink.
97698c2ecf20Sopenharmony_ci * @devlink: devlink.
97708c2ecf20Sopenharmony_ci * @traps: Packet traps.
97718c2ecf20Sopenharmony_ci * @traps_count: Count of provided packet traps.
97728c2ecf20Sopenharmony_ci * @priv: Driver private information.
97738c2ecf20Sopenharmony_ci *
97748c2ecf20Sopenharmony_ci * Return: Non-zero value on failure.
97758c2ecf20Sopenharmony_ci */
97768c2ecf20Sopenharmony_ciint devlink_traps_register(struct devlink *devlink,
97778c2ecf20Sopenharmony_ci			   const struct devlink_trap *traps,
97788c2ecf20Sopenharmony_ci			   size_t traps_count, void *priv)
97798c2ecf20Sopenharmony_ci{
97808c2ecf20Sopenharmony_ci	int i, err;
97818c2ecf20Sopenharmony_ci
97828c2ecf20Sopenharmony_ci	if (!devlink->ops->trap_init || !devlink->ops->trap_action_set)
97838c2ecf20Sopenharmony_ci		return -EINVAL;
97848c2ecf20Sopenharmony_ci
97858c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
97868c2ecf20Sopenharmony_ci	for (i = 0; i < traps_count; i++) {
97878c2ecf20Sopenharmony_ci		const struct devlink_trap *trap = &traps[i];
97888c2ecf20Sopenharmony_ci
97898c2ecf20Sopenharmony_ci		err = devlink_trap_verify(trap);
97908c2ecf20Sopenharmony_ci		if (err)
97918c2ecf20Sopenharmony_ci			goto err_trap_verify;
97928c2ecf20Sopenharmony_ci
97938c2ecf20Sopenharmony_ci		err = devlink_trap_register(devlink, trap, priv);
97948c2ecf20Sopenharmony_ci		if (err)
97958c2ecf20Sopenharmony_ci			goto err_trap_register;
97968c2ecf20Sopenharmony_ci	}
97978c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
97988c2ecf20Sopenharmony_ci
97998c2ecf20Sopenharmony_ci	return 0;
98008c2ecf20Sopenharmony_ci
98018c2ecf20Sopenharmony_cierr_trap_register:
98028c2ecf20Sopenharmony_cierr_trap_verify:
98038c2ecf20Sopenharmony_ci	for (i--; i >= 0; i--)
98048c2ecf20Sopenharmony_ci		devlink_trap_unregister(devlink, &traps[i]);
98058c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
98068c2ecf20Sopenharmony_ci	return err;
98078c2ecf20Sopenharmony_ci}
98088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_traps_register);
98098c2ecf20Sopenharmony_ci
98108c2ecf20Sopenharmony_ci/**
98118c2ecf20Sopenharmony_ci * devlink_traps_unregister - Unregister packet traps from devlink.
98128c2ecf20Sopenharmony_ci * @devlink: devlink.
98138c2ecf20Sopenharmony_ci * @traps: Packet traps.
98148c2ecf20Sopenharmony_ci * @traps_count: Count of provided packet traps.
98158c2ecf20Sopenharmony_ci */
98168c2ecf20Sopenharmony_civoid devlink_traps_unregister(struct devlink *devlink,
98178c2ecf20Sopenharmony_ci			      const struct devlink_trap *traps,
98188c2ecf20Sopenharmony_ci			      size_t traps_count)
98198c2ecf20Sopenharmony_ci{
98208c2ecf20Sopenharmony_ci	int i;
98218c2ecf20Sopenharmony_ci
98228c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
98238c2ecf20Sopenharmony_ci	/* Make sure we do not have any packets in-flight while unregistering
98248c2ecf20Sopenharmony_ci	 * traps by disabling all of them and waiting for a grace period.
98258c2ecf20Sopenharmony_ci	 */
98268c2ecf20Sopenharmony_ci	for (i = traps_count - 1; i >= 0; i--)
98278c2ecf20Sopenharmony_ci		devlink_trap_disable(devlink, &traps[i]);
98288c2ecf20Sopenharmony_ci	synchronize_rcu();
98298c2ecf20Sopenharmony_ci	for (i = traps_count - 1; i >= 0; i--)
98308c2ecf20Sopenharmony_ci		devlink_trap_unregister(devlink, &traps[i]);
98318c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
98328c2ecf20Sopenharmony_ci}
98338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_traps_unregister);
98348c2ecf20Sopenharmony_ci
98358c2ecf20Sopenharmony_cistatic void
98368c2ecf20Sopenharmony_cidevlink_trap_stats_update(struct devlink_stats __percpu *trap_stats,
98378c2ecf20Sopenharmony_ci			  size_t skb_len)
98388c2ecf20Sopenharmony_ci{
98398c2ecf20Sopenharmony_ci	struct devlink_stats *stats;
98408c2ecf20Sopenharmony_ci
98418c2ecf20Sopenharmony_ci	stats = this_cpu_ptr(trap_stats);
98428c2ecf20Sopenharmony_ci	u64_stats_update_begin(&stats->syncp);
98438c2ecf20Sopenharmony_ci	stats->rx_bytes += skb_len;
98448c2ecf20Sopenharmony_ci	stats->rx_packets++;
98458c2ecf20Sopenharmony_ci	u64_stats_update_end(&stats->syncp);
98468c2ecf20Sopenharmony_ci}
98478c2ecf20Sopenharmony_ci
98488c2ecf20Sopenharmony_cistatic void
98498c2ecf20Sopenharmony_cidevlink_trap_report_metadata_set(struct devlink_trap_metadata *metadata,
98508c2ecf20Sopenharmony_ci				 const struct devlink_trap_item *trap_item,
98518c2ecf20Sopenharmony_ci				 struct devlink_port *in_devlink_port,
98528c2ecf20Sopenharmony_ci				 const struct flow_action_cookie *fa_cookie)
98538c2ecf20Sopenharmony_ci{
98548c2ecf20Sopenharmony_ci	metadata->trap_name = trap_item->trap->name;
98558c2ecf20Sopenharmony_ci	metadata->trap_group_name = trap_item->group_item->group->name;
98568c2ecf20Sopenharmony_ci	metadata->fa_cookie = fa_cookie;
98578c2ecf20Sopenharmony_ci	metadata->trap_type = trap_item->trap->type;
98588c2ecf20Sopenharmony_ci
98598c2ecf20Sopenharmony_ci	spin_lock(&in_devlink_port->type_lock);
98608c2ecf20Sopenharmony_ci	if (in_devlink_port->type == DEVLINK_PORT_TYPE_ETH)
98618c2ecf20Sopenharmony_ci		metadata->input_dev = in_devlink_port->type_dev;
98628c2ecf20Sopenharmony_ci	spin_unlock(&in_devlink_port->type_lock);
98638c2ecf20Sopenharmony_ci}
98648c2ecf20Sopenharmony_ci
98658c2ecf20Sopenharmony_ci/**
98668c2ecf20Sopenharmony_ci * devlink_trap_report - Report trapped packet to drop monitor.
98678c2ecf20Sopenharmony_ci * @devlink: devlink.
98688c2ecf20Sopenharmony_ci * @skb: Trapped packet.
98698c2ecf20Sopenharmony_ci * @trap_ctx: Trap context.
98708c2ecf20Sopenharmony_ci * @in_devlink_port: Input devlink port.
98718c2ecf20Sopenharmony_ci * @fa_cookie: Flow action cookie. Could be NULL.
98728c2ecf20Sopenharmony_ci */
98738c2ecf20Sopenharmony_civoid devlink_trap_report(struct devlink *devlink, struct sk_buff *skb,
98748c2ecf20Sopenharmony_ci			 void *trap_ctx, struct devlink_port *in_devlink_port,
98758c2ecf20Sopenharmony_ci			 const struct flow_action_cookie *fa_cookie)
98768c2ecf20Sopenharmony_ci
98778c2ecf20Sopenharmony_ci{
98788c2ecf20Sopenharmony_ci	struct devlink_trap_item *trap_item = trap_ctx;
98798c2ecf20Sopenharmony_ci
98808c2ecf20Sopenharmony_ci	devlink_trap_stats_update(trap_item->stats, skb->len);
98818c2ecf20Sopenharmony_ci	devlink_trap_stats_update(trap_item->group_item->stats, skb->len);
98828c2ecf20Sopenharmony_ci
98838c2ecf20Sopenharmony_ci	if (trace_devlink_trap_report_enabled()) {
98848c2ecf20Sopenharmony_ci		struct devlink_trap_metadata metadata = {};
98858c2ecf20Sopenharmony_ci
98868c2ecf20Sopenharmony_ci		devlink_trap_report_metadata_set(&metadata, trap_item,
98878c2ecf20Sopenharmony_ci						 in_devlink_port, fa_cookie);
98888c2ecf20Sopenharmony_ci		trace_devlink_trap_report(devlink, skb, &metadata);
98898c2ecf20Sopenharmony_ci	}
98908c2ecf20Sopenharmony_ci}
98918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_trap_report);
98928c2ecf20Sopenharmony_ci
98938c2ecf20Sopenharmony_ci/**
98948c2ecf20Sopenharmony_ci * devlink_trap_ctx_priv - Trap context to driver private information.
98958c2ecf20Sopenharmony_ci * @trap_ctx: Trap context.
98968c2ecf20Sopenharmony_ci *
98978c2ecf20Sopenharmony_ci * Return: Driver private information passed during registration.
98988c2ecf20Sopenharmony_ci */
98998c2ecf20Sopenharmony_civoid *devlink_trap_ctx_priv(void *trap_ctx)
99008c2ecf20Sopenharmony_ci{
99018c2ecf20Sopenharmony_ci	struct devlink_trap_item *trap_item = trap_ctx;
99028c2ecf20Sopenharmony_ci
99038c2ecf20Sopenharmony_ci	return trap_item->priv;
99048c2ecf20Sopenharmony_ci}
99058c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_trap_ctx_priv);
99068c2ecf20Sopenharmony_ci
99078c2ecf20Sopenharmony_cistatic int
99088c2ecf20Sopenharmony_cidevlink_trap_group_item_policer_link(struct devlink *devlink,
99098c2ecf20Sopenharmony_ci				     struct devlink_trap_group_item *group_item)
99108c2ecf20Sopenharmony_ci{
99118c2ecf20Sopenharmony_ci	u32 policer_id = group_item->group->init_policer_id;
99128c2ecf20Sopenharmony_ci	struct devlink_trap_policer_item *policer_item;
99138c2ecf20Sopenharmony_ci
99148c2ecf20Sopenharmony_ci	if (policer_id == 0)
99158c2ecf20Sopenharmony_ci		return 0;
99168c2ecf20Sopenharmony_ci
99178c2ecf20Sopenharmony_ci	policer_item = devlink_trap_policer_item_lookup(devlink, policer_id);
99188c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(!policer_item))
99198c2ecf20Sopenharmony_ci		return -EINVAL;
99208c2ecf20Sopenharmony_ci
99218c2ecf20Sopenharmony_ci	group_item->policer_item = policer_item;
99228c2ecf20Sopenharmony_ci
99238c2ecf20Sopenharmony_ci	return 0;
99248c2ecf20Sopenharmony_ci}
99258c2ecf20Sopenharmony_ci
99268c2ecf20Sopenharmony_cistatic int
99278c2ecf20Sopenharmony_cidevlink_trap_group_register(struct devlink *devlink,
99288c2ecf20Sopenharmony_ci			    const struct devlink_trap_group *group)
99298c2ecf20Sopenharmony_ci{
99308c2ecf20Sopenharmony_ci	struct devlink_trap_group_item *group_item;
99318c2ecf20Sopenharmony_ci	int err;
99328c2ecf20Sopenharmony_ci
99338c2ecf20Sopenharmony_ci	if (devlink_trap_group_item_lookup(devlink, group->name))
99348c2ecf20Sopenharmony_ci		return -EEXIST;
99358c2ecf20Sopenharmony_ci
99368c2ecf20Sopenharmony_ci	group_item = kzalloc(sizeof(*group_item), GFP_KERNEL);
99378c2ecf20Sopenharmony_ci	if (!group_item)
99388c2ecf20Sopenharmony_ci		return -ENOMEM;
99398c2ecf20Sopenharmony_ci
99408c2ecf20Sopenharmony_ci	group_item->stats = netdev_alloc_pcpu_stats(struct devlink_stats);
99418c2ecf20Sopenharmony_ci	if (!group_item->stats) {
99428c2ecf20Sopenharmony_ci		err = -ENOMEM;
99438c2ecf20Sopenharmony_ci		goto err_stats_alloc;
99448c2ecf20Sopenharmony_ci	}
99458c2ecf20Sopenharmony_ci
99468c2ecf20Sopenharmony_ci	group_item->group = group;
99478c2ecf20Sopenharmony_ci
99488c2ecf20Sopenharmony_ci	err = devlink_trap_group_item_policer_link(devlink, group_item);
99498c2ecf20Sopenharmony_ci	if (err)
99508c2ecf20Sopenharmony_ci		goto err_policer_link;
99518c2ecf20Sopenharmony_ci
99528c2ecf20Sopenharmony_ci	if (devlink->ops->trap_group_init) {
99538c2ecf20Sopenharmony_ci		err = devlink->ops->trap_group_init(devlink, group);
99548c2ecf20Sopenharmony_ci		if (err)
99558c2ecf20Sopenharmony_ci			goto err_group_init;
99568c2ecf20Sopenharmony_ci	}
99578c2ecf20Sopenharmony_ci
99588c2ecf20Sopenharmony_ci	list_add_tail(&group_item->list, &devlink->trap_group_list);
99598c2ecf20Sopenharmony_ci	devlink_trap_group_notify(devlink, group_item,
99608c2ecf20Sopenharmony_ci				  DEVLINK_CMD_TRAP_GROUP_NEW);
99618c2ecf20Sopenharmony_ci
99628c2ecf20Sopenharmony_ci	return 0;
99638c2ecf20Sopenharmony_ci
99648c2ecf20Sopenharmony_cierr_group_init:
99658c2ecf20Sopenharmony_cierr_policer_link:
99668c2ecf20Sopenharmony_ci	free_percpu(group_item->stats);
99678c2ecf20Sopenharmony_cierr_stats_alloc:
99688c2ecf20Sopenharmony_ci	kfree(group_item);
99698c2ecf20Sopenharmony_ci	return err;
99708c2ecf20Sopenharmony_ci}
99718c2ecf20Sopenharmony_ci
99728c2ecf20Sopenharmony_cistatic void
99738c2ecf20Sopenharmony_cidevlink_trap_group_unregister(struct devlink *devlink,
99748c2ecf20Sopenharmony_ci			      const struct devlink_trap_group *group)
99758c2ecf20Sopenharmony_ci{
99768c2ecf20Sopenharmony_ci	struct devlink_trap_group_item *group_item;
99778c2ecf20Sopenharmony_ci
99788c2ecf20Sopenharmony_ci	group_item = devlink_trap_group_item_lookup(devlink, group->name);
99798c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(!group_item))
99808c2ecf20Sopenharmony_ci		return;
99818c2ecf20Sopenharmony_ci
99828c2ecf20Sopenharmony_ci	devlink_trap_group_notify(devlink, group_item,
99838c2ecf20Sopenharmony_ci				  DEVLINK_CMD_TRAP_GROUP_DEL);
99848c2ecf20Sopenharmony_ci	list_del(&group_item->list);
99858c2ecf20Sopenharmony_ci	free_percpu(group_item->stats);
99868c2ecf20Sopenharmony_ci	kfree(group_item);
99878c2ecf20Sopenharmony_ci}
99888c2ecf20Sopenharmony_ci
99898c2ecf20Sopenharmony_ci/**
99908c2ecf20Sopenharmony_ci * devlink_trap_groups_register - Register packet trap groups with devlink.
99918c2ecf20Sopenharmony_ci * @devlink: devlink.
99928c2ecf20Sopenharmony_ci * @groups: Packet trap groups.
99938c2ecf20Sopenharmony_ci * @groups_count: Count of provided packet trap groups.
99948c2ecf20Sopenharmony_ci *
99958c2ecf20Sopenharmony_ci * Return: Non-zero value on failure.
99968c2ecf20Sopenharmony_ci */
99978c2ecf20Sopenharmony_ciint devlink_trap_groups_register(struct devlink *devlink,
99988c2ecf20Sopenharmony_ci				 const struct devlink_trap_group *groups,
99998c2ecf20Sopenharmony_ci				 size_t groups_count)
100008c2ecf20Sopenharmony_ci{
100018c2ecf20Sopenharmony_ci	int i, err;
100028c2ecf20Sopenharmony_ci
100038c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
100048c2ecf20Sopenharmony_ci	for (i = 0; i < groups_count; i++) {
100058c2ecf20Sopenharmony_ci		const struct devlink_trap_group *group = &groups[i];
100068c2ecf20Sopenharmony_ci
100078c2ecf20Sopenharmony_ci		err = devlink_trap_group_verify(group);
100088c2ecf20Sopenharmony_ci		if (err)
100098c2ecf20Sopenharmony_ci			goto err_trap_group_verify;
100108c2ecf20Sopenharmony_ci
100118c2ecf20Sopenharmony_ci		err = devlink_trap_group_register(devlink, group);
100128c2ecf20Sopenharmony_ci		if (err)
100138c2ecf20Sopenharmony_ci			goto err_trap_group_register;
100148c2ecf20Sopenharmony_ci	}
100158c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
100168c2ecf20Sopenharmony_ci
100178c2ecf20Sopenharmony_ci	return 0;
100188c2ecf20Sopenharmony_ci
100198c2ecf20Sopenharmony_cierr_trap_group_register:
100208c2ecf20Sopenharmony_cierr_trap_group_verify:
100218c2ecf20Sopenharmony_ci	for (i--; i >= 0; i--)
100228c2ecf20Sopenharmony_ci		devlink_trap_group_unregister(devlink, &groups[i]);
100238c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
100248c2ecf20Sopenharmony_ci	return err;
100258c2ecf20Sopenharmony_ci}
100268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_trap_groups_register);
100278c2ecf20Sopenharmony_ci
100288c2ecf20Sopenharmony_ci/**
100298c2ecf20Sopenharmony_ci * devlink_trap_groups_unregister - Unregister packet trap groups from devlink.
100308c2ecf20Sopenharmony_ci * @devlink: devlink.
100318c2ecf20Sopenharmony_ci * @groups: Packet trap groups.
100328c2ecf20Sopenharmony_ci * @groups_count: Count of provided packet trap groups.
100338c2ecf20Sopenharmony_ci */
100348c2ecf20Sopenharmony_civoid devlink_trap_groups_unregister(struct devlink *devlink,
100358c2ecf20Sopenharmony_ci				    const struct devlink_trap_group *groups,
100368c2ecf20Sopenharmony_ci				    size_t groups_count)
100378c2ecf20Sopenharmony_ci{
100388c2ecf20Sopenharmony_ci	int i;
100398c2ecf20Sopenharmony_ci
100408c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
100418c2ecf20Sopenharmony_ci	for (i = groups_count - 1; i >= 0; i--)
100428c2ecf20Sopenharmony_ci		devlink_trap_group_unregister(devlink, &groups[i]);
100438c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
100448c2ecf20Sopenharmony_ci}
100458c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_trap_groups_unregister);
100468c2ecf20Sopenharmony_ci
100478c2ecf20Sopenharmony_cistatic void
100488c2ecf20Sopenharmony_cidevlink_trap_policer_notify(struct devlink *devlink,
100498c2ecf20Sopenharmony_ci			    const struct devlink_trap_policer_item *policer_item,
100508c2ecf20Sopenharmony_ci			    enum devlink_command cmd)
100518c2ecf20Sopenharmony_ci{
100528c2ecf20Sopenharmony_ci	struct sk_buff *msg;
100538c2ecf20Sopenharmony_ci	int err;
100548c2ecf20Sopenharmony_ci
100558c2ecf20Sopenharmony_ci	WARN_ON_ONCE(cmd != DEVLINK_CMD_TRAP_POLICER_NEW &&
100568c2ecf20Sopenharmony_ci		     cmd != DEVLINK_CMD_TRAP_POLICER_DEL);
100578c2ecf20Sopenharmony_ci
100588c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
100598c2ecf20Sopenharmony_ci	if (!msg)
100608c2ecf20Sopenharmony_ci		return;
100618c2ecf20Sopenharmony_ci
100628c2ecf20Sopenharmony_ci	err = devlink_nl_trap_policer_fill(msg, devlink, policer_item, cmd, 0,
100638c2ecf20Sopenharmony_ci					   0, 0);
100648c2ecf20Sopenharmony_ci	if (err) {
100658c2ecf20Sopenharmony_ci		nlmsg_free(msg);
100668c2ecf20Sopenharmony_ci		return;
100678c2ecf20Sopenharmony_ci	}
100688c2ecf20Sopenharmony_ci
100698c2ecf20Sopenharmony_ci	genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
100708c2ecf20Sopenharmony_ci				msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
100718c2ecf20Sopenharmony_ci}
100728c2ecf20Sopenharmony_ci
100738c2ecf20Sopenharmony_cistatic int
100748c2ecf20Sopenharmony_cidevlink_trap_policer_register(struct devlink *devlink,
100758c2ecf20Sopenharmony_ci			      const struct devlink_trap_policer *policer)
100768c2ecf20Sopenharmony_ci{
100778c2ecf20Sopenharmony_ci	struct devlink_trap_policer_item *policer_item;
100788c2ecf20Sopenharmony_ci	int err;
100798c2ecf20Sopenharmony_ci
100808c2ecf20Sopenharmony_ci	if (devlink_trap_policer_item_lookup(devlink, policer->id))
100818c2ecf20Sopenharmony_ci		return -EEXIST;
100828c2ecf20Sopenharmony_ci
100838c2ecf20Sopenharmony_ci	policer_item = kzalloc(sizeof(*policer_item), GFP_KERNEL);
100848c2ecf20Sopenharmony_ci	if (!policer_item)
100858c2ecf20Sopenharmony_ci		return -ENOMEM;
100868c2ecf20Sopenharmony_ci
100878c2ecf20Sopenharmony_ci	policer_item->policer = policer;
100888c2ecf20Sopenharmony_ci	policer_item->rate = policer->init_rate;
100898c2ecf20Sopenharmony_ci	policer_item->burst = policer->init_burst;
100908c2ecf20Sopenharmony_ci
100918c2ecf20Sopenharmony_ci	if (devlink->ops->trap_policer_init) {
100928c2ecf20Sopenharmony_ci		err = devlink->ops->trap_policer_init(devlink, policer);
100938c2ecf20Sopenharmony_ci		if (err)
100948c2ecf20Sopenharmony_ci			goto err_policer_init;
100958c2ecf20Sopenharmony_ci	}
100968c2ecf20Sopenharmony_ci
100978c2ecf20Sopenharmony_ci	list_add_tail(&policer_item->list, &devlink->trap_policer_list);
100988c2ecf20Sopenharmony_ci	devlink_trap_policer_notify(devlink, policer_item,
100998c2ecf20Sopenharmony_ci				    DEVLINK_CMD_TRAP_POLICER_NEW);
101008c2ecf20Sopenharmony_ci
101018c2ecf20Sopenharmony_ci	return 0;
101028c2ecf20Sopenharmony_ci
101038c2ecf20Sopenharmony_cierr_policer_init:
101048c2ecf20Sopenharmony_ci	kfree(policer_item);
101058c2ecf20Sopenharmony_ci	return err;
101068c2ecf20Sopenharmony_ci}
101078c2ecf20Sopenharmony_ci
101088c2ecf20Sopenharmony_cistatic void
101098c2ecf20Sopenharmony_cidevlink_trap_policer_unregister(struct devlink *devlink,
101108c2ecf20Sopenharmony_ci				const struct devlink_trap_policer *policer)
101118c2ecf20Sopenharmony_ci{
101128c2ecf20Sopenharmony_ci	struct devlink_trap_policer_item *policer_item;
101138c2ecf20Sopenharmony_ci
101148c2ecf20Sopenharmony_ci	policer_item = devlink_trap_policer_item_lookup(devlink, policer->id);
101158c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(!policer_item))
101168c2ecf20Sopenharmony_ci		return;
101178c2ecf20Sopenharmony_ci
101188c2ecf20Sopenharmony_ci	devlink_trap_policer_notify(devlink, policer_item,
101198c2ecf20Sopenharmony_ci				    DEVLINK_CMD_TRAP_POLICER_DEL);
101208c2ecf20Sopenharmony_ci	list_del(&policer_item->list);
101218c2ecf20Sopenharmony_ci	if (devlink->ops->trap_policer_fini)
101228c2ecf20Sopenharmony_ci		devlink->ops->trap_policer_fini(devlink, policer);
101238c2ecf20Sopenharmony_ci	kfree(policer_item);
101248c2ecf20Sopenharmony_ci}
101258c2ecf20Sopenharmony_ci
101268c2ecf20Sopenharmony_ci/**
101278c2ecf20Sopenharmony_ci * devlink_trap_policers_register - Register packet trap policers with devlink.
101288c2ecf20Sopenharmony_ci * @devlink: devlink.
101298c2ecf20Sopenharmony_ci * @policers: Packet trap policers.
101308c2ecf20Sopenharmony_ci * @policers_count: Count of provided packet trap policers.
101318c2ecf20Sopenharmony_ci *
101328c2ecf20Sopenharmony_ci * Return: Non-zero value on failure.
101338c2ecf20Sopenharmony_ci */
101348c2ecf20Sopenharmony_ciint
101358c2ecf20Sopenharmony_cidevlink_trap_policers_register(struct devlink *devlink,
101368c2ecf20Sopenharmony_ci			       const struct devlink_trap_policer *policers,
101378c2ecf20Sopenharmony_ci			       size_t policers_count)
101388c2ecf20Sopenharmony_ci{
101398c2ecf20Sopenharmony_ci	int i, err;
101408c2ecf20Sopenharmony_ci
101418c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
101428c2ecf20Sopenharmony_ci	for (i = 0; i < policers_count; i++) {
101438c2ecf20Sopenharmony_ci		const struct devlink_trap_policer *policer = &policers[i];
101448c2ecf20Sopenharmony_ci
101458c2ecf20Sopenharmony_ci		if (WARN_ON(policer->id == 0 ||
101468c2ecf20Sopenharmony_ci			    policer->max_rate < policer->min_rate ||
101478c2ecf20Sopenharmony_ci			    policer->max_burst < policer->min_burst)) {
101488c2ecf20Sopenharmony_ci			err = -EINVAL;
101498c2ecf20Sopenharmony_ci			goto err_trap_policer_verify;
101508c2ecf20Sopenharmony_ci		}
101518c2ecf20Sopenharmony_ci
101528c2ecf20Sopenharmony_ci		err = devlink_trap_policer_register(devlink, policer);
101538c2ecf20Sopenharmony_ci		if (err)
101548c2ecf20Sopenharmony_ci			goto err_trap_policer_register;
101558c2ecf20Sopenharmony_ci	}
101568c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
101578c2ecf20Sopenharmony_ci
101588c2ecf20Sopenharmony_ci	return 0;
101598c2ecf20Sopenharmony_ci
101608c2ecf20Sopenharmony_cierr_trap_policer_register:
101618c2ecf20Sopenharmony_cierr_trap_policer_verify:
101628c2ecf20Sopenharmony_ci	for (i--; i >= 0; i--)
101638c2ecf20Sopenharmony_ci		devlink_trap_policer_unregister(devlink, &policers[i]);
101648c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
101658c2ecf20Sopenharmony_ci	return err;
101668c2ecf20Sopenharmony_ci}
101678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_trap_policers_register);
101688c2ecf20Sopenharmony_ci
101698c2ecf20Sopenharmony_ci/**
101708c2ecf20Sopenharmony_ci * devlink_trap_policers_unregister - Unregister packet trap policers from devlink.
101718c2ecf20Sopenharmony_ci * @devlink: devlink.
101728c2ecf20Sopenharmony_ci * @policers: Packet trap policers.
101738c2ecf20Sopenharmony_ci * @policers_count: Count of provided packet trap policers.
101748c2ecf20Sopenharmony_ci */
101758c2ecf20Sopenharmony_civoid
101768c2ecf20Sopenharmony_cidevlink_trap_policers_unregister(struct devlink *devlink,
101778c2ecf20Sopenharmony_ci				 const struct devlink_trap_policer *policers,
101788c2ecf20Sopenharmony_ci				 size_t policers_count)
101798c2ecf20Sopenharmony_ci{
101808c2ecf20Sopenharmony_ci	int i;
101818c2ecf20Sopenharmony_ci
101828c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
101838c2ecf20Sopenharmony_ci	for (i = policers_count - 1; i >= 0; i--)
101848c2ecf20Sopenharmony_ci		devlink_trap_policer_unregister(devlink, &policers[i]);
101858c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
101868c2ecf20Sopenharmony_ci}
101878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(devlink_trap_policers_unregister);
101888c2ecf20Sopenharmony_ci
101898c2ecf20Sopenharmony_cistatic void __devlink_compat_running_version(struct devlink *devlink,
101908c2ecf20Sopenharmony_ci					     char *buf, size_t len)
101918c2ecf20Sopenharmony_ci{
101928c2ecf20Sopenharmony_ci	const struct nlattr *nlattr;
101938c2ecf20Sopenharmony_ci	struct devlink_info_req req;
101948c2ecf20Sopenharmony_ci	struct sk_buff *msg;
101958c2ecf20Sopenharmony_ci	int rem, err;
101968c2ecf20Sopenharmony_ci
101978c2ecf20Sopenharmony_ci	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
101988c2ecf20Sopenharmony_ci	if (!msg)
101998c2ecf20Sopenharmony_ci		return;
102008c2ecf20Sopenharmony_ci
102018c2ecf20Sopenharmony_ci	req.msg = msg;
102028c2ecf20Sopenharmony_ci	err = devlink->ops->info_get(devlink, &req, NULL);
102038c2ecf20Sopenharmony_ci	if (err)
102048c2ecf20Sopenharmony_ci		goto free_msg;
102058c2ecf20Sopenharmony_ci
102068c2ecf20Sopenharmony_ci	nla_for_each_attr(nlattr, (void *)msg->data, msg->len, rem) {
102078c2ecf20Sopenharmony_ci		const struct nlattr *kv;
102088c2ecf20Sopenharmony_ci		int rem_kv;
102098c2ecf20Sopenharmony_ci
102108c2ecf20Sopenharmony_ci		if (nla_type(nlattr) != DEVLINK_ATTR_INFO_VERSION_RUNNING)
102118c2ecf20Sopenharmony_ci			continue;
102128c2ecf20Sopenharmony_ci
102138c2ecf20Sopenharmony_ci		nla_for_each_nested(kv, nlattr, rem_kv) {
102148c2ecf20Sopenharmony_ci			if (nla_type(kv) != DEVLINK_ATTR_INFO_VERSION_VALUE)
102158c2ecf20Sopenharmony_ci				continue;
102168c2ecf20Sopenharmony_ci
102178c2ecf20Sopenharmony_ci			strlcat(buf, nla_data(kv), len);
102188c2ecf20Sopenharmony_ci			strlcat(buf, " ", len);
102198c2ecf20Sopenharmony_ci		}
102208c2ecf20Sopenharmony_ci	}
102218c2ecf20Sopenharmony_cifree_msg:
102228c2ecf20Sopenharmony_ci	nlmsg_free(msg);
102238c2ecf20Sopenharmony_ci}
102248c2ecf20Sopenharmony_ci
102258c2ecf20Sopenharmony_civoid devlink_compat_running_version(struct net_device *dev,
102268c2ecf20Sopenharmony_ci				    char *buf, size_t len)
102278c2ecf20Sopenharmony_ci{
102288c2ecf20Sopenharmony_ci	struct devlink *devlink;
102298c2ecf20Sopenharmony_ci
102308c2ecf20Sopenharmony_ci	dev_hold(dev);
102318c2ecf20Sopenharmony_ci	rtnl_unlock();
102328c2ecf20Sopenharmony_ci
102338c2ecf20Sopenharmony_ci	devlink = netdev_to_devlink(dev);
102348c2ecf20Sopenharmony_ci	if (!devlink || !devlink->ops->info_get)
102358c2ecf20Sopenharmony_ci		goto out;
102368c2ecf20Sopenharmony_ci
102378c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
102388c2ecf20Sopenharmony_ci	__devlink_compat_running_version(devlink, buf, len);
102398c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
102408c2ecf20Sopenharmony_ci
102418c2ecf20Sopenharmony_ciout:
102428c2ecf20Sopenharmony_ci	rtnl_lock();
102438c2ecf20Sopenharmony_ci	dev_put(dev);
102448c2ecf20Sopenharmony_ci}
102458c2ecf20Sopenharmony_ci
102468c2ecf20Sopenharmony_ciint devlink_compat_flash_update(struct net_device *dev, const char *file_name)
102478c2ecf20Sopenharmony_ci{
102488c2ecf20Sopenharmony_ci	struct devlink_flash_update_params params = {};
102498c2ecf20Sopenharmony_ci	struct devlink *devlink;
102508c2ecf20Sopenharmony_ci	int ret;
102518c2ecf20Sopenharmony_ci
102528c2ecf20Sopenharmony_ci	dev_hold(dev);
102538c2ecf20Sopenharmony_ci	rtnl_unlock();
102548c2ecf20Sopenharmony_ci
102558c2ecf20Sopenharmony_ci	devlink = netdev_to_devlink(dev);
102568c2ecf20Sopenharmony_ci	if (!devlink || !devlink->ops->flash_update) {
102578c2ecf20Sopenharmony_ci		ret = -EOPNOTSUPP;
102588c2ecf20Sopenharmony_ci		goto out;
102598c2ecf20Sopenharmony_ci	}
102608c2ecf20Sopenharmony_ci
102618c2ecf20Sopenharmony_ci	params.file_name = file_name;
102628c2ecf20Sopenharmony_ci
102638c2ecf20Sopenharmony_ci	mutex_lock(&devlink->lock);
102648c2ecf20Sopenharmony_ci	ret = devlink->ops->flash_update(devlink, &params, NULL);
102658c2ecf20Sopenharmony_ci	mutex_unlock(&devlink->lock);
102668c2ecf20Sopenharmony_ci
102678c2ecf20Sopenharmony_ciout:
102688c2ecf20Sopenharmony_ci	rtnl_lock();
102698c2ecf20Sopenharmony_ci	dev_put(dev);
102708c2ecf20Sopenharmony_ci
102718c2ecf20Sopenharmony_ci	return ret;
102728c2ecf20Sopenharmony_ci}
102738c2ecf20Sopenharmony_ci
102748c2ecf20Sopenharmony_ciint devlink_compat_phys_port_name_get(struct net_device *dev,
102758c2ecf20Sopenharmony_ci				      char *name, size_t len)
102768c2ecf20Sopenharmony_ci{
102778c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port;
102788c2ecf20Sopenharmony_ci
102798c2ecf20Sopenharmony_ci	/* RTNL mutex is held here which ensures that devlink_port
102808c2ecf20Sopenharmony_ci	 * instance cannot disappear in the middle. No need to take
102818c2ecf20Sopenharmony_ci	 * any devlink lock as only permanent values are accessed.
102828c2ecf20Sopenharmony_ci	 */
102838c2ecf20Sopenharmony_ci	ASSERT_RTNL();
102848c2ecf20Sopenharmony_ci
102858c2ecf20Sopenharmony_ci	devlink_port = netdev_to_devlink_port(dev);
102868c2ecf20Sopenharmony_ci	if (!devlink_port)
102878c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
102888c2ecf20Sopenharmony_ci
102898c2ecf20Sopenharmony_ci	return __devlink_port_phys_port_name_get(devlink_port, name, len);
102908c2ecf20Sopenharmony_ci}
102918c2ecf20Sopenharmony_ci
102928c2ecf20Sopenharmony_ciint devlink_compat_switch_id_get(struct net_device *dev,
102938c2ecf20Sopenharmony_ci				 struct netdev_phys_item_id *ppid)
102948c2ecf20Sopenharmony_ci{
102958c2ecf20Sopenharmony_ci	struct devlink_port *devlink_port;
102968c2ecf20Sopenharmony_ci
102978c2ecf20Sopenharmony_ci	/* Caller must hold RTNL mutex or reference to dev, which ensures that
102988c2ecf20Sopenharmony_ci	 * devlink_port instance cannot disappear in the middle. No need to take
102998c2ecf20Sopenharmony_ci	 * any devlink lock as only permanent values are accessed.
103008c2ecf20Sopenharmony_ci	 */
103018c2ecf20Sopenharmony_ci	devlink_port = netdev_to_devlink_port(dev);
103028c2ecf20Sopenharmony_ci	if (!devlink_port || !devlink_port->switch_port)
103038c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
103048c2ecf20Sopenharmony_ci
103058c2ecf20Sopenharmony_ci	memcpy(ppid, &devlink_port->attrs.switch_id, sizeof(*ppid));
103068c2ecf20Sopenharmony_ci
103078c2ecf20Sopenharmony_ci	return 0;
103088c2ecf20Sopenharmony_ci}
103098c2ecf20Sopenharmony_ci
103108c2ecf20Sopenharmony_cistatic void __net_exit devlink_pernet_pre_exit(struct net *net)
103118c2ecf20Sopenharmony_ci{
103128c2ecf20Sopenharmony_ci	struct devlink *devlink;
103138c2ecf20Sopenharmony_ci	u32 actions_performed;
103148c2ecf20Sopenharmony_ci	int err;
103158c2ecf20Sopenharmony_ci
103168c2ecf20Sopenharmony_ci	/* In case network namespace is getting destroyed, reload
103178c2ecf20Sopenharmony_ci	 * all devlink instances from this namespace into init_net.
103188c2ecf20Sopenharmony_ci	 */
103198c2ecf20Sopenharmony_ci	mutex_lock(&devlink_mutex);
103208c2ecf20Sopenharmony_ci	list_for_each_entry(devlink, &devlink_list, list) {
103218c2ecf20Sopenharmony_ci		if (net_eq(devlink_net(devlink), net)) {
103228c2ecf20Sopenharmony_ci			if (WARN_ON(!devlink_reload_supported(devlink->ops)))
103238c2ecf20Sopenharmony_ci				continue;
103248c2ecf20Sopenharmony_ci			err = devlink_reload(devlink, &init_net,
103258c2ecf20Sopenharmony_ci					     DEVLINK_RELOAD_ACTION_DRIVER_REINIT,
103268c2ecf20Sopenharmony_ci					     DEVLINK_RELOAD_LIMIT_UNSPEC,
103278c2ecf20Sopenharmony_ci					     &actions_performed, NULL);
103288c2ecf20Sopenharmony_ci			if (err && err != -EOPNOTSUPP)
103298c2ecf20Sopenharmony_ci				pr_warn("Failed to reload devlink instance into init_net\n");
103308c2ecf20Sopenharmony_ci		}
103318c2ecf20Sopenharmony_ci	}
103328c2ecf20Sopenharmony_ci	mutex_unlock(&devlink_mutex);
103338c2ecf20Sopenharmony_ci}
103348c2ecf20Sopenharmony_ci
103358c2ecf20Sopenharmony_cistatic struct pernet_operations devlink_pernet_ops __net_initdata = {
103368c2ecf20Sopenharmony_ci	.pre_exit = devlink_pernet_pre_exit,
103378c2ecf20Sopenharmony_ci};
103388c2ecf20Sopenharmony_ci
103398c2ecf20Sopenharmony_cistatic int __init devlink_init(void)
103408c2ecf20Sopenharmony_ci{
103418c2ecf20Sopenharmony_ci	int err;
103428c2ecf20Sopenharmony_ci
103438c2ecf20Sopenharmony_ci	err = genl_register_family(&devlink_nl_family);
103448c2ecf20Sopenharmony_ci	if (err)
103458c2ecf20Sopenharmony_ci		goto out;
103468c2ecf20Sopenharmony_ci	err = register_pernet_subsys(&devlink_pernet_ops);
103478c2ecf20Sopenharmony_ci
103488c2ecf20Sopenharmony_ciout:
103498c2ecf20Sopenharmony_ci	WARN_ON(err);
103508c2ecf20Sopenharmony_ci	return err;
103518c2ecf20Sopenharmony_ci}
103528c2ecf20Sopenharmony_ci
103538c2ecf20Sopenharmony_cisubsys_initcall(devlink_init);
10354