162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/* Copyright (c) 2016 Mellanox Technologies. All rights reserved.
362306a36Sopenharmony_ci * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/etherdevice.h>
762306a36Sopenharmony_ci#include <linux/mutex.h>
862306a36Sopenharmony_ci#include <linux/netdevice.h>
962306a36Sopenharmony_ci#include <linux/notifier.h>
1062306a36Sopenharmony_ci#include <linux/types.h>
1162306a36Sopenharmony_ci#include <linux/workqueue.h>
1262306a36Sopenharmony_ci#include <linux/xarray.h>
1362306a36Sopenharmony_ci#include <net/devlink.h>
1462306a36Sopenharmony_ci#include <net/net_namespace.h>
1562306a36Sopenharmony_ci#include <net/rtnetlink.h>
1662306a36Sopenharmony_ci#include <rdma/ib_verbs.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "netlink_gen.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define DEVLINK_REGISTERED XA_MARK_1
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define DEVLINK_RELOAD_STATS_ARRAY_SIZE \
2362306a36Sopenharmony_ci	(__DEVLINK_RELOAD_LIMIT_MAX * __DEVLINK_RELOAD_ACTION_MAX)
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistruct devlink_dev_stats {
2662306a36Sopenharmony_ci	u32 reload_stats[DEVLINK_RELOAD_STATS_ARRAY_SIZE];
2762306a36Sopenharmony_ci	u32 remote_reload_stats[DEVLINK_RELOAD_STATS_ARRAY_SIZE];
2862306a36Sopenharmony_ci};
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistruct devlink {
3162306a36Sopenharmony_ci	u32 index;
3262306a36Sopenharmony_ci	struct xarray ports;
3362306a36Sopenharmony_ci	struct list_head rate_list;
3462306a36Sopenharmony_ci	struct list_head sb_list;
3562306a36Sopenharmony_ci	struct list_head dpipe_table_list;
3662306a36Sopenharmony_ci	struct list_head resource_list;
3762306a36Sopenharmony_ci	struct xarray params;
3862306a36Sopenharmony_ci	struct list_head region_list;
3962306a36Sopenharmony_ci	struct list_head reporter_list;
4062306a36Sopenharmony_ci	struct devlink_dpipe_headers *dpipe_headers;
4162306a36Sopenharmony_ci	struct list_head trap_list;
4262306a36Sopenharmony_ci	struct list_head trap_group_list;
4362306a36Sopenharmony_ci	struct list_head trap_policer_list;
4462306a36Sopenharmony_ci	struct list_head linecard_list;
4562306a36Sopenharmony_ci	const struct devlink_ops *ops;
4662306a36Sopenharmony_ci	struct xarray snapshot_ids;
4762306a36Sopenharmony_ci	struct devlink_dev_stats stats;
4862306a36Sopenharmony_ci	struct device *dev;
4962306a36Sopenharmony_ci	possible_net_t _net;
5062306a36Sopenharmony_ci	/* Serializes access to devlink instance specific objects such as
5162306a36Sopenharmony_ci	 * port, sb, dpipe, resource, params, region, traps and more.
5262306a36Sopenharmony_ci	 */
5362306a36Sopenharmony_ci	struct mutex lock;
5462306a36Sopenharmony_ci	struct lock_class_key lock_key;
5562306a36Sopenharmony_ci	u8 reload_failed:1;
5662306a36Sopenharmony_ci	refcount_t refcount;
5762306a36Sopenharmony_ci	struct rcu_work rwork;
5862306a36Sopenharmony_ci	char priv[] __aligned(NETDEV_ALIGN);
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ciextern struct xarray devlinks;
6262306a36Sopenharmony_ciextern struct genl_family devlink_nl_family;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/* devlink instances are open to the access from the user space after
6562306a36Sopenharmony_ci * devlink_register() call. Such logical barrier allows us to have certain
6662306a36Sopenharmony_ci * expectations related to locking.
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci * Before *_register() - we are in initialization stage and no parallel
6962306a36Sopenharmony_ci * access possible to the devlink instance. All drivers perform that phase
7062306a36Sopenharmony_ci * by implicitly holding device_lock.
7162306a36Sopenharmony_ci *
7262306a36Sopenharmony_ci * After *_register() - users and driver can access devlink instance at
7362306a36Sopenharmony_ci * the same time.
7462306a36Sopenharmony_ci */
7562306a36Sopenharmony_ci#define ASSERT_DEVLINK_REGISTERED(d)                                           \
7662306a36Sopenharmony_ci	WARN_ON_ONCE(!xa_get_mark(&devlinks, (d)->index, DEVLINK_REGISTERED))
7762306a36Sopenharmony_ci#define ASSERT_DEVLINK_NOT_REGISTERED(d)                                       \
7862306a36Sopenharmony_ci	WARN_ON_ONCE(xa_get_mark(&devlinks, (d)->index, DEVLINK_REGISTERED))
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci/* Iterate over devlink pointers which were possible to get reference to.
8162306a36Sopenharmony_ci * devlink_put() needs to be called for each iterated devlink pointer
8262306a36Sopenharmony_ci * in loop body in order to release the reference.
8362306a36Sopenharmony_ci */
8462306a36Sopenharmony_ci#define devlinks_xa_for_each_registered_get(net, index, devlink)	\
8562306a36Sopenharmony_ci	for (index = 0; (devlink = devlinks_xa_find_get(net, &index)); index++)
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistruct devlink *devlinks_xa_find_get(struct net *net, unsigned long *indexp);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic inline bool devl_is_registered(struct devlink *devlink)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	devl_assert_locked(devlink);
9262306a36Sopenharmony_ci	return xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci/* Netlink */
9662306a36Sopenharmony_ci#define DEVLINK_NL_FLAG_NEED_PORT		BIT(0)
9762306a36Sopenharmony_ci#define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT	BIT(1)
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cienum devlink_multicast_groups {
10062306a36Sopenharmony_ci	DEVLINK_MCGRP_CONFIG,
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/* state held across netlink dumps */
10462306a36Sopenharmony_cistruct devlink_nl_dump_state {
10562306a36Sopenharmony_ci	unsigned long instance;
10662306a36Sopenharmony_ci	int idx;
10762306a36Sopenharmony_ci	union {
10862306a36Sopenharmony_ci		/* DEVLINK_CMD_REGION_READ */
10962306a36Sopenharmony_ci		struct {
11062306a36Sopenharmony_ci			u64 start_offset;
11162306a36Sopenharmony_ci		};
11262306a36Sopenharmony_ci		/* DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET */
11362306a36Sopenharmony_ci		struct {
11462306a36Sopenharmony_ci			u64 dump_ts;
11562306a36Sopenharmony_ci		};
11662306a36Sopenharmony_ci	};
11762306a36Sopenharmony_ci};
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_citypedef int devlink_nl_dump_one_func_t(struct sk_buff *msg,
12062306a36Sopenharmony_ci				       struct devlink *devlink,
12162306a36Sopenharmony_ci				       struct netlink_callback *cb,
12262306a36Sopenharmony_ci				       int flags);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistruct devlink *
12562306a36Sopenharmony_cidevlink_get_from_attrs_lock(struct net *net, struct nlattr **attrs);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ciint devlink_nl_dumpit(struct sk_buff *msg, struct netlink_callback *cb,
12862306a36Sopenharmony_ci		      devlink_nl_dump_one_func_t *dump_one);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic inline struct devlink_nl_dump_state *
13162306a36Sopenharmony_cidevlink_dump_state(struct netlink_callback *cb)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	NL_ASSERT_DUMP_CTX_FITS(struct devlink_nl_dump_state);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	return (struct devlink_nl_dump_state *)cb->ctx;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic inline int
13962306a36Sopenharmony_cidevlink_nl_put_handle(struct sk_buff *msg, struct devlink *devlink)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	if (nla_put_string(msg, DEVLINK_ATTR_BUS_NAME, devlink->dev->bus->name))
14262306a36Sopenharmony_ci		return -EMSGSIZE;
14362306a36Sopenharmony_ci	if (nla_put_string(msg, DEVLINK_ATTR_DEV_NAME, dev_name(devlink->dev)))
14462306a36Sopenharmony_ci		return -EMSGSIZE;
14562306a36Sopenharmony_ci	return 0;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ciint devlink_nl_msg_reply_and_new(struct sk_buff **msg, struct genl_info *info);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/* Notify */
15162306a36Sopenharmony_civoid devlink_notify_register(struct devlink *devlink);
15262306a36Sopenharmony_civoid devlink_notify_unregister(struct devlink *devlink);
15362306a36Sopenharmony_civoid devlink_ports_notify_register(struct devlink *devlink);
15462306a36Sopenharmony_civoid devlink_ports_notify_unregister(struct devlink *devlink);
15562306a36Sopenharmony_civoid devlink_params_notify_register(struct devlink *devlink);
15662306a36Sopenharmony_civoid devlink_params_notify_unregister(struct devlink *devlink);
15762306a36Sopenharmony_civoid devlink_regions_notify_register(struct devlink *devlink);
15862306a36Sopenharmony_civoid devlink_regions_notify_unregister(struct devlink *devlink);
15962306a36Sopenharmony_civoid devlink_trap_policers_notify_register(struct devlink *devlink);
16062306a36Sopenharmony_civoid devlink_trap_policers_notify_unregister(struct devlink *devlink);
16162306a36Sopenharmony_civoid devlink_trap_groups_notify_register(struct devlink *devlink);
16262306a36Sopenharmony_civoid devlink_trap_groups_notify_unregister(struct devlink *devlink);
16362306a36Sopenharmony_civoid devlink_traps_notify_register(struct devlink *devlink);
16462306a36Sopenharmony_civoid devlink_traps_notify_unregister(struct devlink *devlink);
16562306a36Sopenharmony_civoid devlink_rates_notify_register(struct devlink *devlink);
16662306a36Sopenharmony_civoid devlink_rates_notify_unregister(struct devlink *devlink);
16762306a36Sopenharmony_civoid devlink_linecards_notify_register(struct devlink *devlink);
16862306a36Sopenharmony_civoid devlink_linecards_notify_unregister(struct devlink *devlink);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/* Ports */
17162306a36Sopenharmony_ci#define ASSERT_DEVLINK_PORT_INITIALIZED(devlink_port)				\
17262306a36Sopenharmony_ci	WARN_ON_ONCE(!(devlink_port)->initialized)
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistruct devlink_port *devlink_port_get_by_index(struct devlink *devlink,
17562306a36Sopenharmony_ci					       unsigned int port_index);
17662306a36Sopenharmony_ciint devlink_port_netdevice_event(struct notifier_block *nb,
17762306a36Sopenharmony_ci				 unsigned long event, void *ptr);
17862306a36Sopenharmony_cistruct devlink_port *
17962306a36Sopenharmony_cidevlink_port_get_from_info(struct devlink *devlink, struct genl_info *info);
18062306a36Sopenharmony_cistruct devlink_port *devlink_port_get_from_attrs(struct devlink *devlink,
18162306a36Sopenharmony_ci						 struct nlattr **attrs);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci/* Reload */
18462306a36Sopenharmony_cibool devlink_reload_actions_valid(const struct devlink_ops *ops);
18562306a36Sopenharmony_ciint devlink_reload(struct devlink *devlink, struct net *dest_net,
18662306a36Sopenharmony_ci		   enum devlink_reload_action action,
18762306a36Sopenharmony_ci		   enum devlink_reload_limit limit,
18862306a36Sopenharmony_ci		   u32 *actions_performed, struct netlink_ext_ack *extack);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic inline bool devlink_reload_supported(const struct devlink_ops *ops)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	return ops->reload_down && ops->reload_up;
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci/* Params */
19662306a36Sopenharmony_civoid devlink_params_driverinit_load_new(struct devlink *devlink);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci/* Resources */
19962306a36Sopenharmony_cistruct devlink_resource;
20062306a36Sopenharmony_ciint devlink_resources_validate(struct devlink *devlink,
20162306a36Sopenharmony_ci			       struct devlink_resource *resource,
20262306a36Sopenharmony_ci			       struct genl_info *info);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci/* Rates */
20562306a36Sopenharmony_ciint devlink_rate_nodes_check(struct devlink *devlink, u16 mode,
20662306a36Sopenharmony_ci			     struct netlink_ext_ack *extack);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci/* Linecards */
20962306a36Sopenharmony_cistruct devlink_linecard {
21062306a36Sopenharmony_ci	struct list_head list;
21162306a36Sopenharmony_ci	struct devlink *devlink;
21262306a36Sopenharmony_ci	unsigned int index;
21362306a36Sopenharmony_ci	const struct devlink_linecard_ops *ops;
21462306a36Sopenharmony_ci	void *priv;
21562306a36Sopenharmony_ci	enum devlink_linecard_state state;
21662306a36Sopenharmony_ci	struct mutex state_lock; /* Protects state */
21762306a36Sopenharmony_ci	const char *type;
21862306a36Sopenharmony_ci	struct devlink_linecard_type *types;
21962306a36Sopenharmony_ci	unsigned int types_count;
22062306a36Sopenharmony_ci	struct devlink *nested_devlink;
22162306a36Sopenharmony_ci};
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci/* Devlink nl cmds */
22462306a36Sopenharmony_ciint devlink_nl_cmd_reload(struct sk_buff *skb, struct genl_info *info);
22562306a36Sopenharmony_ciint devlink_nl_cmd_eswitch_get_doit(struct sk_buff *skb, struct genl_info *info);
22662306a36Sopenharmony_ciint devlink_nl_cmd_eswitch_set_doit(struct sk_buff *skb, struct genl_info *info);
22762306a36Sopenharmony_ciint devlink_nl_cmd_flash_update(struct sk_buff *skb, struct genl_info *info);
22862306a36Sopenharmony_ciint devlink_nl_cmd_selftests_run(struct sk_buff *skb, struct genl_info *info);
22962306a36Sopenharmony_ciint devlink_nl_cmd_port_set_doit(struct sk_buff *skb, struct genl_info *info);
23062306a36Sopenharmony_ciint devlink_nl_cmd_port_split_doit(struct sk_buff *skb, struct genl_info *info);
23162306a36Sopenharmony_ciint devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb,
23262306a36Sopenharmony_ci				     struct genl_info *info);
23362306a36Sopenharmony_ciint devlink_nl_cmd_port_new_doit(struct sk_buff *skb, struct genl_info *info);
23462306a36Sopenharmony_ciint devlink_nl_cmd_port_del_doit(struct sk_buff *skb, struct genl_info *info);
23562306a36Sopenharmony_ciint devlink_nl_cmd_sb_pool_set_doit(struct sk_buff *skb, struct genl_info *info);
23662306a36Sopenharmony_ciint devlink_nl_cmd_sb_port_pool_set_doit(struct sk_buff *skb,
23762306a36Sopenharmony_ci					 struct genl_info *info);
23862306a36Sopenharmony_ciint devlink_nl_cmd_sb_tc_pool_bind_set_doit(struct sk_buff *skb,
23962306a36Sopenharmony_ci					    struct genl_info *info);
24062306a36Sopenharmony_ciint devlink_nl_cmd_sb_occ_snapshot_doit(struct sk_buff *skb,
24162306a36Sopenharmony_ci					struct genl_info *info);
24262306a36Sopenharmony_ciint devlink_nl_cmd_sb_occ_max_clear_doit(struct sk_buff *skb,
24362306a36Sopenharmony_ci					 struct genl_info *info);
24462306a36Sopenharmony_ciint devlink_nl_cmd_dpipe_table_get(struct sk_buff *skb, struct genl_info *info);
24562306a36Sopenharmony_ciint devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
24662306a36Sopenharmony_ci				     struct genl_info *info);
24762306a36Sopenharmony_ciint devlink_nl_cmd_dpipe_headers_get(struct sk_buff *skb,
24862306a36Sopenharmony_ci				     struct genl_info *info);
24962306a36Sopenharmony_ciint devlink_nl_cmd_dpipe_table_counters_set(struct sk_buff *skb,
25062306a36Sopenharmony_ci					    struct genl_info *info);
25162306a36Sopenharmony_ciint devlink_nl_cmd_resource_set(struct sk_buff *skb, struct genl_info *info);
25262306a36Sopenharmony_ciint devlink_nl_cmd_resource_dump(struct sk_buff *skb, struct genl_info *info);
25362306a36Sopenharmony_ciint devlink_nl_cmd_param_set_doit(struct sk_buff *skb, struct genl_info *info);
25462306a36Sopenharmony_ciint devlink_nl_cmd_port_param_get_dumpit(struct sk_buff *msg,
25562306a36Sopenharmony_ci					 struct netlink_callback *cb);
25662306a36Sopenharmony_ciint devlink_nl_cmd_port_param_get_doit(struct sk_buff *skb,
25762306a36Sopenharmony_ci				       struct genl_info *info);
25862306a36Sopenharmony_ciint devlink_nl_cmd_port_param_set_doit(struct sk_buff *skb,
25962306a36Sopenharmony_ci				       struct genl_info *info);
26062306a36Sopenharmony_ciint devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info);
26162306a36Sopenharmony_ciint devlink_nl_cmd_region_del(struct sk_buff *skb, struct genl_info *info);
26262306a36Sopenharmony_ciint devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
26362306a36Sopenharmony_ci				      struct netlink_callback *cb);
26462306a36Sopenharmony_ciint devlink_nl_cmd_health_reporter_set_doit(struct sk_buff *skb,
26562306a36Sopenharmony_ci					    struct genl_info *info);
26662306a36Sopenharmony_ciint devlink_nl_cmd_health_reporter_recover_doit(struct sk_buff *skb,
26762306a36Sopenharmony_ci						struct genl_info *info);
26862306a36Sopenharmony_ciint devlink_nl_cmd_health_reporter_diagnose_doit(struct sk_buff *skb,
26962306a36Sopenharmony_ci						 struct genl_info *info);
27062306a36Sopenharmony_ciint devlink_nl_cmd_health_reporter_dump_get_dumpit(struct sk_buff *skb,
27162306a36Sopenharmony_ci						   struct netlink_callback *cb);
27262306a36Sopenharmony_ciint devlink_nl_cmd_health_reporter_dump_clear_doit(struct sk_buff *skb,
27362306a36Sopenharmony_ci						   struct genl_info *info);
27462306a36Sopenharmony_ciint devlink_nl_cmd_health_reporter_test_doit(struct sk_buff *skb,
27562306a36Sopenharmony_ci					     struct genl_info *info);
27662306a36Sopenharmony_ciint devlink_nl_cmd_trap_set_doit(struct sk_buff *skb, struct genl_info *info);
27762306a36Sopenharmony_ciint devlink_nl_cmd_trap_group_set_doit(struct sk_buff *skb,
27862306a36Sopenharmony_ci				       struct genl_info *info);
27962306a36Sopenharmony_ciint devlink_nl_cmd_trap_policer_set_doit(struct sk_buff *skb,
28062306a36Sopenharmony_ci					 struct genl_info *info);
28162306a36Sopenharmony_ciint devlink_nl_cmd_rate_set_doit(struct sk_buff *skb, struct genl_info *info);
28262306a36Sopenharmony_ciint devlink_nl_cmd_rate_new_doit(struct sk_buff *skb, struct genl_info *info);
28362306a36Sopenharmony_ciint devlink_nl_cmd_rate_del_doit(struct sk_buff *skb, struct genl_info *info);
28462306a36Sopenharmony_ciint devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb,
28562306a36Sopenharmony_ci				     struct genl_info *info);
286