xref: /linux-6.15/net/devlink/param.c (revision 5625ca56)
1830c41e1SJiri Pirko // SPDX-License-Identifier: GPL-2.0-or-later
2830c41e1SJiri Pirko /*
3830c41e1SJiri Pirko  * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4830c41e1SJiri Pirko  * Copyright (c) 2016 Jiri Pirko <[email protected]>
5830c41e1SJiri Pirko  */
6830c41e1SJiri Pirko 
7830c41e1SJiri Pirko #include "devl_internal.h"
8830c41e1SJiri Pirko 
9830c41e1SJiri Pirko static const struct devlink_param devlink_param_generic[] = {
10830c41e1SJiri Pirko 	{
11830c41e1SJiri Pirko 		.id = DEVLINK_PARAM_GENERIC_ID_INT_ERR_RESET,
12830c41e1SJiri Pirko 		.name = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_NAME,
13830c41e1SJiri Pirko 		.type = DEVLINK_PARAM_GENERIC_INT_ERR_RESET_TYPE,
14830c41e1SJiri Pirko 	},
15830c41e1SJiri Pirko 	{
16830c41e1SJiri Pirko 		.id = DEVLINK_PARAM_GENERIC_ID_MAX_MACS,
17830c41e1SJiri Pirko 		.name = DEVLINK_PARAM_GENERIC_MAX_MACS_NAME,
18830c41e1SJiri Pirko 		.type = DEVLINK_PARAM_GENERIC_MAX_MACS_TYPE,
19830c41e1SJiri Pirko 	},
20830c41e1SJiri Pirko 	{
21830c41e1SJiri Pirko 		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_SRIOV,
22830c41e1SJiri Pirko 		.name = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_NAME,
23830c41e1SJiri Pirko 		.type = DEVLINK_PARAM_GENERIC_ENABLE_SRIOV_TYPE,
24830c41e1SJiri Pirko 	},
25830c41e1SJiri Pirko 	{
26830c41e1SJiri Pirko 		.id = DEVLINK_PARAM_GENERIC_ID_REGION_SNAPSHOT,
27830c41e1SJiri Pirko 		.name = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_NAME,
28830c41e1SJiri Pirko 		.type = DEVLINK_PARAM_GENERIC_REGION_SNAPSHOT_TYPE,
29830c41e1SJiri Pirko 	},
30830c41e1SJiri Pirko 	{
31830c41e1SJiri Pirko 		.id = DEVLINK_PARAM_GENERIC_ID_IGNORE_ARI,
32830c41e1SJiri Pirko 		.name = DEVLINK_PARAM_GENERIC_IGNORE_ARI_NAME,
33830c41e1SJiri Pirko 		.type = DEVLINK_PARAM_GENERIC_IGNORE_ARI_TYPE,
34830c41e1SJiri Pirko 	},
35830c41e1SJiri Pirko 	{
36830c41e1SJiri Pirko 		.id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MAX,
37830c41e1SJiri Pirko 		.name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_NAME,
38830c41e1SJiri Pirko 		.type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MAX_TYPE,
39830c41e1SJiri Pirko 	},
40830c41e1SJiri Pirko 	{
41830c41e1SJiri Pirko 		.id = DEVLINK_PARAM_GENERIC_ID_MSIX_VEC_PER_PF_MIN,
42830c41e1SJiri Pirko 		.name = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_NAME,
43830c41e1SJiri Pirko 		.type = DEVLINK_PARAM_GENERIC_MSIX_VEC_PER_PF_MIN_TYPE,
44830c41e1SJiri Pirko 	},
45830c41e1SJiri Pirko 	{
46830c41e1SJiri Pirko 		.id = DEVLINK_PARAM_GENERIC_ID_FW_LOAD_POLICY,
47830c41e1SJiri Pirko 		.name = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_NAME,
48830c41e1SJiri Pirko 		.type = DEVLINK_PARAM_GENERIC_FW_LOAD_POLICY_TYPE,
49830c41e1SJiri Pirko 	},
50830c41e1SJiri Pirko 	{
51830c41e1SJiri Pirko 		.id = DEVLINK_PARAM_GENERIC_ID_RESET_DEV_ON_DRV_PROBE,
52830c41e1SJiri Pirko 		.name = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_NAME,
53830c41e1SJiri Pirko 		.type = DEVLINK_PARAM_GENERIC_RESET_DEV_ON_DRV_PROBE_TYPE,
54830c41e1SJiri Pirko 	},
55830c41e1SJiri Pirko 	{
56830c41e1SJiri Pirko 		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_ROCE,
57830c41e1SJiri Pirko 		.name = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_NAME,
58830c41e1SJiri Pirko 		.type = DEVLINK_PARAM_GENERIC_ENABLE_ROCE_TYPE,
59830c41e1SJiri Pirko 	},
60830c41e1SJiri Pirko 	{
61830c41e1SJiri Pirko 		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_REMOTE_DEV_RESET,
62830c41e1SJiri Pirko 		.name = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_NAME,
63830c41e1SJiri Pirko 		.type = DEVLINK_PARAM_GENERIC_ENABLE_REMOTE_DEV_RESET_TYPE,
64830c41e1SJiri Pirko 	},
65830c41e1SJiri Pirko 	{
66830c41e1SJiri Pirko 		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_ETH,
67830c41e1SJiri Pirko 		.name = DEVLINK_PARAM_GENERIC_ENABLE_ETH_NAME,
68830c41e1SJiri Pirko 		.type = DEVLINK_PARAM_GENERIC_ENABLE_ETH_TYPE,
69830c41e1SJiri Pirko 	},
70830c41e1SJiri Pirko 	{
71830c41e1SJiri Pirko 		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_RDMA,
72830c41e1SJiri Pirko 		.name = DEVLINK_PARAM_GENERIC_ENABLE_RDMA_NAME,
73830c41e1SJiri Pirko 		.type = DEVLINK_PARAM_GENERIC_ENABLE_RDMA_TYPE,
74830c41e1SJiri Pirko 	},
75830c41e1SJiri Pirko 	{
76830c41e1SJiri Pirko 		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_VNET,
77830c41e1SJiri Pirko 		.name = DEVLINK_PARAM_GENERIC_ENABLE_VNET_NAME,
78830c41e1SJiri Pirko 		.type = DEVLINK_PARAM_GENERIC_ENABLE_VNET_TYPE,
79830c41e1SJiri Pirko 	},
80830c41e1SJiri Pirko 	{
81830c41e1SJiri Pirko 		.id = DEVLINK_PARAM_GENERIC_ID_ENABLE_IWARP,
82830c41e1SJiri Pirko 		.name = DEVLINK_PARAM_GENERIC_ENABLE_IWARP_NAME,
83830c41e1SJiri Pirko 		.type = DEVLINK_PARAM_GENERIC_ENABLE_IWARP_TYPE,
84830c41e1SJiri Pirko 	},
85830c41e1SJiri Pirko 	{
86830c41e1SJiri Pirko 		.id = DEVLINK_PARAM_GENERIC_ID_IO_EQ_SIZE,
87830c41e1SJiri Pirko 		.name = DEVLINK_PARAM_GENERIC_IO_EQ_SIZE_NAME,
88830c41e1SJiri Pirko 		.type = DEVLINK_PARAM_GENERIC_IO_EQ_SIZE_TYPE,
89830c41e1SJiri Pirko 	},
90830c41e1SJiri Pirko 	{
91830c41e1SJiri Pirko 		.id = DEVLINK_PARAM_GENERIC_ID_EVENT_EQ_SIZE,
92830c41e1SJiri Pirko 		.name = DEVLINK_PARAM_GENERIC_EVENT_EQ_SIZE_NAME,
93830c41e1SJiri Pirko 		.type = DEVLINK_PARAM_GENERIC_EVENT_EQ_SIZE_TYPE,
94830c41e1SJiri Pirko 	},
95830c41e1SJiri Pirko };
96830c41e1SJiri Pirko 
devlink_param_generic_verify(const struct devlink_param * param)97830c41e1SJiri Pirko static int devlink_param_generic_verify(const struct devlink_param *param)
98830c41e1SJiri Pirko {
99830c41e1SJiri Pirko 	/* verify it match generic parameter by id and name */
100830c41e1SJiri Pirko 	if (param->id > DEVLINK_PARAM_GENERIC_ID_MAX)
101830c41e1SJiri Pirko 		return -EINVAL;
102830c41e1SJiri Pirko 	if (strcmp(param->name, devlink_param_generic[param->id].name))
103830c41e1SJiri Pirko 		return -ENOENT;
104830c41e1SJiri Pirko 
105830c41e1SJiri Pirko 	WARN_ON(param->type != devlink_param_generic[param->id].type);
106830c41e1SJiri Pirko 
107830c41e1SJiri Pirko 	return 0;
108830c41e1SJiri Pirko }
109830c41e1SJiri Pirko 
devlink_param_driver_verify(const struct devlink_param * param)110830c41e1SJiri Pirko static int devlink_param_driver_verify(const struct devlink_param *param)
111830c41e1SJiri Pirko {
112830c41e1SJiri Pirko 	int i;
113830c41e1SJiri Pirko 
114830c41e1SJiri Pirko 	if (param->id <= DEVLINK_PARAM_GENERIC_ID_MAX)
115830c41e1SJiri Pirko 		return -EINVAL;
116830c41e1SJiri Pirko 	/* verify no such name in generic params */
117830c41e1SJiri Pirko 	for (i = 0; i <= DEVLINK_PARAM_GENERIC_ID_MAX; i++)
118830c41e1SJiri Pirko 		if (!strcmp(param->name, devlink_param_generic[i].name))
119830c41e1SJiri Pirko 			return -EEXIST;
120830c41e1SJiri Pirko 
121830c41e1SJiri Pirko 	return 0;
122830c41e1SJiri Pirko }
123830c41e1SJiri Pirko 
124830c41e1SJiri Pirko static struct devlink_param_item *
devlink_param_find_by_name(struct xarray * params,const char * param_name)125830c41e1SJiri Pirko devlink_param_find_by_name(struct xarray *params, const char *param_name)
126830c41e1SJiri Pirko {
127830c41e1SJiri Pirko 	struct devlink_param_item *param_item;
128830c41e1SJiri Pirko 	unsigned long param_id;
129830c41e1SJiri Pirko 
130830c41e1SJiri Pirko 	xa_for_each(params, param_id, param_item) {
131830c41e1SJiri Pirko 		if (!strcmp(param_item->param->name, param_name))
132830c41e1SJiri Pirko 			return param_item;
133830c41e1SJiri Pirko 	}
134830c41e1SJiri Pirko 	return NULL;
135830c41e1SJiri Pirko }
136830c41e1SJiri Pirko 
137830c41e1SJiri Pirko static struct devlink_param_item *
devlink_param_find_by_id(struct xarray * params,u32 param_id)138830c41e1SJiri Pirko devlink_param_find_by_id(struct xarray *params, u32 param_id)
139830c41e1SJiri Pirko {
140830c41e1SJiri Pirko 	return xa_load(params, param_id);
141830c41e1SJiri Pirko }
142830c41e1SJiri Pirko 
143830c41e1SJiri Pirko static bool
devlink_param_cmode_is_supported(const struct devlink_param * param,enum devlink_param_cmode cmode)144830c41e1SJiri Pirko devlink_param_cmode_is_supported(const struct devlink_param *param,
145830c41e1SJiri Pirko 				 enum devlink_param_cmode cmode)
146830c41e1SJiri Pirko {
147830c41e1SJiri Pirko 	return test_bit(cmode, &param->supported_cmodes);
148830c41e1SJiri Pirko }
149830c41e1SJiri Pirko 
devlink_param_get(struct devlink * devlink,const struct devlink_param * param,struct devlink_param_gset_ctx * ctx)150830c41e1SJiri Pirko static int devlink_param_get(struct devlink *devlink,
151830c41e1SJiri Pirko 			     const struct devlink_param *param,
152830c41e1SJiri Pirko 			     struct devlink_param_gset_ctx *ctx)
153830c41e1SJiri Pirko {
154830c41e1SJiri Pirko 	if (!param->get)
155830c41e1SJiri Pirko 		return -EOPNOTSUPP;
156830c41e1SJiri Pirko 	return param->get(devlink, param->id, ctx);
157830c41e1SJiri Pirko }
158830c41e1SJiri Pirko 
devlink_param_set(struct devlink * devlink,const struct devlink_param * param,struct devlink_param_gset_ctx * ctx,struct netlink_ext_ack * extack)159830c41e1SJiri Pirko static int devlink_param_set(struct devlink *devlink,
160830c41e1SJiri Pirko 			     const struct devlink_param *param,
161*5625ca56SMateusz Polchlopek 			     struct devlink_param_gset_ctx *ctx,
162*5625ca56SMateusz Polchlopek 			     struct netlink_ext_ack *extack)
163830c41e1SJiri Pirko {
164830c41e1SJiri Pirko 	if (!param->set)
165830c41e1SJiri Pirko 		return -EOPNOTSUPP;
166*5625ca56SMateusz Polchlopek 	return param->set(devlink, param->id, ctx, extack);
167830c41e1SJiri Pirko }
168830c41e1SJiri Pirko 
169830c41e1SJiri Pirko static int
devlink_param_type_to_nla_type(enum devlink_param_type param_type)170830c41e1SJiri Pirko devlink_param_type_to_nla_type(enum devlink_param_type param_type)
171830c41e1SJiri Pirko {
172830c41e1SJiri Pirko 	switch (param_type) {
173830c41e1SJiri Pirko 	case DEVLINK_PARAM_TYPE_U8:
174830c41e1SJiri Pirko 		return NLA_U8;
175830c41e1SJiri Pirko 	case DEVLINK_PARAM_TYPE_U16:
176830c41e1SJiri Pirko 		return NLA_U16;
177830c41e1SJiri Pirko 	case DEVLINK_PARAM_TYPE_U32:
178830c41e1SJiri Pirko 		return NLA_U32;
179830c41e1SJiri Pirko 	case DEVLINK_PARAM_TYPE_STRING:
180830c41e1SJiri Pirko 		return NLA_STRING;
181830c41e1SJiri Pirko 	case DEVLINK_PARAM_TYPE_BOOL:
182830c41e1SJiri Pirko 		return NLA_FLAG;
183830c41e1SJiri Pirko 	default:
184830c41e1SJiri Pirko 		return -EINVAL;
185830c41e1SJiri Pirko 	}
186830c41e1SJiri Pirko }
187830c41e1SJiri Pirko 
188830c41e1SJiri Pirko static int
devlink_nl_param_value_fill_one(struct sk_buff * msg,enum devlink_param_type type,enum devlink_param_cmode cmode,union devlink_param_value val)189830c41e1SJiri Pirko devlink_nl_param_value_fill_one(struct sk_buff *msg,
190830c41e1SJiri Pirko 				enum devlink_param_type type,
191830c41e1SJiri Pirko 				enum devlink_param_cmode cmode,
192830c41e1SJiri Pirko 				union devlink_param_value val)
193830c41e1SJiri Pirko {
194830c41e1SJiri Pirko 	struct nlattr *param_value_attr;
195830c41e1SJiri Pirko 
196830c41e1SJiri Pirko 	param_value_attr = nla_nest_start_noflag(msg,
197830c41e1SJiri Pirko 						 DEVLINK_ATTR_PARAM_VALUE);
198830c41e1SJiri Pirko 	if (!param_value_attr)
199830c41e1SJiri Pirko 		goto nla_put_failure;
200830c41e1SJiri Pirko 
201830c41e1SJiri Pirko 	if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_CMODE, cmode))
202830c41e1SJiri Pirko 		goto value_nest_cancel;
203830c41e1SJiri Pirko 
204830c41e1SJiri Pirko 	switch (type) {
205830c41e1SJiri Pirko 	case DEVLINK_PARAM_TYPE_U8:
206830c41e1SJiri Pirko 		if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu8))
207830c41e1SJiri Pirko 			goto value_nest_cancel;
208830c41e1SJiri Pirko 		break;
209830c41e1SJiri Pirko 	case DEVLINK_PARAM_TYPE_U16:
210830c41e1SJiri Pirko 		if (nla_put_u16(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu16))
211830c41e1SJiri Pirko 			goto value_nest_cancel;
212830c41e1SJiri Pirko 		break;
213830c41e1SJiri Pirko 	case DEVLINK_PARAM_TYPE_U32:
214830c41e1SJiri Pirko 		if (nla_put_u32(msg, DEVLINK_ATTR_PARAM_VALUE_DATA, val.vu32))
215830c41e1SJiri Pirko 			goto value_nest_cancel;
216830c41e1SJiri Pirko 		break;
217830c41e1SJiri Pirko 	case DEVLINK_PARAM_TYPE_STRING:
218830c41e1SJiri Pirko 		if (nla_put_string(msg, DEVLINK_ATTR_PARAM_VALUE_DATA,
219830c41e1SJiri Pirko 				   val.vstr))
220830c41e1SJiri Pirko 			goto value_nest_cancel;
221830c41e1SJiri Pirko 		break;
222830c41e1SJiri Pirko 	case DEVLINK_PARAM_TYPE_BOOL:
223830c41e1SJiri Pirko 		if (val.vbool &&
224830c41e1SJiri Pirko 		    nla_put_flag(msg, DEVLINK_ATTR_PARAM_VALUE_DATA))
225830c41e1SJiri Pirko 			goto value_nest_cancel;
226830c41e1SJiri Pirko 		break;
227830c41e1SJiri Pirko 	}
228830c41e1SJiri Pirko 
229830c41e1SJiri Pirko 	nla_nest_end(msg, param_value_attr);
230830c41e1SJiri Pirko 	return 0;
231830c41e1SJiri Pirko 
232830c41e1SJiri Pirko value_nest_cancel:
233830c41e1SJiri Pirko 	nla_nest_cancel(msg, param_value_attr);
234830c41e1SJiri Pirko nla_put_failure:
235830c41e1SJiri Pirko 	return -EMSGSIZE;
236830c41e1SJiri Pirko }
237830c41e1SJiri Pirko 
devlink_nl_param_fill(struct sk_buff * msg,struct devlink * devlink,unsigned int port_index,struct devlink_param_item * param_item,enum devlink_command cmd,u32 portid,u32 seq,int flags)238830c41e1SJiri Pirko static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
239830c41e1SJiri Pirko 				 unsigned int port_index,
240830c41e1SJiri Pirko 				 struct devlink_param_item *param_item,
241830c41e1SJiri Pirko 				 enum devlink_command cmd,
242830c41e1SJiri Pirko 				 u32 portid, u32 seq, int flags)
243830c41e1SJiri Pirko {
244830c41e1SJiri Pirko 	union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
245830c41e1SJiri Pirko 	bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
246830c41e1SJiri Pirko 	const struct devlink_param *param = param_item->param;
247830c41e1SJiri Pirko 	struct devlink_param_gset_ctx ctx;
248830c41e1SJiri Pirko 	struct nlattr *param_values_list;
249830c41e1SJiri Pirko 	struct nlattr *param_attr;
250830c41e1SJiri Pirko 	int nla_type;
251830c41e1SJiri Pirko 	void *hdr;
252830c41e1SJiri Pirko 	int err;
253830c41e1SJiri Pirko 	int i;
254830c41e1SJiri Pirko 
255830c41e1SJiri Pirko 	/* Get value from driver part to driverinit configuration mode */
256830c41e1SJiri Pirko 	for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
257830c41e1SJiri Pirko 		if (!devlink_param_cmode_is_supported(param, i))
258830c41e1SJiri Pirko 			continue;
259830c41e1SJiri Pirko 		if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
260830c41e1SJiri Pirko 			if (param_item->driverinit_value_new_valid)
261830c41e1SJiri Pirko 				param_value[i] = param_item->driverinit_value_new;
262830c41e1SJiri Pirko 			else if (param_item->driverinit_value_valid)
263830c41e1SJiri Pirko 				param_value[i] = param_item->driverinit_value;
264830c41e1SJiri Pirko 			else
265830c41e1SJiri Pirko 				return -EOPNOTSUPP;
266830c41e1SJiri Pirko 		} else {
267830c41e1SJiri Pirko 			ctx.cmode = i;
268830c41e1SJiri Pirko 			err = devlink_param_get(devlink, param, &ctx);
269830c41e1SJiri Pirko 			if (err)
270830c41e1SJiri Pirko 				return err;
271830c41e1SJiri Pirko 			param_value[i] = ctx.val;
272830c41e1SJiri Pirko 		}
273830c41e1SJiri Pirko 		param_value_set[i] = true;
274830c41e1SJiri Pirko 	}
275830c41e1SJiri Pirko 
276830c41e1SJiri Pirko 	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
277830c41e1SJiri Pirko 	if (!hdr)
278830c41e1SJiri Pirko 		return -EMSGSIZE;
279830c41e1SJiri Pirko 
280830c41e1SJiri Pirko 	if (devlink_nl_put_handle(msg, devlink))
281830c41e1SJiri Pirko 		goto genlmsg_cancel;
282830c41e1SJiri Pirko 
283830c41e1SJiri Pirko 	if (cmd == DEVLINK_CMD_PORT_PARAM_GET ||
284830c41e1SJiri Pirko 	    cmd == DEVLINK_CMD_PORT_PARAM_NEW ||
285830c41e1SJiri Pirko 	    cmd == DEVLINK_CMD_PORT_PARAM_DEL)
286830c41e1SJiri Pirko 		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, port_index))
287830c41e1SJiri Pirko 			goto genlmsg_cancel;
288830c41e1SJiri Pirko 
289830c41e1SJiri Pirko 	param_attr = nla_nest_start_noflag(msg, DEVLINK_ATTR_PARAM);
290830c41e1SJiri Pirko 	if (!param_attr)
291830c41e1SJiri Pirko 		goto genlmsg_cancel;
292830c41e1SJiri Pirko 	if (nla_put_string(msg, DEVLINK_ATTR_PARAM_NAME, param->name))
293830c41e1SJiri Pirko 		goto param_nest_cancel;
294830c41e1SJiri Pirko 	if (param->generic && nla_put_flag(msg, DEVLINK_ATTR_PARAM_GENERIC))
295830c41e1SJiri Pirko 		goto param_nest_cancel;
296830c41e1SJiri Pirko 
297830c41e1SJiri Pirko 	nla_type = devlink_param_type_to_nla_type(param->type);
298830c41e1SJiri Pirko 	if (nla_type < 0)
299830c41e1SJiri Pirko 		goto param_nest_cancel;
300830c41e1SJiri Pirko 	if (nla_put_u8(msg, DEVLINK_ATTR_PARAM_TYPE, nla_type))
301830c41e1SJiri Pirko 		goto param_nest_cancel;
302830c41e1SJiri Pirko 
303830c41e1SJiri Pirko 	param_values_list = nla_nest_start_noflag(msg,
304830c41e1SJiri Pirko 						  DEVLINK_ATTR_PARAM_VALUES_LIST);
305830c41e1SJiri Pirko 	if (!param_values_list)
306830c41e1SJiri Pirko 		goto param_nest_cancel;
307830c41e1SJiri Pirko 
308830c41e1SJiri Pirko 	for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
309830c41e1SJiri Pirko 		if (!param_value_set[i])
310830c41e1SJiri Pirko 			continue;
311830c41e1SJiri Pirko 		err = devlink_nl_param_value_fill_one(msg, param->type,
312830c41e1SJiri Pirko 						      i, param_value[i]);
313830c41e1SJiri Pirko 		if (err)
314830c41e1SJiri Pirko 			goto values_list_nest_cancel;
315830c41e1SJiri Pirko 	}
316830c41e1SJiri Pirko 
317830c41e1SJiri Pirko 	nla_nest_end(msg, param_values_list);
318830c41e1SJiri Pirko 	nla_nest_end(msg, param_attr);
319830c41e1SJiri Pirko 	genlmsg_end(msg, hdr);
320830c41e1SJiri Pirko 	return 0;
321830c41e1SJiri Pirko 
322830c41e1SJiri Pirko values_list_nest_cancel:
323830c41e1SJiri Pirko 	nla_nest_end(msg, param_values_list);
324830c41e1SJiri Pirko param_nest_cancel:
325830c41e1SJiri Pirko 	nla_nest_cancel(msg, param_attr);
326830c41e1SJiri Pirko genlmsg_cancel:
327830c41e1SJiri Pirko 	genlmsg_cancel(msg, hdr);
328830c41e1SJiri Pirko 	return -EMSGSIZE;
329830c41e1SJiri Pirko }
330830c41e1SJiri Pirko 
devlink_param_notify(struct devlink * devlink,unsigned int port_index,struct devlink_param_item * param_item,enum devlink_command cmd)331830c41e1SJiri Pirko static void devlink_param_notify(struct devlink *devlink,
332830c41e1SJiri Pirko 				 unsigned int port_index,
333830c41e1SJiri Pirko 				 struct devlink_param_item *param_item,
334830c41e1SJiri Pirko 				 enum devlink_command cmd)
335830c41e1SJiri Pirko {
336830c41e1SJiri Pirko 	struct sk_buff *msg;
337830c41e1SJiri Pirko 	int err;
338830c41e1SJiri Pirko 
339830c41e1SJiri Pirko 	WARN_ON(cmd != DEVLINK_CMD_PARAM_NEW && cmd != DEVLINK_CMD_PARAM_DEL &&
340830c41e1SJiri Pirko 		cmd != DEVLINK_CMD_PORT_PARAM_NEW &&
341830c41e1SJiri Pirko 		cmd != DEVLINK_CMD_PORT_PARAM_DEL);
342830c41e1SJiri Pirko 
343830c41e1SJiri Pirko 	/* devlink_notify_register() / devlink_notify_unregister()
344830c41e1SJiri Pirko 	 * will replay the notifications if the params are added/removed
345830c41e1SJiri Pirko 	 * outside of the lifetime of the instance.
346830c41e1SJiri Pirko 	 */
347cddbff47SJiri Pirko 	if (!devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
348830c41e1SJiri Pirko 		return;
349830c41e1SJiri Pirko 
350830c41e1SJiri Pirko 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
351830c41e1SJiri Pirko 	if (!msg)
352830c41e1SJiri Pirko 		return;
353830c41e1SJiri Pirko 	err = devlink_nl_param_fill(msg, devlink, port_index, param_item, cmd,
354830c41e1SJiri Pirko 				    0, 0, 0);
355830c41e1SJiri Pirko 	if (err) {
356830c41e1SJiri Pirko 		nlmsg_free(msg);
357830c41e1SJiri Pirko 		return;
358830c41e1SJiri Pirko 	}
359830c41e1SJiri Pirko 
3605648de0bSJiri Pirko 	devlink_nl_notify_send(devlink, msg);
361830c41e1SJiri Pirko }
362830c41e1SJiri Pirko 
devlink_params_notify(struct devlink * devlink,enum devlink_command cmd)363830c41e1SJiri Pirko static void devlink_params_notify(struct devlink *devlink,
364830c41e1SJiri Pirko 				  enum devlink_command cmd)
365830c41e1SJiri Pirko {
366830c41e1SJiri Pirko 	struct devlink_param_item *param_item;
367830c41e1SJiri Pirko 	unsigned long param_id;
368830c41e1SJiri Pirko 
369830c41e1SJiri Pirko 	xa_for_each(&devlink->params, param_id, param_item)
370830c41e1SJiri Pirko 		devlink_param_notify(devlink, 0, param_item, cmd);
371830c41e1SJiri Pirko }
372830c41e1SJiri Pirko 
devlink_params_notify_register(struct devlink * devlink)373830c41e1SJiri Pirko void devlink_params_notify_register(struct devlink *devlink)
374830c41e1SJiri Pirko {
375830c41e1SJiri Pirko 	devlink_params_notify(devlink, DEVLINK_CMD_PARAM_NEW);
376830c41e1SJiri Pirko }
377830c41e1SJiri Pirko 
devlink_params_notify_unregister(struct devlink * devlink)378830c41e1SJiri Pirko void devlink_params_notify_unregister(struct devlink *devlink)
379830c41e1SJiri Pirko {
380830c41e1SJiri Pirko 	devlink_params_notify(devlink, DEVLINK_CMD_PARAM_DEL);
381830c41e1SJiri Pirko }
382830c41e1SJiri Pirko 
devlink_nl_param_get_dump_one(struct sk_buff * msg,struct devlink * devlink,struct netlink_callback * cb,int flags)383830c41e1SJiri Pirko static int devlink_nl_param_get_dump_one(struct sk_buff *msg,
384830c41e1SJiri Pirko 					 struct devlink *devlink,
385830c41e1SJiri Pirko 					 struct netlink_callback *cb,
386830c41e1SJiri Pirko 					 int flags)
387830c41e1SJiri Pirko {
388830c41e1SJiri Pirko 	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
389830c41e1SJiri Pirko 	struct devlink_param_item *param_item;
390830c41e1SJiri Pirko 	unsigned long param_id;
391830c41e1SJiri Pirko 	int err = 0;
392830c41e1SJiri Pirko 
393830c41e1SJiri Pirko 	xa_for_each_start(&devlink->params, param_id, param_item, state->idx) {
394830c41e1SJiri Pirko 		err = devlink_nl_param_fill(msg, devlink, 0, param_item,
395830c41e1SJiri Pirko 					    DEVLINK_CMD_PARAM_GET,
396830c41e1SJiri Pirko 					    NETLINK_CB(cb->skb).portid,
397830c41e1SJiri Pirko 					    cb->nlh->nlmsg_seq, flags);
398830c41e1SJiri Pirko 		if (err == -EOPNOTSUPP) {
399830c41e1SJiri Pirko 			err = 0;
400830c41e1SJiri Pirko 		} else if (err) {
401830c41e1SJiri Pirko 			state->idx = param_id;
402830c41e1SJiri Pirko 			break;
403830c41e1SJiri Pirko 		}
404830c41e1SJiri Pirko 	}
405830c41e1SJiri Pirko 
406830c41e1SJiri Pirko 	return err;
407830c41e1SJiri Pirko }
408830c41e1SJiri Pirko 
devlink_nl_param_get_dumpit(struct sk_buff * skb,struct netlink_callback * cb)409830c41e1SJiri Pirko int devlink_nl_param_get_dumpit(struct sk_buff *skb,
410830c41e1SJiri Pirko 				struct netlink_callback *cb)
411830c41e1SJiri Pirko {
412830c41e1SJiri Pirko 	return devlink_nl_dumpit(skb, cb, devlink_nl_param_get_dump_one);
413830c41e1SJiri Pirko }
414830c41e1SJiri Pirko 
415830c41e1SJiri Pirko static int
devlink_param_type_get_from_info(struct genl_info * info,enum devlink_param_type * param_type)416830c41e1SJiri Pirko devlink_param_type_get_from_info(struct genl_info *info,
417830c41e1SJiri Pirko 				 enum devlink_param_type *param_type)
418830c41e1SJiri Pirko {
419830c41e1SJiri Pirko 	if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_TYPE))
420830c41e1SJiri Pirko 		return -EINVAL;
421830c41e1SJiri Pirko 
422830c41e1SJiri Pirko 	switch (nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_TYPE])) {
423830c41e1SJiri Pirko 	case NLA_U8:
424830c41e1SJiri Pirko 		*param_type = DEVLINK_PARAM_TYPE_U8;
425830c41e1SJiri Pirko 		break;
426830c41e1SJiri Pirko 	case NLA_U16:
427830c41e1SJiri Pirko 		*param_type = DEVLINK_PARAM_TYPE_U16;
428830c41e1SJiri Pirko 		break;
429830c41e1SJiri Pirko 	case NLA_U32:
430830c41e1SJiri Pirko 		*param_type = DEVLINK_PARAM_TYPE_U32;
431830c41e1SJiri Pirko 		break;
432830c41e1SJiri Pirko 	case NLA_STRING:
433830c41e1SJiri Pirko 		*param_type = DEVLINK_PARAM_TYPE_STRING;
434830c41e1SJiri Pirko 		break;
435830c41e1SJiri Pirko 	case NLA_FLAG:
436830c41e1SJiri Pirko 		*param_type = DEVLINK_PARAM_TYPE_BOOL;
437830c41e1SJiri Pirko 		break;
438830c41e1SJiri Pirko 	default:
439830c41e1SJiri Pirko 		return -EINVAL;
440830c41e1SJiri Pirko 	}
441830c41e1SJiri Pirko 
442830c41e1SJiri Pirko 	return 0;
443830c41e1SJiri Pirko }
444830c41e1SJiri Pirko 
445830c41e1SJiri Pirko static int
devlink_param_value_get_from_info(const struct devlink_param * param,struct genl_info * info,union devlink_param_value * value)446830c41e1SJiri Pirko devlink_param_value_get_from_info(const struct devlink_param *param,
447830c41e1SJiri Pirko 				  struct genl_info *info,
448830c41e1SJiri Pirko 				  union devlink_param_value *value)
449830c41e1SJiri Pirko {
450830c41e1SJiri Pirko 	struct nlattr *param_data;
451830c41e1SJiri Pirko 	int len;
452830c41e1SJiri Pirko 
453830c41e1SJiri Pirko 	param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
454830c41e1SJiri Pirko 
455830c41e1SJiri Pirko 	if (param->type != DEVLINK_PARAM_TYPE_BOOL && !param_data)
456830c41e1SJiri Pirko 		return -EINVAL;
457830c41e1SJiri Pirko 
458830c41e1SJiri Pirko 	switch (param->type) {
459830c41e1SJiri Pirko 	case DEVLINK_PARAM_TYPE_U8:
460830c41e1SJiri Pirko 		if (nla_len(param_data) != sizeof(u8))
461830c41e1SJiri Pirko 			return -EINVAL;
462830c41e1SJiri Pirko 		value->vu8 = nla_get_u8(param_data);
463830c41e1SJiri Pirko 		break;
464830c41e1SJiri Pirko 	case DEVLINK_PARAM_TYPE_U16:
465830c41e1SJiri Pirko 		if (nla_len(param_data) != sizeof(u16))
466830c41e1SJiri Pirko 			return -EINVAL;
467830c41e1SJiri Pirko 		value->vu16 = nla_get_u16(param_data);
468830c41e1SJiri Pirko 		break;
469830c41e1SJiri Pirko 	case DEVLINK_PARAM_TYPE_U32:
470830c41e1SJiri Pirko 		if (nla_len(param_data) != sizeof(u32))
471830c41e1SJiri Pirko 			return -EINVAL;
472830c41e1SJiri Pirko 		value->vu32 = nla_get_u32(param_data);
473830c41e1SJiri Pirko 		break;
474830c41e1SJiri Pirko 	case DEVLINK_PARAM_TYPE_STRING:
475830c41e1SJiri Pirko 		len = strnlen(nla_data(param_data), nla_len(param_data));
476830c41e1SJiri Pirko 		if (len == nla_len(param_data) ||
477830c41e1SJiri Pirko 		    len >= __DEVLINK_PARAM_MAX_STRING_VALUE)
478830c41e1SJiri Pirko 			return -EINVAL;
479830c41e1SJiri Pirko 		strcpy(value->vstr, nla_data(param_data));
480830c41e1SJiri Pirko 		break;
481830c41e1SJiri Pirko 	case DEVLINK_PARAM_TYPE_BOOL:
482830c41e1SJiri Pirko 		if (param_data && nla_len(param_data))
483830c41e1SJiri Pirko 			return -EINVAL;
484830c41e1SJiri Pirko 		value->vbool = nla_get_flag(param_data);
485830c41e1SJiri Pirko 		break;
486830c41e1SJiri Pirko 	}
487830c41e1SJiri Pirko 	return 0;
488830c41e1SJiri Pirko }
489830c41e1SJiri Pirko 
490830c41e1SJiri Pirko static struct devlink_param_item *
devlink_param_get_from_info(struct xarray * params,struct genl_info * info)491830c41e1SJiri Pirko devlink_param_get_from_info(struct xarray *params, struct genl_info *info)
492830c41e1SJiri Pirko {
493830c41e1SJiri Pirko 	char *param_name;
494830c41e1SJiri Pirko 
495830c41e1SJiri Pirko 	if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_NAME))
496830c41e1SJiri Pirko 		return NULL;
497830c41e1SJiri Pirko 
498830c41e1SJiri Pirko 	param_name = nla_data(info->attrs[DEVLINK_ATTR_PARAM_NAME]);
499830c41e1SJiri Pirko 	return devlink_param_find_by_name(params, param_name);
500830c41e1SJiri Pirko }
501830c41e1SJiri Pirko 
devlink_nl_param_get_doit(struct sk_buff * skb,struct genl_info * info)502830c41e1SJiri Pirko int devlink_nl_param_get_doit(struct sk_buff *skb,
503830c41e1SJiri Pirko 			      struct genl_info *info)
504830c41e1SJiri Pirko {
505830c41e1SJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
506830c41e1SJiri Pirko 	struct devlink_param_item *param_item;
507830c41e1SJiri Pirko 	struct sk_buff *msg;
508830c41e1SJiri Pirko 	int err;
509830c41e1SJiri Pirko 
510830c41e1SJiri Pirko 	param_item = devlink_param_get_from_info(&devlink->params, info);
511830c41e1SJiri Pirko 	if (!param_item)
512830c41e1SJiri Pirko 		return -EINVAL;
513830c41e1SJiri Pirko 
514830c41e1SJiri Pirko 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
515830c41e1SJiri Pirko 	if (!msg)
516830c41e1SJiri Pirko 		return -ENOMEM;
517830c41e1SJiri Pirko 
518830c41e1SJiri Pirko 	err = devlink_nl_param_fill(msg, devlink, 0, param_item,
519830c41e1SJiri Pirko 				    DEVLINK_CMD_PARAM_GET,
520830c41e1SJiri Pirko 				    info->snd_portid, info->snd_seq, 0);
521830c41e1SJiri Pirko 	if (err) {
522830c41e1SJiri Pirko 		nlmsg_free(msg);
523830c41e1SJiri Pirko 		return err;
524830c41e1SJiri Pirko 	}
525830c41e1SJiri Pirko 
526830c41e1SJiri Pirko 	return genlmsg_reply(msg, info);
527830c41e1SJiri Pirko }
528830c41e1SJiri Pirko 
__devlink_nl_cmd_param_set_doit(struct devlink * devlink,unsigned int port_index,struct xarray * params,struct genl_info * info,enum devlink_command cmd)529830c41e1SJiri Pirko static int __devlink_nl_cmd_param_set_doit(struct devlink *devlink,
530830c41e1SJiri Pirko 					   unsigned int port_index,
531830c41e1SJiri Pirko 					   struct xarray *params,
532830c41e1SJiri Pirko 					   struct genl_info *info,
533830c41e1SJiri Pirko 					   enum devlink_command cmd)
534830c41e1SJiri Pirko {
535830c41e1SJiri Pirko 	enum devlink_param_type param_type;
536830c41e1SJiri Pirko 	struct devlink_param_gset_ctx ctx;
537830c41e1SJiri Pirko 	enum devlink_param_cmode cmode;
538830c41e1SJiri Pirko 	struct devlink_param_item *param_item;
539830c41e1SJiri Pirko 	const struct devlink_param *param;
540830c41e1SJiri Pirko 	union devlink_param_value value;
541830c41e1SJiri Pirko 	int err = 0;
542830c41e1SJiri Pirko 
543830c41e1SJiri Pirko 	param_item = devlink_param_get_from_info(params, info);
544830c41e1SJiri Pirko 	if (!param_item)
545830c41e1SJiri Pirko 		return -EINVAL;
546830c41e1SJiri Pirko 	param = param_item->param;
547830c41e1SJiri Pirko 	err = devlink_param_type_get_from_info(info, &param_type);
548830c41e1SJiri Pirko 	if (err)
549830c41e1SJiri Pirko 		return err;
550830c41e1SJiri Pirko 	if (param_type != param->type)
551830c41e1SJiri Pirko 		return -EINVAL;
552830c41e1SJiri Pirko 	err = devlink_param_value_get_from_info(param, info, &value);
553830c41e1SJiri Pirko 	if (err)
554830c41e1SJiri Pirko 		return err;
555830c41e1SJiri Pirko 	if (param->validate) {
556830c41e1SJiri Pirko 		err = param->validate(devlink, param->id, value, info->extack);
557830c41e1SJiri Pirko 		if (err)
558830c41e1SJiri Pirko 			return err;
559830c41e1SJiri Pirko 	}
560830c41e1SJiri Pirko 
561830c41e1SJiri Pirko 	if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_PARAM_VALUE_CMODE))
562830c41e1SJiri Pirko 		return -EINVAL;
563830c41e1SJiri Pirko 	cmode = nla_get_u8(info->attrs[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
564830c41e1SJiri Pirko 	if (!devlink_param_cmode_is_supported(param, cmode))
565830c41e1SJiri Pirko 		return -EOPNOTSUPP;
566830c41e1SJiri Pirko 
567830c41e1SJiri Pirko 	if (cmode == DEVLINK_PARAM_CMODE_DRIVERINIT) {
568830c41e1SJiri Pirko 		param_item->driverinit_value_new = value;
569830c41e1SJiri Pirko 		param_item->driverinit_value_new_valid = true;
570830c41e1SJiri Pirko 	} else {
571830c41e1SJiri Pirko 		if (!param->set)
572830c41e1SJiri Pirko 			return -EOPNOTSUPP;
573830c41e1SJiri Pirko 		ctx.val = value;
574830c41e1SJiri Pirko 		ctx.cmode = cmode;
575*5625ca56SMateusz Polchlopek 		err = devlink_param_set(devlink, param, &ctx, info->extack);
576830c41e1SJiri Pirko 		if (err)
577830c41e1SJiri Pirko 			return err;
578830c41e1SJiri Pirko 	}
579830c41e1SJiri Pirko 
580830c41e1SJiri Pirko 	devlink_param_notify(devlink, port_index, param_item, cmd);
581830c41e1SJiri Pirko 	return 0;
582830c41e1SJiri Pirko }
583830c41e1SJiri Pirko 
devlink_nl_param_set_doit(struct sk_buff * skb,struct genl_info * info)58453590934SJiri Pirko int devlink_nl_param_set_doit(struct sk_buff *skb, struct genl_info *info)
585830c41e1SJiri Pirko {
586830c41e1SJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
587830c41e1SJiri Pirko 
588830c41e1SJiri Pirko 	return __devlink_nl_cmd_param_set_doit(devlink, 0, &devlink->params,
589830c41e1SJiri Pirko 					       info, DEVLINK_CMD_PARAM_NEW);
590830c41e1SJiri Pirko }
591830c41e1SJiri Pirko 
devlink_nl_port_param_get_dumpit(struct sk_buff * msg,struct netlink_callback * cb)59253590934SJiri Pirko int devlink_nl_port_param_get_dumpit(struct sk_buff *msg,
593830c41e1SJiri Pirko 				     struct netlink_callback *cb)
594830c41e1SJiri Pirko {
595830c41e1SJiri Pirko 	NL_SET_ERR_MSG(cb->extack, "Port params are not supported");
596830c41e1SJiri Pirko 	return msg->len;
597830c41e1SJiri Pirko }
598830c41e1SJiri Pirko 
devlink_nl_port_param_get_doit(struct sk_buff * skb,struct genl_info * info)59953590934SJiri Pirko int devlink_nl_port_param_get_doit(struct sk_buff *skb,
600830c41e1SJiri Pirko 				   struct genl_info *info)
601830c41e1SJiri Pirko {
602830c41e1SJiri Pirko 	NL_SET_ERR_MSG(info->extack, "Port params are not supported");
603830c41e1SJiri Pirko 	return -EINVAL;
604830c41e1SJiri Pirko }
605830c41e1SJiri Pirko 
devlink_nl_port_param_set_doit(struct sk_buff * skb,struct genl_info * info)60653590934SJiri Pirko int devlink_nl_port_param_set_doit(struct sk_buff *skb,
607830c41e1SJiri Pirko 				   struct genl_info *info)
608830c41e1SJiri Pirko {
609830c41e1SJiri Pirko 	NL_SET_ERR_MSG(info->extack, "Port params are not supported");
610830c41e1SJiri Pirko 	return -EINVAL;
611830c41e1SJiri Pirko }
612830c41e1SJiri Pirko 
devlink_param_verify(const struct devlink_param * param)613830c41e1SJiri Pirko static int devlink_param_verify(const struct devlink_param *param)
614830c41e1SJiri Pirko {
615830c41e1SJiri Pirko 	if (!param || !param->name || !param->supported_cmodes)
616830c41e1SJiri Pirko 		return -EINVAL;
617830c41e1SJiri Pirko 	if (param->generic)
618830c41e1SJiri Pirko 		return devlink_param_generic_verify(param);
619830c41e1SJiri Pirko 	else
620830c41e1SJiri Pirko 		return devlink_param_driver_verify(param);
621830c41e1SJiri Pirko }
622830c41e1SJiri Pirko 
devlink_param_register(struct devlink * devlink,const struct devlink_param * param)623830c41e1SJiri Pirko static int devlink_param_register(struct devlink *devlink,
624830c41e1SJiri Pirko 				  const struct devlink_param *param)
625830c41e1SJiri Pirko {
626830c41e1SJiri Pirko 	struct devlink_param_item *param_item;
627830c41e1SJiri Pirko 	int err;
628830c41e1SJiri Pirko 
629830c41e1SJiri Pirko 	WARN_ON(devlink_param_verify(param));
630830c41e1SJiri Pirko 	WARN_ON(devlink_param_find_by_name(&devlink->params, param->name));
631830c41e1SJiri Pirko 
632830c41e1SJiri Pirko 	if (param->supported_cmodes == BIT(DEVLINK_PARAM_CMODE_DRIVERINIT))
633830c41e1SJiri Pirko 		WARN_ON(param->get || param->set);
634830c41e1SJiri Pirko 	else
635830c41e1SJiri Pirko 		WARN_ON(!param->get || !param->set);
636830c41e1SJiri Pirko 
637830c41e1SJiri Pirko 	param_item = kzalloc(sizeof(*param_item), GFP_KERNEL);
638830c41e1SJiri Pirko 	if (!param_item)
639830c41e1SJiri Pirko 		return -ENOMEM;
640830c41e1SJiri Pirko 
641830c41e1SJiri Pirko 	param_item->param = param;
642830c41e1SJiri Pirko 
643830c41e1SJiri Pirko 	err = xa_insert(&devlink->params, param->id, param_item, GFP_KERNEL);
644830c41e1SJiri Pirko 	if (err)
645830c41e1SJiri Pirko 		goto err_xa_insert;
646830c41e1SJiri Pirko 
647830c41e1SJiri Pirko 	devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
648830c41e1SJiri Pirko 	return 0;
649830c41e1SJiri Pirko 
650830c41e1SJiri Pirko err_xa_insert:
651830c41e1SJiri Pirko 	kfree(param_item);
652830c41e1SJiri Pirko 	return err;
653830c41e1SJiri Pirko }
654830c41e1SJiri Pirko 
devlink_param_unregister(struct devlink * devlink,const struct devlink_param * param)655830c41e1SJiri Pirko static void devlink_param_unregister(struct devlink *devlink,
656830c41e1SJiri Pirko 				     const struct devlink_param *param)
657830c41e1SJiri Pirko {
658830c41e1SJiri Pirko 	struct devlink_param_item *param_item;
659830c41e1SJiri Pirko 
660830c41e1SJiri Pirko 	param_item = devlink_param_find_by_id(&devlink->params, param->id);
661830c41e1SJiri Pirko 	if (WARN_ON(!param_item))
662830c41e1SJiri Pirko 		return;
663830c41e1SJiri Pirko 	devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_DEL);
664830c41e1SJiri Pirko 	xa_erase(&devlink->params, param->id);
665830c41e1SJiri Pirko 	kfree(param_item);
666830c41e1SJiri Pirko }
667830c41e1SJiri Pirko 
668830c41e1SJiri Pirko /**
669830c41e1SJiri Pirko  *	devl_params_register - register configuration parameters
670830c41e1SJiri Pirko  *
671830c41e1SJiri Pirko  *	@devlink: devlink
672830c41e1SJiri Pirko  *	@params: configuration parameters array
673830c41e1SJiri Pirko  *	@params_count: number of parameters provided
674830c41e1SJiri Pirko  *
675830c41e1SJiri Pirko  *	Register the configuration parameters supported by the driver.
676830c41e1SJiri Pirko  */
devl_params_register(struct devlink * devlink,const struct devlink_param * params,size_t params_count)677830c41e1SJiri Pirko int devl_params_register(struct devlink *devlink,
678830c41e1SJiri Pirko 			 const struct devlink_param *params,
679830c41e1SJiri Pirko 			 size_t params_count)
680830c41e1SJiri Pirko {
681830c41e1SJiri Pirko 	const struct devlink_param *param = params;
682830c41e1SJiri Pirko 	int i, err;
683830c41e1SJiri Pirko 
684830c41e1SJiri Pirko 	lockdep_assert_held(&devlink->lock);
685830c41e1SJiri Pirko 
686830c41e1SJiri Pirko 	for (i = 0; i < params_count; i++, param++) {
687830c41e1SJiri Pirko 		err = devlink_param_register(devlink, param);
688830c41e1SJiri Pirko 		if (err)
689830c41e1SJiri Pirko 			goto rollback;
690830c41e1SJiri Pirko 	}
691830c41e1SJiri Pirko 	return 0;
692830c41e1SJiri Pirko 
693830c41e1SJiri Pirko rollback:
694830c41e1SJiri Pirko 	if (!i)
695830c41e1SJiri Pirko 		return err;
696830c41e1SJiri Pirko 
697830c41e1SJiri Pirko 	for (param--; i > 0; i--, param--)
698830c41e1SJiri Pirko 		devlink_param_unregister(devlink, param);
699830c41e1SJiri Pirko 	return err;
700830c41e1SJiri Pirko }
701830c41e1SJiri Pirko EXPORT_SYMBOL_GPL(devl_params_register);
702830c41e1SJiri Pirko 
devlink_params_register(struct devlink * devlink,const struct devlink_param * params,size_t params_count)703830c41e1SJiri Pirko int devlink_params_register(struct devlink *devlink,
704830c41e1SJiri Pirko 			    const struct devlink_param *params,
705830c41e1SJiri Pirko 			    size_t params_count)
706830c41e1SJiri Pirko {
707830c41e1SJiri Pirko 	int err;
708830c41e1SJiri Pirko 
709830c41e1SJiri Pirko 	devl_lock(devlink);
710830c41e1SJiri Pirko 	err = devl_params_register(devlink, params, params_count);
711830c41e1SJiri Pirko 	devl_unlock(devlink);
712830c41e1SJiri Pirko 	return err;
713830c41e1SJiri Pirko }
714830c41e1SJiri Pirko EXPORT_SYMBOL_GPL(devlink_params_register);
715830c41e1SJiri Pirko 
716830c41e1SJiri Pirko /**
717830c41e1SJiri Pirko  *	devl_params_unregister - unregister configuration parameters
718830c41e1SJiri Pirko  *	@devlink: devlink
719830c41e1SJiri Pirko  *	@params: configuration parameters to unregister
720830c41e1SJiri Pirko  *	@params_count: number of parameters provided
721830c41e1SJiri Pirko  */
devl_params_unregister(struct devlink * devlink,const struct devlink_param * params,size_t params_count)722830c41e1SJiri Pirko void devl_params_unregister(struct devlink *devlink,
723830c41e1SJiri Pirko 			    const struct devlink_param *params,
724830c41e1SJiri Pirko 			    size_t params_count)
725830c41e1SJiri Pirko {
726830c41e1SJiri Pirko 	const struct devlink_param *param = params;
727830c41e1SJiri Pirko 	int i;
728830c41e1SJiri Pirko 
729830c41e1SJiri Pirko 	lockdep_assert_held(&devlink->lock);
730830c41e1SJiri Pirko 
731830c41e1SJiri Pirko 	for (i = 0; i < params_count; i++, param++)
732830c41e1SJiri Pirko 		devlink_param_unregister(devlink, param);
733830c41e1SJiri Pirko }
734830c41e1SJiri Pirko EXPORT_SYMBOL_GPL(devl_params_unregister);
735830c41e1SJiri Pirko 
devlink_params_unregister(struct devlink * devlink,const struct devlink_param * params,size_t params_count)736830c41e1SJiri Pirko void devlink_params_unregister(struct devlink *devlink,
737830c41e1SJiri Pirko 			       const struct devlink_param *params,
738830c41e1SJiri Pirko 			       size_t params_count)
739830c41e1SJiri Pirko {
740830c41e1SJiri Pirko 	devl_lock(devlink);
741830c41e1SJiri Pirko 	devl_params_unregister(devlink, params, params_count);
742830c41e1SJiri Pirko 	devl_unlock(devlink);
743830c41e1SJiri Pirko }
744830c41e1SJiri Pirko EXPORT_SYMBOL_GPL(devlink_params_unregister);
745830c41e1SJiri Pirko 
746830c41e1SJiri Pirko /**
747830c41e1SJiri Pirko  *	devl_param_driverinit_value_get - get configuration parameter
748830c41e1SJiri Pirko  *					  value for driver initializing
749830c41e1SJiri Pirko  *
750830c41e1SJiri Pirko  *	@devlink: devlink
751830c41e1SJiri Pirko  *	@param_id: parameter ID
752830c41e1SJiri Pirko  *	@val: pointer to store the value of parameter in driverinit
753830c41e1SJiri Pirko  *	      configuration mode
754830c41e1SJiri Pirko  *
755830c41e1SJiri Pirko  *	This function should be used by the driver to get driverinit
756830c41e1SJiri Pirko  *	configuration for initialization after reload command.
757830c41e1SJiri Pirko  *
758830c41e1SJiri Pirko  *	Note that lockless call of this function relies on the
759830c41e1SJiri Pirko  *	driver to maintain following basic sane behavior:
760830c41e1SJiri Pirko  *	1) Driver ensures a call to this function cannot race with
761830c41e1SJiri Pirko  *	   registering/unregistering the parameter with the same parameter ID.
762830c41e1SJiri Pirko  *	2) Driver ensures a call to this function cannot race with
763830c41e1SJiri Pirko  *	   devl_param_driverinit_value_set() call with the same parameter ID.
764830c41e1SJiri Pirko  *	3) Driver ensures a call to this function cannot race with
765830c41e1SJiri Pirko  *	   reload operation.
766830c41e1SJiri Pirko  *	If the driver is not able to comply, it has to take the devlink->lock
767830c41e1SJiri Pirko  *	while calling this.
768830c41e1SJiri Pirko  */
devl_param_driverinit_value_get(struct devlink * devlink,u32 param_id,union devlink_param_value * val)769830c41e1SJiri Pirko int devl_param_driverinit_value_get(struct devlink *devlink, u32 param_id,
770830c41e1SJiri Pirko 				    union devlink_param_value *val)
771830c41e1SJiri Pirko {
772830c41e1SJiri Pirko 	struct devlink_param_item *param_item;
773830c41e1SJiri Pirko 
774830c41e1SJiri Pirko 	if (WARN_ON(!devlink_reload_supported(devlink->ops)))
775830c41e1SJiri Pirko 		return -EOPNOTSUPP;
776830c41e1SJiri Pirko 
777830c41e1SJiri Pirko 	param_item = devlink_param_find_by_id(&devlink->params, param_id);
778830c41e1SJiri Pirko 	if (!param_item)
779830c41e1SJiri Pirko 		return -EINVAL;
780830c41e1SJiri Pirko 
781830c41e1SJiri Pirko 	if (!param_item->driverinit_value_valid)
782830c41e1SJiri Pirko 		return -EOPNOTSUPP;
783830c41e1SJiri Pirko 
784830c41e1SJiri Pirko 	if (WARN_ON(!devlink_param_cmode_is_supported(param_item->param,
785830c41e1SJiri Pirko 						      DEVLINK_PARAM_CMODE_DRIVERINIT)))
786830c41e1SJiri Pirko 		return -EOPNOTSUPP;
787830c41e1SJiri Pirko 
788830c41e1SJiri Pirko 	*val = param_item->driverinit_value;
789830c41e1SJiri Pirko 
790830c41e1SJiri Pirko 	return 0;
791830c41e1SJiri Pirko }
792830c41e1SJiri Pirko EXPORT_SYMBOL_GPL(devl_param_driverinit_value_get);
793830c41e1SJiri Pirko 
794830c41e1SJiri Pirko /**
795830c41e1SJiri Pirko  *	devl_param_driverinit_value_set - set value of configuration
796830c41e1SJiri Pirko  *					  parameter for driverinit
797830c41e1SJiri Pirko  *					  configuration mode
798830c41e1SJiri Pirko  *
799830c41e1SJiri Pirko  *	@devlink: devlink
800830c41e1SJiri Pirko  *	@param_id: parameter ID
801830c41e1SJiri Pirko  *	@init_val: value of parameter to set for driverinit configuration mode
802830c41e1SJiri Pirko  *
803830c41e1SJiri Pirko  *	This function should be used by the driver to set driverinit
804830c41e1SJiri Pirko  *	configuration mode default value.
805830c41e1SJiri Pirko  */
devl_param_driverinit_value_set(struct devlink * devlink,u32 param_id,union devlink_param_value init_val)806830c41e1SJiri Pirko void devl_param_driverinit_value_set(struct devlink *devlink, u32 param_id,
807830c41e1SJiri Pirko 				     union devlink_param_value init_val)
808830c41e1SJiri Pirko {
809830c41e1SJiri Pirko 	struct devlink_param_item *param_item;
810830c41e1SJiri Pirko 
811830c41e1SJiri Pirko 	devl_assert_locked(devlink);
812830c41e1SJiri Pirko 
813830c41e1SJiri Pirko 	param_item = devlink_param_find_by_id(&devlink->params, param_id);
814830c41e1SJiri Pirko 	if (WARN_ON(!param_item))
815830c41e1SJiri Pirko 		return;
816830c41e1SJiri Pirko 
817830c41e1SJiri Pirko 	if (WARN_ON(!devlink_param_cmode_is_supported(param_item->param,
818830c41e1SJiri Pirko 						      DEVLINK_PARAM_CMODE_DRIVERINIT)))
819830c41e1SJiri Pirko 		return;
820830c41e1SJiri Pirko 
821830c41e1SJiri Pirko 	param_item->driverinit_value = init_val;
822830c41e1SJiri Pirko 	param_item->driverinit_value_valid = true;
823830c41e1SJiri Pirko 
824830c41e1SJiri Pirko 	devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
825830c41e1SJiri Pirko }
826830c41e1SJiri Pirko EXPORT_SYMBOL_GPL(devl_param_driverinit_value_set);
827830c41e1SJiri Pirko 
devlink_params_driverinit_load_new(struct devlink * devlink)828830c41e1SJiri Pirko void devlink_params_driverinit_load_new(struct devlink *devlink)
829830c41e1SJiri Pirko {
830830c41e1SJiri Pirko 	struct devlink_param_item *param_item;
831830c41e1SJiri Pirko 	unsigned long param_id;
832830c41e1SJiri Pirko 
833830c41e1SJiri Pirko 	xa_for_each(&devlink->params, param_id, param_item) {
834830c41e1SJiri Pirko 		if (!devlink_param_cmode_is_supported(param_item->param,
835830c41e1SJiri Pirko 						      DEVLINK_PARAM_CMODE_DRIVERINIT) ||
836830c41e1SJiri Pirko 		    !param_item->driverinit_value_new_valid)
837830c41e1SJiri Pirko 			continue;
838830c41e1SJiri Pirko 		param_item->driverinit_value = param_item->driverinit_value_new;
839830c41e1SJiri Pirko 		param_item->driverinit_value_valid = true;
840830c41e1SJiri Pirko 		param_item->driverinit_value_new_valid = false;
841830c41e1SJiri Pirko 	}
842830c41e1SJiri Pirko }
843830c41e1SJiri Pirko 
844830c41e1SJiri Pirko /**
845830c41e1SJiri Pirko  *	devl_param_value_changed - notify devlink on a parameter's value
846830c41e1SJiri Pirko  *				   change. Should be called by the driver
847830c41e1SJiri Pirko  *				   right after the change.
848830c41e1SJiri Pirko  *
849830c41e1SJiri Pirko  *	@devlink: devlink
850830c41e1SJiri Pirko  *	@param_id: parameter ID
851830c41e1SJiri Pirko  *
852830c41e1SJiri Pirko  *	This function should be used by the driver to notify devlink on value
853830c41e1SJiri Pirko  *	change, excluding driverinit configuration mode.
854830c41e1SJiri Pirko  *	For driverinit configuration mode driver should use the function
855830c41e1SJiri Pirko  */
devl_param_value_changed(struct devlink * devlink,u32 param_id)856830c41e1SJiri Pirko void devl_param_value_changed(struct devlink *devlink, u32 param_id)
857830c41e1SJiri Pirko {
858830c41e1SJiri Pirko 	struct devlink_param_item *param_item;
859830c41e1SJiri Pirko 
860830c41e1SJiri Pirko 	param_item = devlink_param_find_by_id(&devlink->params, param_id);
861830c41e1SJiri Pirko 	WARN_ON(!param_item);
862830c41e1SJiri Pirko 
863830c41e1SJiri Pirko 	devlink_param_notify(devlink, 0, param_item, DEVLINK_CMD_PARAM_NEW);
864830c41e1SJiri Pirko }
865830c41e1SJiri Pirko EXPORT_SYMBOL_GPL(devl_param_value_changed);
866