1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
7 #include "devl_internal.h"
9 static struct devlink_linecard *
10 devlink_linecard_get_by_index(struct devlink *devlink,
11 unsigned int linecard_index)
13 struct devlink_linecard *devlink_linecard;
15 list_for_each_entry(devlink_linecard, &devlink->linecard_list, list) {
16 if (devlink_linecard->index == linecard_index)
17 return devlink_linecard;
22 static bool devlink_linecard_index_exists(struct devlink *devlink,
23 unsigned int linecard_index)
25 return devlink_linecard_get_by_index(devlink, linecard_index);
28 static struct devlink_linecard *
29 devlink_linecard_get_from_attrs(struct devlink *devlink, struct nlattr **attrs)
31 if (attrs[DEVLINK_ATTR_LINECARD_INDEX]) {
32 u32 linecard_index = nla_get_u32(attrs[DEVLINK_ATTR_LINECARD_INDEX]);
33 struct devlink_linecard *linecard;
35 linecard = devlink_linecard_get_by_index(devlink, linecard_index);
37 return ERR_PTR(-ENODEV);
40 return ERR_PTR(-EINVAL);
43 static struct devlink_linecard *
44 devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info)
46 return devlink_linecard_get_from_attrs(devlink, info->attrs);
49 static int devlink_nl_put_nested_handle(struct sk_buff *msg, struct devlink *devlink)
51 struct nlattr *nested_attr;
53 nested_attr = nla_nest_start(msg, DEVLINK_ATTR_NESTED_DEVLINK);
56 if (devlink_nl_put_handle(msg, devlink))
59 nla_nest_end(msg, nested_attr);
63 nla_nest_cancel(msg, nested_attr);
67 struct devlink_linecard_type {
72 static int devlink_nl_linecard_fill(struct sk_buff *msg,
73 struct devlink *devlink,
74 struct devlink_linecard *linecard,
75 enum devlink_command cmd, u32 portid,
77 struct netlink_ext_ack *extack)
79 struct devlink_linecard_type *linecard_type;
84 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
88 if (devlink_nl_put_handle(msg, devlink))
90 if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index))
92 if (nla_put_u8(msg, DEVLINK_ATTR_LINECARD_STATE, linecard->state))
95 nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE, linecard->type))
98 if (linecard->types_count) {
99 attr = nla_nest_start(msg,
100 DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES);
102 goto nla_put_failure;
103 for (i = 0; i < linecard->types_count; i++) {
104 linecard_type = &linecard->types[i];
105 if (nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE,
106 linecard_type->type)) {
107 nla_nest_cancel(msg, attr);
108 goto nla_put_failure;
111 nla_nest_end(msg, attr);
114 if (linecard->nested_devlink &&
115 devlink_nl_put_nested_handle(msg, linecard->nested_devlink))
116 goto nla_put_failure;
118 genlmsg_end(msg, hdr);
122 genlmsg_cancel(msg, hdr);
126 static void devlink_linecard_notify(struct devlink_linecard *linecard,
127 enum devlink_command cmd)
129 struct devlink *devlink = linecard->devlink;
133 WARN_ON(cmd != DEVLINK_CMD_LINECARD_NEW &&
134 cmd != DEVLINK_CMD_LINECARD_DEL);
136 if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED))
139 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
143 err = devlink_nl_linecard_fill(msg, devlink, linecard, cmd, 0, 0, 0,
150 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
151 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
154 void devlink_linecards_notify_register(struct devlink *devlink)
156 struct devlink_linecard *linecard;
158 list_for_each_entry(linecard, &devlink->linecard_list, list)
159 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
162 void devlink_linecards_notify_unregister(struct devlink *devlink)
164 struct devlink_linecard *linecard;
166 list_for_each_entry_reverse(linecard, &devlink->linecard_list, list)
167 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL);
170 int devlink_nl_linecard_get_doit(struct sk_buff *skb, struct genl_info *info)
172 struct devlink *devlink = info->user_ptr[0];
173 struct devlink_linecard *linecard;
177 linecard = devlink_linecard_get_from_info(devlink, info);
178 if (IS_ERR(linecard))
179 return PTR_ERR(linecard);
181 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
185 mutex_lock(&linecard->state_lock);
186 err = devlink_nl_linecard_fill(msg, devlink, linecard,
187 DEVLINK_CMD_LINECARD_NEW,
188 info->snd_portid, info->snd_seq, 0,
190 mutex_unlock(&linecard->state_lock);
196 return genlmsg_reply(msg, info);
199 static int devlink_nl_linecard_get_dump_one(struct sk_buff *msg,
200 struct devlink *devlink,
201 struct netlink_callback *cb,
204 struct devlink_nl_dump_state *state = devlink_dump_state(cb);
205 struct devlink_linecard *linecard;
209 list_for_each_entry(linecard, &devlink->linecard_list, list) {
210 if (idx < state->idx) {
214 mutex_lock(&linecard->state_lock);
215 err = devlink_nl_linecard_fill(msg, devlink, linecard,
216 DEVLINK_CMD_LINECARD_NEW,
217 NETLINK_CB(cb->skb).portid,
218 cb->nlh->nlmsg_seq, flags,
220 mutex_unlock(&linecard->state_lock);
231 int devlink_nl_linecard_get_dumpit(struct sk_buff *skb,
232 struct netlink_callback *cb)
234 return devlink_nl_dumpit(skb, cb, devlink_nl_linecard_get_dump_one);
237 static struct devlink_linecard_type *
238 devlink_linecard_type_lookup(struct devlink_linecard *linecard,
241 struct devlink_linecard_type *linecard_type;
244 for (i = 0; i < linecard->types_count; i++) {
245 linecard_type = &linecard->types[i];
246 if (!strcmp(type, linecard_type->type))
247 return linecard_type;
252 static int devlink_linecard_type_set(struct devlink_linecard *linecard,
254 struct netlink_ext_ack *extack)
256 const struct devlink_linecard_ops *ops = linecard->ops;
257 struct devlink_linecard_type *linecard_type;
260 mutex_lock(&linecard->state_lock);
261 if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) {
262 NL_SET_ERR_MSG(extack, "Line card is currently being provisioned");
266 if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) {
267 NL_SET_ERR_MSG(extack, "Line card is currently being unprovisioned");
272 linecard_type = devlink_linecard_type_lookup(linecard, type);
273 if (!linecard_type) {
274 NL_SET_ERR_MSG(extack, "Unsupported line card type provided");
279 if (linecard->state != DEVLINK_LINECARD_STATE_UNPROVISIONED &&
280 linecard->state != DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) {
281 NL_SET_ERR_MSG(extack, "Line card already provisioned");
283 /* Check if the line card is provisioned in the same
284 * way the user asks. In case it is, make the operation
287 if (ops->same_provision &&
288 ops->same_provision(linecard, linecard->priv,
290 linecard_type->priv))
295 linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING;
296 linecard->type = linecard_type->type;
297 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
298 mutex_unlock(&linecard->state_lock);
299 err = ops->provision(linecard, linecard->priv, linecard_type->type,
300 linecard_type->priv, extack);
302 /* Provisioning failed. Assume the linecard is unprovisioned
303 * for future operations.
305 mutex_lock(&linecard->state_lock);
306 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
307 linecard->type = NULL;
308 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
309 mutex_unlock(&linecard->state_lock);
314 mutex_unlock(&linecard->state_lock);
318 static int devlink_linecard_type_unset(struct devlink_linecard *linecard,
319 struct netlink_ext_ack *extack)
323 mutex_lock(&linecard->state_lock);
324 if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) {
325 NL_SET_ERR_MSG(extack, "Line card is currently being provisioned");
329 if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) {
330 NL_SET_ERR_MSG(extack, "Line card is currently being unprovisioned");
334 if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) {
335 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
336 linecard->type = NULL;
337 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
342 if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONED) {
343 NL_SET_ERR_MSG(extack, "Line card is not provisioned");
347 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONING;
348 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
349 mutex_unlock(&linecard->state_lock);
350 err = linecard->ops->unprovision(linecard, linecard->priv,
353 /* Unprovisioning failed. Assume the linecard is unprovisioned
354 * for future operations.
356 mutex_lock(&linecard->state_lock);
357 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
358 linecard->type = NULL;
359 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
360 mutex_unlock(&linecard->state_lock);
365 mutex_unlock(&linecard->state_lock);
369 int devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb,
370 struct genl_info *info)
372 struct netlink_ext_ack *extack = info->extack;
373 struct devlink *devlink = info->user_ptr[0];
374 struct devlink_linecard *linecard;
377 linecard = devlink_linecard_get_from_info(devlink, info);
378 if (IS_ERR(linecard))
379 return PTR_ERR(linecard);
381 if (info->attrs[DEVLINK_ATTR_LINECARD_TYPE]) {
384 type = nla_data(info->attrs[DEVLINK_ATTR_LINECARD_TYPE]);
385 if (strcmp(type, "")) {
386 err = devlink_linecard_type_set(linecard, type, extack);
390 err = devlink_linecard_type_unset(linecard, extack);
399 static int devlink_linecard_types_init(struct devlink_linecard *linecard)
401 struct devlink_linecard_type *linecard_type;
405 count = linecard->ops->types_count(linecard, linecard->priv);
406 linecard->types = kmalloc_array(count, sizeof(*linecard_type),
408 if (!linecard->types)
410 linecard->types_count = count;
412 for (i = 0; i < count; i++) {
413 linecard_type = &linecard->types[i];
414 linecard->ops->types_get(linecard, linecard->priv, i,
415 &linecard_type->type,
416 &linecard_type->priv);
421 static void devlink_linecard_types_fini(struct devlink_linecard *linecard)
423 kfree(linecard->types);
427 * devl_linecard_create - Create devlink linecard
430 * @linecard_index: driver-specific numerical identifier of the linecard
431 * @ops: linecards ops
432 * @priv: user priv pointer
434 * Create devlink linecard instance with provided linecard index.
435 * Caller can use any indexing, even hw-related one.
437 * Return: Line card structure or an ERR_PTR() encoded error code.
439 struct devlink_linecard *
440 devl_linecard_create(struct devlink *devlink, unsigned int linecard_index,
441 const struct devlink_linecard_ops *ops, void *priv)
443 struct devlink_linecard *linecard;
446 if (WARN_ON(!ops || !ops->provision || !ops->unprovision ||
447 !ops->types_count || !ops->types_get))
448 return ERR_PTR(-EINVAL);
450 if (devlink_linecard_index_exists(devlink, linecard_index))
451 return ERR_PTR(-EEXIST);
453 linecard = kzalloc(sizeof(*linecard), GFP_KERNEL);
455 return ERR_PTR(-ENOMEM);
457 linecard->devlink = devlink;
458 linecard->index = linecard_index;
460 linecard->priv = priv;
461 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
462 mutex_init(&linecard->state_lock);
464 err = devlink_linecard_types_init(linecard);
466 mutex_destroy(&linecard->state_lock);
471 list_add_tail(&linecard->list, &devlink->linecard_list);
472 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
475 EXPORT_SYMBOL_GPL(devl_linecard_create);
478 * devl_linecard_destroy - Destroy devlink linecard
480 * @linecard: devlink linecard
482 void devl_linecard_destroy(struct devlink_linecard *linecard)
484 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL);
485 list_del(&linecard->list);
486 devlink_linecard_types_fini(linecard);
487 mutex_destroy(&linecard->state_lock);
490 EXPORT_SYMBOL_GPL(devl_linecard_destroy);
493 * devlink_linecard_provision_set - Set provisioning on linecard
495 * @linecard: devlink linecard
496 * @type: linecard type
498 * This is either called directly from the provision() op call or
499 * as a result of the provision() op call asynchronously.
501 void devlink_linecard_provision_set(struct devlink_linecard *linecard,
504 mutex_lock(&linecard->state_lock);
505 WARN_ON(linecard->type && strcmp(linecard->type, type));
506 linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED;
507 linecard->type = type;
508 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
509 mutex_unlock(&linecard->state_lock);
511 EXPORT_SYMBOL_GPL(devlink_linecard_provision_set);
514 * devlink_linecard_provision_clear - Clear provisioning on linecard
516 * @linecard: devlink linecard
518 * This is either called directly from the unprovision() op call or
519 * as a result of the unprovision() op call asynchronously.
521 void devlink_linecard_provision_clear(struct devlink_linecard *linecard)
523 mutex_lock(&linecard->state_lock);
524 WARN_ON(linecard->nested_devlink);
525 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
526 linecard->type = NULL;
527 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
528 mutex_unlock(&linecard->state_lock);
530 EXPORT_SYMBOL_GPL(devlink_linecard_provision_clear);
533 * devlink_linecard_provision_fail - Fail provisioning on linecard
535 * @linecard: devlink linecard
537 * This is either called directly from the provision() op call or
538 * as a result of the provision() op call asynchronously.
540 void devlink_linecard_provision_fail(struct devlink_linecard *linecard)
542 mutex_lock(&linecard->state_lock);
543 WARN_ON(linecard->nested_devlink);
544 linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING_FAILED;
545 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
546 mutex_unlock(&linecard->state_lock);
548 EXPORT_SYMBOL_GPL(devlink_linecard_provision_fail);
551 * devlink_linecard_activate - Set linecard active
553 * @linecard: devlink linecard
555 void devlink_linecard_activate(struct devlink_linecard *linecard)
557 mutex_lock(&linecard->state_lock);
558 WARN_ON(linecard->state != DEVLINK_LINECARD_STATE_PROVISIONED);
559 linecard->state = DEVLINK_LINECARD_STATE_ACTIVE;
560 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
561 mutex_unlock(&linecard->state_lock);
563 EXPORT_SYMBOL_GPL(devlink_linecard_activate);
566 * devlink_linecard_deactivate - Set linecard inactive
568 * @linecard: devlink linecard
570 void devlink_linecard_deactivate(struct devlink_linecard *linecard)
572 mutex_lock(&linecard->state_lock);
573 switch (linecard->state) {
574 case DEVLINK_LINECARD_STATE_ACTIVE:
575 linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED;
576 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
578 case DEVLINK_LINECARD_STATE_UNPROVISIONING:
579 /* Line card is being deactivated as part
580 * of unprovisioning flow.
587 mutex_unlock(&linecard->state_lock);
589 EXPORT_SYMBOL_GPL(devlink_linecard_deactivate);
592 * devlink_linecard_nested_dl_set - Attach/detach nested devlink
593 * instance to linecard.
595 * @linecard: devlink linecard
596 * @nested_devlink: devlink instance to attach or NULL to detach
598 void devlink_linecard_nested_dl_set(struct devlink_linecard *linecard,
599 struct devlink *nested_devlink)
601 mutex_lock(&linecard->state_lock);
602 linecard->nested_devlink = nested_devlink;
603 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
604 mutex_unlock(&linecard->state_lock);
606 EXPORT_SYMBOL_GPL(devlink_linecard_nested_dl_set);