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