xref: /linux-6.15/net/devlink/resource.c (revision e3302f9a)
1a9f96007SJiri Pirko // SPDX-License-Identifier: GPL-2.0-or-later
2a9f96007SJiri Pirko /*
3a9f96007SJiri Pirko  * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4a9f96007SJiri Pirko  * Copyright (c) 2016 Jiri Pirko <[email protected]>
5a9f96007SJiri Pirko  */
6a9f96007SJiri Pirko 
7a9f96007SJiri Pirko #include "devl_internal.h"
8a9f96007SJiri Pirko 
9a9f96007SJiri Pirko /**
10a9f96007SJiri Pirko  * struct devlink_resource - devlink resource
11a9f96007SJiri Pirko  * @name: name of the resource
12a9f96007SJiri Pirko  * @id: id, per devlink instance
13a9f96007SJiri Pirko  * @size: size of the resource
14a9f96007SJiri Pirko  * @size_new: updated size of the resource, reload is needed
15a9f96007SJiri Pirko  * @size_valid: valid in case the total size of the resource is valid
16a9f96007SJiri Pirko  *              including its children
17a9f96007SJiri Pirko  * @parent: parent resource
18a9f96007SJiri Pirko  * @size_params: size parameters
19a9f96007SJiri Pirko  * @list: parent list
20a9f96007SJiri Pirko  * @resource_list: list of child resources
21a9f96007SJiri Pirko  * @occ_get: occupancy getter callback
22a9f96007SJiri Pirko  * @occ_get_priv: occupancy getter callback priv
23a9f96007SJiri Pirko  */
24a9f96007SJiri Pirko struct devlink_resource {
25a9f96007SJiri Pirko 	const char *name;
26a9f96007SJiri Pirko 	u64 id;
27a9f96007SJiri Pirko 	u64 size;
28a9f96007SJiri Pirko 	u64 size_new;
29a9f96007SJiri Pirko 	bool size_valid;
30a9f96007SJiri Pirko 	struct devlink_resource *parent;
31a9f96007SJiri Pirko 	struct devlink_resource_size_params size_params;
32a9f96007SJiri Pirko 	struct list_head list;
33a9f96007SJiri Pirko 	struct list_head resource_list;
34a9f96007SJiri Pirko 	devlink_resource_occ_get_t *occ_get;
35a9f96007SJiri Pirko 	void *occ_get_priv;
36a9f96007SJiri Pirko };
37a9f96007SJiri Pirko 
38a9f96007SJiri Pirko static struct devlink_resource *
devlink_resource_find(struct devlink * devlink,struct devlink_resource * resource,u64 resource_id)39a9f96007SJiri Pirko devlink_resource_find(struct devlink *devlink,
40a9f96007SJiri Pirko 		      struct devlink_resource *resource, u64 resource_id)
41a9f96007SJiri Pirko {
42a9f96007SJiri Pirko 	struct list_head *resource_list;
43a9f96007SJiri Pirko 
44a9f96007SJiri Pirko 	if (resource)
45a9f96007SJiri Pirko 		resource_list = &resource->resource_list;
46a9f96007SJiri Pirko 	else
47a9f96007SJiri Pirko 		resource_list = &devlink->resource_list;
48a9f96007SJiri Pirko 
49a9f96007SJiri Pirko 	list_for_each_entry(resource, resource_list, list) {
50a9f96007SJiri Pirko 		struct devlink_resource *child_resource;
51a9f96007SJiri Pirko 
52a9f96007SJiri Pirko 		if (resource->id == resource_id)
53a9f96007SJiri Pirko 			return resource;
54a9f96007SJiri Pirko 
55a9f96007SJiri Pirko 		child_resource = devlink_resource_find(devlink, resource,
56a9f96007SJiri Pirko 						       resource_id);
57a9f96007SJiri Pirko 		if (child_resource)
58a9f96007SJiri Pirko 			return child_resource;
59a9f96007SJiri Pirko 	}
60a9f96007SJiri Pirko 	return NULL;
61a9f96007SJiri Pirko }
62a9f96007SJiri Pirko 
63a9f96007SJiri Pirko static void
devlink_resource_validate_children(struct devlink_resource * resource)64a9f96007SJiri Pirko devlink_resource_validate_children(struct devlink_resource *resource)
65a9f96007SJiri Pirko {
66a9f96007SJiri Pirko 	struct devlink_resource *child_resource;
67a9f96007SJiri Pirko 	bool size_valid = true;
68a9f96007SJiri Pirko 	u64 parts_size = 0;
69a9f96007SJiri Pirko 
70a9f96007SJiri Pirko 	if (list_empty(&resource->resource_list))
71a9f96007SJiri Pirko 		goto out;
72a9f96007SJiri Pirko 
73a9f96007SJiri Pirko 	list_for_each_entry(child_resource, &resource->resource_list, list)
74a9f96007SJiri Pirko 		parts_size += child_resource->size_new;
75a9f96007SJiri Pirko 
76a9f96007SJiri Pirko 	if (parts_size > resource->size_new)
77a9f96007SJiri Pirko 		size_valid = false;
78a9f96007SJiri Pirko out:
79a9f96007SJiri Pirko 	resource->size_valid = size_valid;
80a9f96007SJiri Pirko }
81a9f96007SJiri Pirko 
82a9f96007SJiri Pirko static int
devlink_resource_validate_size(struct devlink_resource * resource,u64 size,struct netlink_ext_ack * extack)83a9f96007SJiri Pirko devlink_resource_validate_size(struct devlink_resource *resource, u64 size,
84a9f96007SJiri Pirko 			       struct netlink_ext_ack *extack)
85a9f96007SJiri Pirko {
86a9f96007SJiri Pirko 	u64 reminder;
87a9f96007SJiri Pirko 	int err = 0;
88a9f96007SJiri Pirko 
89a9f96007SJiri Pirko 	if (size > resource->size_params.size_max) {
90a9f96007SJiri Pirko 		NL_SET_ERR_MSG(extack, "Size larger than maximum");
91a9f96007SJiri Pirko 		err = -EINVAL;
92a9f96007SJiri Pirko 	}
93a9f96007SJiri Pirko 
94a9f96007SJiri Pirko 	if (size < resource->size_params.size_min) {
95a9f96007SJiri Pirko 		NL_SET_ERR_MSG(extack, "Size smaller than minimum");
96a9f96007SJiri Pirko 		err = -EINVAL;
97a9f96007SJiri Pirko 	}
98a9f96007SJiri Pirko 
99a9f96007SJiri Pirko 	div64_u64_rem(size, resource->size_params.size_granularity, &reminder);
100a9f96007SJiri Pirko 	if (reminder) {
101a9f96007SJiri Pirko 		NL_SET_ERR_MSG(extack, "Wrong granularity");
102a9f96007SJiri Pirko 		err = -EINVAL;
103a9f96007SJiri Pirko 	}
104a9f96007SJiri Pirko 
105a9f96007SJiri Pirko 	return err;
106a9f96007SJiri Pirko }
107a9f96007SJiri Pirko 
devlink_nl_resource_set_doit(struct sk_buff * skb,struct genl_info * info)10853590934SJiri Pirko int devlink_nl_resource_set_doit(struct sk_buff *skb, struct genl_info *info)
109a9f96007SJiri Pirko {
110a9f96007SJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
111a9f96007SJiri Pirko 	struct devlink_resource *resource;
112a9f96007SJiri Pirko 	u64 resource_id;
113a9f96007SJiri Pirko 	u64 size;
114a9f96007SJiri Pirko 	int err;
115a9f96007SJiri Pirko 
116a9f96007SJiri Pirko 	if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_RESOURCE_ID) ||
117a9f96007SJiri Pirko 	    GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_RESOURCE_SIZE))
118a9f96007SJiri Pirko 		return -EINVAL;
119a9f96007SJiri Pirko 	resource_id = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_ID]);
120a9f96007SJiri Pirko 
121a9f96007SJiri Pirko 	resource = devlink_resource_find(devlink, NULL, resource_id);
122a9f96007SJiri Pirko 	if (!resource)
123a9f96007SJiri Pirko 		return -EINVAL;
124a9f96007SJiri Pirko 
125a9f96007SJiri Pirko 	size = nla_get_u64(info->attrs[DEVLINK_ATTR_RESOURCE_SIZE]);
126a9f96007SJiri Pirko 	err = devlink_resource_validate_size(resource, size, info->extack);
127a9f96007SJiri Pirko 	if (err)
128a9f96007SJiri Pirko 		return err;
129a9f96007SJiri Pirko 
130a9f96007SJiri Pirko 	resource->size_new = size;
131a9f96007SJiri Pirko 	devlink_resource_validate_children(resource);
132a9f96007SJiri Pirko 	if (resource->parent)
133a9f96007SJiri Pirko 		devlink_resource_validate_children(resource->parent);
134a9f96007SJiri Pirko 	return 0;
135a9f96007SJiri Pirko }
136a9f96007SJiri Pirko 
137a9f96007SJiri Pirko static int
devlink_resource_size_params_put(struct devlink_resource * resource,struct sk_buff * skb)138a9f96007SJiri Pirko devlink_resource_size_params_put(struct devlink_resource *resource,
139a9f96007SJiri Pirko 				 struct sk_buff *skb)
140a9f96007SJiri Pirko {
141a9f96007SJiri Pirko 	struct devlink_resource_size_params *size_params;
142a9f96007SJiri Pirko 
143a9f96007SJiri Pirko 	size_params = &resource->size_params;
144a788acf1SPrzemek Kitszel 	if (devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
145a788acf1SPrzemek Kitszel 			       size_params->size_granularity) ||
146a788acf1SPrzemek Kitszel 	    devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
147a788acf1SPrzemek Kitszel 			       size_params->size_max) ||
148a788acf1SPrzemek Kitszel 	    devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
149a788acf1SPrzemek Kitszel 			       size_params->size_min) ||
150a9f96007SJiri Pirko 	    nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
151a9f96007SJiri Pirko 		return -EMSGSIZE;
152a9f96007SJiri Pirko 	return 0;
153a9f96007SJiri Pirko }
154a9f96007SJiri Pirko 
devlink_resource_occ_put(struct devlink_resource * resource,struct sk_buff * skb)155a9f96007SJiri Pirko static int devlink_resource_occ_put(struct devlink_resource *resource,
156a9f96007SJiri Pirko 				    struct sk_buff *skb)
157a9f96007SJiri Pirko {
158a9f96007SJiri Pirko 	if (!resource->occ_get)
159a9f96007SJiri Pirko 		return 0;
160a788acf1SPrzemek Kitszel 	return devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_OCC,
161a788acf1SPrzemek Kitszel 				  resource->occ_get(resource->occ_get_priv));
162a9f96007SJiri Pirko }
163a9f96007SJiri Pirko 
devlink_resource_put(struct devlink * devlink,struct sk_buff * skb,struct devlink_resource * resource)164a9f96007SJiri Pirko static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
165a9f96007SJiri Pirko 				struct devlink_resource *resource)
166a9f96007SJiri Pirko {
167a9f96007SJiri Pirko 	struct devlink_resource *child_resource;
168a9f96007SJiri Pirko 	struct nlattr *child_resource_attr;
169a9f96007SJiri Pirko 	struct nlattr *resource_attr;
170a9f96007SJiri Pirko 
171a9f96007SJiri Pirko 	resource_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_RESOURCE);
172a9f96007SJiri Pirko 	if (!resource_attr)
173a9f96007SJiri Pirko 		return -EMSGSIZE;
174a9f96007SJiri Pirko 
175a9f96007SJiri Pirko 	if (nla_put_string(skb, DEVLINK_ATTR_RESOURCE_NAME, resource->name) ||
176a788acf1SPrzemek Kitszel 	    devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE, resource->size) ||
177a788acf1SPrzemek Kitszel 	    devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_ID, resource->id))
178a9f96007SJiri Pirko 		goto nla_put_failure;
179a9f96007SJiri Pirko 	if (resource->size != resource->size_new &&
180a788acf1SPrzemek Kitszel 	    devlink_nl_put_u64(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
181a788acf1SPrzemek Kitszel 			       resource->size_new))
182a9f96007SJiri Pirko 		goto nla_put_failure;
183a9f96007SJiri Pirko 	if (devlink_resource_occ_put(resource, skb))
184a9f96007SJiri Pirko 		goto nla_put_failure;
185a9f96007SJiri Pirko 	if (devlink_resource_size_params_put(resource, skb))
186a9f96007SJiri Pirko 		goto nla_put_failure;
187a9f96007SJiri Pirko 	if (list_empty(&resource->resource_list))
188a9f96007SJiri Pirko 		goto out;
189a9f96007SJiri Pirko 
190a9f96007SJiri Pirko 	if (nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_SIZE_VALID,
191a9f96007SJiri Pirko 		       resource->size_valid))
192a9f96007SJiri Pirko 		goto nla_put_failure;
193a9f96007SJiri Pirko 
194a9f96007SJiri Pirko 	child_resource_attr = nla_nest_start_noflag(skb,
195a9f96007SJiri Pirko 						    DEVLINK_ATTR_RESOURCE_LIST);
196a9f96007SJiri Pirko 	if (!child_resource_attr)
197a9f96007SJiri Pirko 		goto nla_put_failure;
198a9f96007SJiri Pirko 
199a9f96007SJiri Pirko 	list_for_each_entry(child_resource, &resource->resource_list, list) {
200a9f96007SJiri Pirko 		if (devlink_resource_put(devlink, skb, child_resource))
201a9f96007SJiri Pirko 			goto resource_put_failure;
202a9f96007SJiri Pirko 	}
203a9f96007SJiri Pirko 
204a9f96007SJiri Pirko 	nla_nest_end(skb, child_resource_attr);
205a9f96007SJiri Pirko out:
206a9f96007SJiri Pirko 	nla_nest_end(skb, resource_attr);
207a9f96007SJiri Pirko 	return 0;
208a9f96007SJiri Pirko 
209a9f96007SJiri Pirko resource_put_failure:
210a9f96007SJiri Pirko 	nla_nest_cancel(skb, child_resource_attr);
211a9f96007SJiri Pirko nla_put_failure:
212a9f96007SJiri Pirko 	nla_nest_cancel(skb, resource_attr);
213a9f96007SJiri Pirko 	return -EMSGSIZE;
214a9f96007SJiri Pirko }
215a9f96007SJiri Pirko 
devlink_resource_fill(struct genl_info * info,enum devlink_command cmd,int flags)216a9f96007SJiri Pirko static int devlink_resource_fill(struct genl_info *info,
217a9f96007SJiri Pirko 				 enum devlink_command cmd, int flags)
218a9f96007SJiri Pirko {
219a9f96007SJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
220a9f96007SJiri Pirko 	struct devlink_resource *resource;
221a9f96007SJiri Pirko 	struct nlattr *resources_attr;
222a9f96007SJiri Pirko 	struct sk_buff *skb = NULL;
223a9f96007SJiri Pirko 	struct nlmsghdr *nlh;
224a9f96007SJiri Pirko 	bool incomplete;
225a9f96007SJiri Pirko 	void *hdr;
226a9f96007SJiri Pirko 	int i;
227a9f96007SJiri Pirko 	int err;
228a9f96007SJiri Pirko 
229a9f96007SJiri Pirko 	resource = list_first_entry(&devlink->resource_list,
230a9f96007SJiri Pirko 				    struct devlink_resource, list);
231a9f96007SJiri Pirko start_again:
232a9f96007SJiri Pirko 	err = devlink_nl_msg_reply_and_new(&skb, info);
233a9f96007SJiri Pirko 	if (err)
234a9f96007SJiri Pirko 		return err;
235a9f96007SJiri Pirko 
236a9f96007SJiri Pirko 	hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
237a9f96007SJiri Pirko 			  &devlink_nl_family, NLM_F_MULTI, cmd);
238a9f96007SJiri Pirko 	if (!hdr) {
239a9f96007SJiri Pirko 		nlmsg_free(skb);
240a9f96007SJiri Pirko 		return -EMSGSIZE;
241a9f96007SJiri Pirko 	}
242a9f96007SJiri Pirko 
243a9f96007SJiri Pirko 	if (devlink_nl_put_handle(skb, devlink))
244a9f96007SJiri Pirko 		goto nla_put_failure;
245a9f96007SJiri Pirko 
246a9f96007SJiri Pirko 	resources_attr = nla_nest_start_noflag(skb,
247a9f96007SJiri Pirko 					       DEVLINK_ATTR_RESOURCE_LIST);
248a9f96007SJiri Pirko 	if (!resources_attr)
249a9f96007SJiri Pirko 		goto nla_put_failure;
250a9f96007SJiri Pirko 
251a9f96007SJiri Pirko 	incomplete = false;
252a9f96007SJiri Pirko 	i = 0;
253a9f96007SJiri Pirko 	list_for_each_entry_from(resource, &devlink->resource_list, list) {
254a9f96007SJiri Pirko 		err = devlink_resource_put(devlink, skb, resource);
255a9f96007SJiri Pirko 		if (err) {
256a9f96007SJiri Pirko 			if (!i)
257a9f96007SJiri Pirko 				goto err_resource_put;
258a9f96007SJiri Pirko 			incomplete = true;
259a9f96007SJiri Pirko 			break;
260a9f96007SJiri Pirko 		}
261a9f96007SJiri Pirko 		i++;
262a9f96007SJiri Pirko 	}
263a9f96007SJiri Pirko 	nla_nest_end(skb, resources_attr);
264a9f96007SJiri Pirko 	genlmsg_end(skb, hdr);
265a9f96007SJiri Pirko 	if (incomplete)
266a9f96007SJiri Pirko 		goto start_again;
267a9f96007SJiri Pirko send_done:
268a9f96007SJiri Pirko 	nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
269a9f96007SJiri Pirko 			NLMSG_DONE, 0, flags | NLM_F_MULTI);
270a9f96007SJiri Pirko 	if (!nlh) {
271a9f96007SJiri Pirko 		err = devlink_nl_msg_reply_and_new(&skb, info);
272a9f96007SJiri Pirko 		if (err)
273a9f96007SJiri Pirko 			return err;
274a9f96007SJiri Pirko 		goto send_done;
275a9f96007SJiri Pirko 	}
276a9f96007SJiri Pirko 	return genlmsg_reply(skb, info);
277a9f96007SJiri Pirko 
278a9f96007SJiri Pirko nla_put_failure:
279a9f96007SJiri Pirko 	err = -EMSGSIZE;
280a9f96007SJiri Pirko err_resource_put:
281a9f96007SJiri Pirko 	nlmsg_free(skb);
282a9f96007SJiri Pirko 	return err;
283a9f96007SJiri Pirko }
284a9f96007SJiri Pirko 
devlink_nl_resource_dump_doit(struct sk_buff * skb,struct genl_info * info)28553590934SJiri Pirko int devlink_nl_resource_dump_doit(struct sk_buff *skb, struct genl_info *info)
286a9f96007SJiri Pirko {
287a9f96007SJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
288a9f96007SJiri Pirko 
289a9f96007SJiri Pirko 	if (list_empty(&devlink->resource_list))
290a9f96007SJiri Pirko 		return -EOPNOTSUPP;
291a9f96007SJiri Pirko 
292a9f96007SJiri Pirko 	return devlink_resource_fill(info, DEVLINK_CMD_RESOURCE_DUMP, 0);
293a9f96007SJiri Pirko }
294a9f96007SJiri Pirko 
devlink_resources_validate(struct devlink * devlink,struct devlink_resource * resource,struct genl_info * info)295a9f96007SJiri Pirko int devlink_resources_validate(struct devlink *devlink,
296a9f96007SJiri Pirko 			       struct devlink_resource *resource,
297a9f96007SJiri Pirko 			       struct genl_info *info)
298a9f96007SJiri Pirko {
299a9f96007SJiri Pirko 	struct list_head *resource_list;
300a9f96007SJiri Pirko 	int err = 0;
301a9f96007SJiri Pirko 
302a9f96007SJiri Pirko 	if (resource)
303a9f96007SJiri Pirko 		resource_list = &resource->resource_list;
304a9f96007SJiri Pirko 	else
305a9f96007SJiri Pirko 		resource_list = &devlink->resource_list;
306a9f96007SJiri Pirko 
307a9f96007SJiri Pirko 	list_for_each_entry(resource, resource_list, list) {
308a9f96007SJiri Pirko 		if (!resource->size_valid)
309a9f96007SJiri Pirko 			return -EINVAL;
310a9f96007SJiri Pirko 		err = devlink_resources_validate(devlink, resource, info);
311a9f96007SJiri Pirko 		if (err)
312a9f96007SJiri Pirko 			return err;
313a9f96007SJiri Pirko 	}
314a9f96007SJiri Pirko 	return err;
315a9f96007SJiri Pirko }
316a9f96007SJiri Pirko 
317a9f96007SJiri Pirko /**
318a9f96007SJiri Pirko  * devl_resource_register - devlink resource register
319a9f96007SJiri Pirko  *
320a9f96007SJiri Pirko  * @devlink: devlink
321a9f96007SJiri Pirko  * @resource_name: resource's name
322a9f96007SJiri Pirko  * @resource_size: resource's size
323a9f96007SJiri Pirko  * @resource_id: resource's id
324a9f96007SJiri Pirko  * @parent_resource_id: resource's parent id
325a9f96007SJiri Pirko  * @size_params: size parameters
326a9f96007SJiri Pirko  *
327a9f96007SJiri Pirko  * Generic resources should reuse the same names across drivers.
328a9f96007SJiri Pirko  * Please see the generic resources list at:
329a9f96007SJiri Pirko  * Documentation/networking/devlink/devlink-resource.rst
330a9f96007SJiri Pirko  */
devl_resource_register(struct devlink * devlink,const char * resource_name,u64 resource_size,u64 resource_id,u64 parent_resource_id,const struct devlink_resource_size_params * size_params)331a9f96007SJiri Pirko int devl_resource_register(struct devlink *devlink,
332a9f96007SJiri Pirko 			   const char *resource_name,
333a9f96007SJiri Pirko 			   u64 resource_size,
334a9f96007SJiri Pirko 			   u64 resource_id,
335a9f96007SJiri Pirko 			   u64 parent_resource_id,
336a9f96007SJiri Pirko 			   const struct devlink_resource_size_params *size_params)
337a9f96007SJiri Pirko {
338a9f96007SJiri Pirko 	struct devlink_resource *resource;
339a9f96007SJiri Pirko 	struct list_head *resource_list;
340a9f96007SJiri Pirko 	bool top_hierarchy;
341a9f96007SJiri Pirko 
342a9f96007SJiri Pirko 	lockdep_assert_held(&devlink->lock);
343a9f96007SJiri Pirko 
344a9f96007SJiri Pirko 	top_hierarchy = parent_resource_id == DEVLINK_RESOURCE_ID_PARENT_TOP;
345a9f96007SJiri Pirko 
346a9f96007SJiri Pirko 	resource = devlink_resource_find(devlink, NULL, resource_id);
347a9f96007SJiri Pirko 	if (resource)
348*e0b140c4SPrzemek Kitszel 		return -EEXIST;
349a9f96007SJiri Pirko 
350a9f96007SJiri Pirko 	resource = kzalloc(sizeof(*resource), GFP_KERNEL);
351a9f96007SJiri Pirko 	if (!resource)
352a9f96007SJiri Pirko 		return -ENOMEM;
353a9f96007SJiri Pirko 
354a9f96007SJiri Pirko 	if (top_hierarchy) {
355a9f96007SJiri Pirko 		resource_list = &devlink->resource_list;
356a9f96007SJiri Pirko 	} else {
357a9f96007SJiri Pirko 		struct devlink_resource *parent_resource;
358a9f96007SJiri Pirko 
359a9f96007SJiri Pirko 		parent_resource = devlink_resource_find(devlink, NULL,
360a9f96007SJiri Pirko 							parent_resource_id);
361a9f96007SJiri Pirko 		if (parent_resource) {
362a9f96007SJiri Pirko 			resource_list = &parent_resource->resource_list;
363a9f96007SJiri Pirko 			resource->parent = parent_resource;
364a9f96007SJiri Pirko 		} else {
365a9f96007SJiri Pirko 			kfree(resource);
366a9f96007SJiri Pirko 			return -EINVAL;
367a9f96007SJiri Pirko 		}
368a9f96007SJiri Pirko 	}
369a9f96007SJiri Pirko 
370a9f96007SJiri Pirko 	resource->name = resource_name;
371a9f96007SJiri Pirko 	resource->size = resource_size;
372a9f96007SJiri Pirko 	resource->size_new = resource_size;
373a9f96007SJiri Pirko 	resource->id = resource_id;
374a9f96007SJiri Pirko 	resource->size_valid = true;
375a9f96007SJiri Pirko 	memcpy(&resource->size_params, size_params,
376a9f96007SJiri Pirko 	       sizeof(resource->size_params));
377a9f96007SJiri Pirko 	INIT_LIST_HEAD(&resource->resource_list);
378a9f96007SJiri Pirko 	list_add_tail(&resource->list, resource_list);
379a9f96007SJiri Pirko 
380a9f96007SJiri Pirko 	return 0;
381a9f96007SJiri Pirko }
382a9f96007SJiri Pirko EXPORT_SYMBOL_GPL(devl_resource_register);
383a9f96007SJiri Pirko 
devlink_resource_unregister(struct devlink * devlink,struct devlink_resource * resource)384a9f96007SJiri Pirko static void devlink_resource_unregister(struct devlink *devlink,
385a9f96007SJiri Pirko 					struct devlink_resource *resource)
386a9f96007SJiri Pirko {
387a9f96007SJiri Pirko 	struct devlink_resource *tmp, *child_resource;
388a9f96007SJiri Pirko 
389a9f96007SJiri Pirko 	list_for_each_entry_safe(child_resource, tmp, &resource->resource_list,
390a9f96007SJiri Pirko 				 list) {
391a9f96007SJiri Pirko 		devlink_resource_unregister(devlink, child_resource);
392a9f96007SJiri Pirko 		list_del(&child_resource->list);
393a9f96007SJiri Pirko 		kfree(child_resource);
394a9f96007SJiri Pirko 	}
395a9f96007SJiri Pirko }
396a9f96007SJiri Pirko 
397a9f96007SJiri Pirko /**
398a9f96007SJiri Pirko  * devl_resources_unregister - free all resources
399a9f96007SJiri Pirko  *
400a9f96007SJiri Pirko  * @devlink: devlink
401a9f96007SJiri Pirko  */
devl_resources_unregister(struct devlink * devlink)402a9f96007SJiri Pirko void devl_resources_unregister(struct devlink *devlink)
403a9f96007SJiri Pirko {
404a9f96007SJiri Pirko 	struct devlink_resource *tmp, *child_resource;
405a9f96007SJiri Pirko 
406a9f96007SJiri Pirko 	lockdep_assert_held(&devlink->lock);
407a9f96007SJiri Pirko 
408a9f96007SJiri Pirko 	list_for_each_entry_safe(child_resource, tmp, &devlink->resource_list,
409a9f96007SJiri Pirko 				 list) {
410a9f96007SJiri Pirko 		devlink_resource_unregister(devlink, child_resource);
411a9f96007SJiri Pirko 		list_del(&child_resource->list);
412a9f96007SJiri Pirko 		kfree(child_resource);
413a9f96007SJiri Pirko 	}
414a9f96007SJiri Pirko }
415a9f96007SJiri Pirko EXPORT_SYMBOL_GPL(devl_resources_unregister);
416a9f96007SJiri Pirko 
417a9f96007SJiri Pirko /**
418a9f96007SJiri Pirko  *	devlink_resources_unregister - free all resources
419a9f96007SJiri Pirko  *
420a9f96007SJiri Pirko  *	@devlink: devlink
421a9f96007SJiri Pirko  *
422a9f96007SJiri Pirko  *	Context: Takes and release devlink->lock <mutex>.
423a9f96007SJiri Pirko  */
devlink_resources_unregister(struct devlink * devlink)424a9f96007SJiri Pirko void devlink_resources_unregister(struct devlink *devlink)
425a9f96007SJiri Pirko {
426a9f96007SJiri Pirko 	devl_lock(devlink);
427a9f96007SJiri Pirko 	devl_resources_unregister(devlink);
428a9f96007SJiri Pirko 	devl_unlock(devlink);
429a9f96007SJiri Pirko }
430a9f96007SJiri Pirko EXPORT_SYMBOL_GPL(devlink_resources_unregister);
431a9f96007SJiri Pirko 
432a9f96007SJiri Pirko /**
433a9f96007SJiri Pirko  * devl_resource_size_get - get and update size
434a9f96007SJiri Pirko  *
435a9f96007SJiri Pirko  * @devlink: devlink
436a9f96007SJiri Pirko  * @resource_id: the requested resource id
437a9f96007SJiri Pirko  * @p_resource_size: ptr to update
438a9f96007SJiri Pirko  */
devl_resource_size_get(struct devlink * devlink,u64 resource_id,u64 * p_resource_size)439a9f96007SJiri Pirko int devl_resource_size_get(struct devlink *devlink,
440a9f96007SJiri Pirko 			   u64 resource_id,
441a9f96007SJiri Pirko 			   u64 *p_resource_size)
442a9f96007SJiri Pirko {
443a9f96007SJiri Pirko 	struct devlink_resource *resource;
444a9f96007SJiri Pirko 
445a9f96007SJiri Pirko 	lockdep_assert_held(&devlink->lock);
446a9f96007SJiri Pirko 
447a9f96007SJiri Pirko 	resource = devlink_resource_find(devlink, NULL, resource_id);
448a9f96007SJiri Pirko 	if (!resource)
449a9f96007SJiri Pirko 		return -EINVAL;
450a9f96007SJiri Pirko 	*p_resource_size = resource->size_new;
451a9f96007SJiri Pirko 	resource->size = resource->size_new;
452a9f96007SJiri Pirko 	return 0;
453a9f96007SJiri Pirko }
454a9f96007SJiri Pirko EXPORT_SYMBOL_GPL(devl_resource_size_get);
455a9f96007SJiri Pirko 
456a9f96007SJiri Pirko /**
457a9f96007SJiri Pirko  * devl_resource_occ_get_register - register occupancy getter
458a9f96007SJiri Pirko  *
459a9f96007SJiri Pirko  * @devlink: devlink
460a9f96007SJiri Pirko  * @resource_id: resource id
461a9f96007SJiri Pirko  * @occ_get: occupancy getter callback
462a9f96007SJiri Pirko  * @occ_get_priv: occupancy getter callback priv
463a9f96007SJiri Pirko  */
devl_resource_occ_get_register(struct devlink * devlink,u64 resource_id,devlink_resource_occ_get_t * occ_get,void * occ_get_priv)464a9f96007SJiri Pirko void devl_resource_occ_get_register(struct devlink *devlink,
465a9f96007SJiri Pirko 				    u64 resource_id,
466a9f96007SJiri Pirko 				    devlink_resource_occ_get_t *occ_get,
467a9f96007SJiri Pirko 				    void *occ_get_priv)
468a9f96007SJiri Pirko {
469a9f96007SJiri Pirko 	struct devlink_resource *resource;
470a9f96007SJiri Pirko 
471a9f96007SJiri Pirko 	lockdep_assert_held(&devlink->lock);
472a9f96007SJiri Pirko 
473a9f96007SJiri Pirko 	resource = devlink_resource_find(devlink, NULL, resource_id);
474a9f96007SJiri Pirko 	if (WARN_ON(!resource))
475a9f96007SJiri Pirko 		return;
476a9f96007SJiri Pirko 	WARN_ON(resource->occ_get);
477a9f96007SJiri Pirko 
478a9f96007SJiri Pirko 	resource->occ_get = occ_get;
479a9f96007SJiri Pirko 	resource->occ_get_priv = occ_get_priv;
480a9f96007SJiri Pirko }
481a9f96007SJiri Pirko EXPORT_SYMBOL_GPL(devl_resource_occ_get_register);
482a9f96007SJiri Pirko 
483a9f96007SJiri Pirko /**
484a9f96007SJiri Pirko  * devl_resource_occ_get_unregister - unregister occupancy getter
485a9f96007SJiri Pirko  *
486a9f96007SJiri Pirko  * @devlink: devlink
487a9f96007SJiri Pirko  * @resource_id: resource id
488a9f96007SJiri Pirko  */
devl_resource_occ_get_unregister(struct devlink * devlink,u64 resource_id)489a9f96007SJiri Pirko void devl_resource_occ_get_unregister(struct devlink *devlink,
490a9f96007SJiri Pirko 				      u64 resource_id)
491a9f96007SJiri Pirko {
492a9f96007SJiri Pirko 	struct devlink_resource *resource;
493a9f96007SJiri Pirko 
494a9f96007SJiri Pirko 	lockdep_assert_held(&devlink->lock);
495a9f96007SJiri Pirko 
496a9f96007SJiri Pirko 	resource = devlink_resource_find(devlink, NULL, resource_id);
497a9f96007SJiri Pirko 	if (WARN_ON(!resource))
498a9f96007SJiri Pirko 		return;
499a9f96007SJiri Pirko 	WARN_ON(!resource->occ_get);
500a9f96007SJiri Pirko 
501a9f96007SJiri Pirko 	resource->occ_get = NULL;
502a9f96007SJiri Pirko 	resource->occ_get_priv = NULL;
503a9f96007SJiri Pirko }
504a9f96007SJiri Pirko EXPORT_SYMBOL_GPL(devl_resource_occ_get_unregister);
505