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 struct devlink_linecard {
10 struct list_head list;
11 struct devlink *devlink;
13 const struct devlink_linecard_ops *ops;
15 enum devlink_linecard_state state;
16 struct mutex state_lock; /* Protects state */
18 struct devlink_linecard_type *types;
19 unsigned int types_count;
20 struct devlink *nested_devlink;
23 unsigned int devlink_linecard_index(struct devlink_linecard *linecard)
25 return linecard->index;
28 static struct devlink_linecard *
29 devlink_linecard_get_by_index(struct devlink *devlink,
30 unsigned int linecard_index)
32 struct devlink_linecard *devlink_linecard;
34 list_for_each_entry(devlink_linecard, &devlink->linecard_list, list) {
35 if (devlink_linecard->index == linecard_index)
36 return devlink_linecard;
41 static bool devlink_linecard_index_exists(struct devlink *devlink,
42 unsigned int linecard_index)
44 return devlink_linecard_get_by_index(devlink, linecard_index);
47 static struct devlink_linecard *
48 devlink_linecard_get_from_attrs(struct devlink *devlink, struct nlattr **attrs)
50 if (attrs[DEVLINK_ATTR_LINECARD_INDEX]) {
51 u32 linecard_index = nla_get_u32(attrs[DEVLINK_ATTR_LINECARD_INDEX]);
52 struct devlink_linecard *linecard;
54 linecard = devlink_linecard_get_by_index(devlink, linecard_index);
56 return ERR_PTR(-ENODEV);
59 return ERR_PTR(-EINVAL);
62 static struct devlink_linecard *
63 devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info)
65 return devlink_linecard_get_from_attrs(devlink, info->attrs);
68 static int devlink_nl_put_nested_handle(struct sk_buff *msg, struct net *net,
69 struct devlink *devlink)
71 struct nlattr *nested_attr;
73 nested_attr = nla_nest_start(msg, DEVLINK_ATTR_NESTED_DEVLINK);
76 if (devlink_nl_put_handle(msg, devlink))
78 if (!net_eq(net, devlink_net(devlink))) {
79 int id = peernet2id_alloc(net, devlink_net(devlink),
82 if (nla_put_s32(msg, DEVLINK_ATTR_NETNS_ID, id))
86 nla_nest_end(msg, nested_attr);
90 nla_nest_cancel(msg, nested_attr);
94 struct devlink_linecard_type {
99 static int devlink_nl_linecard_fill(struct sk_buff *msg,
100 struct devlink *devlink,
101 struct devlink_linecard *linecard,
102 enum devlink_command cmd, u32 portid,
104 struct netlink_ext_ack *extack)
106 struct devlink_linecard_type *linecard_type;
111 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
115 if (devlink_nl_put_handle(msg, devlink))
116 goto nla_put_failure;
117 if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index))
118 goto nla_put_failure;
119 if (nla_put_u8(msg, DEVLINK_ATTR_LINECARD_STATE, linecard->state))
120 goto nla_put_failure;
121 if (linecard->type &&
122 nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE, linecard->type))
123 goto nla_put_failure;
125 if (linecard->types_count) {
126 attr = nla_nest_start(msg,
127 DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES);
129 goto nla_put_failure;
130 for (i = 0; i < linecard->types_count; i++) {
131 linecard_type = &linecard->types[i];
132 if (nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE,
133 linecard_type->type)) {
134 nla_nest_cancel(msg, attr);
135 goto nla_put_failure;
138 nla_nest_end(msg, attr);
141 if (linecard->nested_devlink &&
142 devlink_nl_put_nested_handle(msg, devlink_net(devlink),
143 linecard->nested_devlink))
144 goto nla_put_failure;
146 genlmsg_end(msg, hdr);
150 genlmsg_cancel(msg, hdr);
154 static void devlink_linecard_notify(struct devlink_linecard *linecard,
155 enum devlink_command cmd)
157 struct devlink *devlink = linecard->devlink;
161 WARN_ON(cmd != DEVLINK_CMD_LINECARD_NEW &&
162 cmd != DEVLINK_CMD_LINECARD_DEL);
164 if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED))
167 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
171 err = devlink_nl_linecard_fill(msg, devlink, linecard, cmd, 0, 0, 0,
178 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
179 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
182 void devlink_linecards_notify_register(struct devlink *devlink)
184 struct devlink_linecard *linecard;
186 list_for_each_entry(linecard, &devlink->linecard_list, list)
187 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
190 void devlink_linecards_notify_unregister(struct devlink *devlink)
192 struct devlink_linecard *linecard;
194 list_for_each_entry_reverse(linecard, &devlink->linecard_list, list)
195 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL);
198 int devlink_nl_linecard_get_doit(struct sk_buff *skb, struct genl_info *info)
200 struct devlink *devlink = info->user_ptr[0];
201 struct devlink_linecard *linecard;
205 linecard = devlink_linecard_get_from_info(devlink, info);
206 if (IS_ERR(linecard))
207 return PTR_ERR(linecard);
209 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
213 mutex_lock(&linecard->state_lock);
214 err = devlink_nl_linecard_fill(msg, devlink, linecard,
215 DEVLINK_CMD_LINECARD_NEW,
216 info->snd_portid, info->snd_seq, 0,
218 mutex_unlock(&linecard->state_lock);
224 return genlmsg_reply(msg, info);
227 static int devlink_nl_linecard_get_dump_one(struct sk_buff *msg,
228 struct devlink *devlink,
229 struct netlink_callback *cb,
232 struct devlink_nl_dump_state *state = devlink_dump_state(cb);
233 struct devlink_linecard *linecard;
237 list_for_each_entry(linecard, &devlink->linecard_list, list) {
238 if (idx < state->idx) {
242 mutex_lock(&linecard->state_lock);
243 err = devlink_nl_linecard_fill(msg, devlink, linecard,
244 DEVLINK_CMD_LINECARD_NEW,
245 NETLINK_CB(cb->skb).portid,
246 cb->nlh->nlmsg_seq, flags,
248 mutex_unlock(&linecard->state_lock);
259 int devlink_nl_linecard_get_dumpit(struct sk_buff *skb,
260 struct netlink_callback *cb)
262 return devlink_nl_dumpit(skb, cb, devlink_nl_linecard_get_dump_one);
265 static struct devlink_linecard_type *
266 devlink_linecard_type_lookup(struct devlink_linecard *linecard,
269 struct devlink_linecard_type *linecard_type;
272 for (i = 0; i < linecard->types_count; i++) {
273 linecard_type = &linecard->types[i];
274 if (!strcmp(type, linecard_type->type))
275 return linecard_type;
280 static int devlink_linecard_type_set(struct devlink_linecard *linecard,
282 struct netlink_ext_ack *extack)
284 const struct devlink_linecard_ops *ops = linecard->ops;
285 struct devlink_linecard_type *linecard_type;
288 mutex_lock(&linecard->state_lock);
289 if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) {
290 NL_SET_ERR_MSG(extack, "Line card is currently being provisioned");
294 if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) {
295 NL_SET_ERR_MSG(extack, "Line card is currently being unprovisioned");
300 linecard_type = devlink_linecard_type_lookup(linecard, type);
301 if (!linecard_type) {
302 NL_SET_ERR_MSG(extack, "Unsupported line card type provided");
307 if (linecard->state != DEVLINK_LINECARD_STATE_UNPROVISIONED &&
308 linecard->state != DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) {
309 NL_SET_ERR_MSG(extack, "Line card already provisioned");
311 /* Check if the line card is provisioned in the same
312 * way the user asks. In case it is, make the operation
315 if (ops->same_provision &&
316 ops->same_provision(linecard, linecard->priv,
318 linecard_type->priv))
323 linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING;
324 linecard->type = linecard_type->type;
325 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
326 mutex_unlock(&linecard->state_lock);
327 err = ops->provision(linecard, linecard->priv, linecard_type->type,
328 linecard_type->priv, extack);
330 /* Provisioning failed. Assume the linecard is unprovisioned
331 * for future operations.
333 mutex_lock(&linecard->state_lock);
334 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
335 linecard->type = NULL;
336 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
337 mutex_unlock(&linecard->state_lock);
342 mutex_unlock(&linecard->state_lock);
346 static int devlink_linecard_type_unset(struct devlink_linecard *linecard,
347 struct netlink_ext_ack *extack)
351 mutex_lock(&linecard->state_lock);
352 if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) {
353 NL_SET_ERR_MSG(extack, "Line card is currently being provisioned");
357 if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) {
358 NL_SET_ERR_MSG(extack, "Line card is currently being unprovisioned");
362 if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) {
363 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
364 linecard->type = NULL;
365 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
370 if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONED) {
371 NL_SET_ERR_MSG(extack, "Line card is not provisioned");
375 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONING;
376 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
377 mutex_unlock(&linecard->state_lock);
378 err = linecard->ops->unprovision(linecard, linecard->priv,
381 /* Unprovisioning failed. Assume the linecard is unprovisioned
382 * for future operations.
384 mutex_lock(&linecard->state_lock);
385 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
386 linecard->type = NULL;
387 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
388 mutex_unlock(&linecard->state_lock);
393 mutex_unlock(&linecard->state_lock);
397 int devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb,
398 struct genl_info *info)
400 struct netlink_ext_ack *extack = info->extack;
401 struct devlink *devlink = info->user_ptr[0];
402 struct devlink_linecard *linecard;
405 linecard = devlink_linecard_get_from_info(devlink, info);
406 if (IS_ERR(linecard))
407 return PTR_ERR(linecard);
409 if (info->attrs[DEVLINK_ATTR_LINECARD_TYPE]) {
412 type = nla_data(info->attrs[DEVLINK_ATTR_LINECARD_TYPE]);
413 if (strcmp(type, "")) {
414 err = devlink_linecard_type_set(linecard, type, extack);
418 err = devlink_linecard_type_unset(linecard, extack);
427 static int devlink_linecard_types_init(struct devlink_linecard *linecard)
429 struct devlink_linecard_type *linecard_type;
433 count = linecard->ops->types_count(linecard, linecard->priv);
434 linecard->types = kmalloc_array(count, sizeof(*linecard_type),
436 if (!linecard->types)
438 linecard->types_count = count;
440 for (i = 0; i < count; i++) {
441 linecard_type = &linecard->types[i];
442 linecard->ops->types_get(linecard, linecard->priv, i,
443 &linecard_type->type,
444 &linecard_type->priv);
449 static void devlink_linecard_types_fini(struct devlink_linecard *linecard)
451 kfree(linecard->types);
455 * devl_linecard_create - Create devlink linecard
458 * @linecard_index: driver-specific numerical identifier of the linecard
459 * @ops: linecards ops
460 * @priv: user priv pointer
462 * Create devlink linecard instance with provided linecard index.
463 * Caller can use any indexing, even hw-related one.
465 * Return: Line card structure or an ERR_PTR() encoded error code.
467 struct devlink_linecard *
468 devl_linecard_create(struct devlink *devlink, unsigned int linecard_index,
469 const struct devlink_linecard_ops *ops, void *priv)
471 struct devlink_linecard *linecard;
474 if (WARN_ON(!ops || !ops->provision || !ops->unprovision ||
475 !ops->types_count || !ops->types_get))
476 return ERR_PTR(-EINVAL);
478 if (devlink_linecard_index_exists(devlink, linecard_index))
479 return ERR_PTR(-EEXIST);
481 linecard = kzalloc(sizeof(*linecard), GFP_KERNEL);
483 return ERR_PTR(-ENOMEM);
485 linecard->devlink = devlink;
486 linecard->index = linecard_index;
488 linecard->priv = priv;
489 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
490 mutex_init(&linecard->state_lock);
492 err = devlink_linecard_types_init(linecard);
494 mutex_destroy(&linecard->state_lock);
499 list_add_tail(&linecard->list, &devlink->linecard_list);
500 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
503 EXPORT_SYMBOL_GPL(devl_linecard_create);
506 * devl_linecard_destroy - Destroy devlink linecard
508 * @linecard: devlink linecard
510 void devl_linecard_destroy(struct devlink_linecard *linecard)
512 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL);
513 list_del(&linecard->list);
514 devlink_linecard_types_fini(linecard);
515 mutex_destroy(&linecard->state_lock);
518 EXPORT_SYMBOL_GPL(devl_linecard_destroy);
521 * devlink_linecard_provision_set - Set provisioning on linecard
523 * @linecard: devlink linecard
524 * @type: linecard type
526 * This is either called directly from the provision() op call or
527 * as a result of the provision() op call asynchronously.
529 void devlink_linecard_provision_set(struct devlink_linecard *linecard,
532 mutex_lock(&linecard->state_lock);
533 WARN_ON(linecard->type && strcmp(linecard->type, type));
534 linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED;
535 linecard->type = type;
536 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
537 mutex_unlock(&linecard->state_lock);
539 EXPORT_SYMBOL_GPL(devlink_linecard_provision_set);
542 * devlink_linecard_provision_clear - Clear provisioning on linecard
544 * @linecard: devlink linecard
546 * This is either called directly from the unprovision() op call or
547 * as a result of the unprovision() op call asynchronously.
549 void devlink_linecard_provision_clear(struct devlink_linecard *linecard)
551 mutex_lock(&linecard->state_lock);
552 WARN_ON(linecard->nested_devlink);
553 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
554 linecard->type = NULL;
555 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
556 mutex_unlock(&linecard->state_lock);
558 EXPORT_SYMBOL_GPL(devlink_linecard_provision_clear);
561 * devlink_linecard_provision_fail - Fail provisioning on linecard
563 * @linecard: devlink linecard
565 * This is either called directly from the provision() op call or
566 * as a result of the provision() op call asynchronously.
568 void devlink_linecard_provision_fail(struct devlink_linecard *linecard)
570 mutex_lock(&linecard->state_lock);
571 WARN_ON(linecard->nested_devlink);
572 linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING_FAILED;
573 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
574 mutex_unlock(&linecard->state_lock);
576 EXPORT_SYMBOL_GPL(devlink_linecard_provision_fail);
579 * devlink_linecard_activate - Set linecard active
581 * @linecard: devlink linecard
583 void devlink_linecard_activate(struct devlink_linecard *linecard)
585 mutex_lock(&linecard->state_lock);
586 WARN_ON(linecard->state != DEVLINK_LINECARD_STATE_PROVISIONED);
587 linecard->state = DEVLINK_LINECARD_STATE_ACTIVE;
588 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
589 mutex_unlock(&linecard->state_lock);
591 EXPORT_SYMBOL_GPL(devlink_linecard_activate);
594 * devlink_linecard_deactivate - Set linecard inactive
596 * @linecard: devlink linecard
598 void devlink_linecard_deactivate(struct devlink_linecard *linecard)
600 mutex_lock(&linecard->state_lock);
601 switch (linecard->state) {
602 case DEVLINK_LINECARD_STATE_ACTIVE:
603 linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED;
604 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
606 case DEVLINK_LINECARD_STATE_UNPROVISIONING:
607 /* Line card is being deactivated as part
608 * of unprovisioning flow.
615 mutex_unlock(&linecard->state_lock);
617 EXPORT_SYMBOL_GPL(devlink_linecard_deactivate);
620 * devlink_linecard_nested_dl_set - Attach/detach nested devlink
621 * instance to linecard.
623 * @linecard: devlink linecard
624 * @nested_devlink: devlink instance to attach or NULL to detach
626 void devlink_linecard_nested_dl_set(struct devlink_linecard *linecard,
627 struct devlink *nested_devlink)
629 mutex_lock(&linecard->state_lock);
630 linecard->nested_devlink = nested_devlink;
631 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
632 mutex_unlock(&linecard->state_lock);
634 EXPORT_SYMBOL_GPL(devlink_linecard_nested_dl_set);