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;
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 struct devlink_linecard_type {
73 static int devlink_nl_linecard_fill(struct sk_buff *msg,
74 struct devlink *devlink,
75 struct devlink_linecard *linecard,
76 enum devlink_command cmd, u32 portid,
78 struct netlink_ext_ack *extack)
80 struct devlink_linecard_type *linecard_type;
85 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
89 if (devlink_nl_put_handle(msg, devlink))
91 if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index))
93 if (nla_put_u8(msg, DEVLINK_ATTR_LINECARD_STATE, linecard->state))
96 nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE, linecard->type))
99 if (linecard->types_count) {
100 attr = nla_nest_start(msg,
101 DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES);
103 goto nla_put_failure;
104 for (i = 0; i < linecard->types_count; i++) {
105 linecard_type = &linecard->types[i];
106 if (nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE,
107 linecard_type->type)) {
108 nla_nest_cancel(msg, attr);
109 goto nla_put_failure;
112 nla_nest_end(msg, attr);
115 if (devlink_rel_devlink_handle_put(msg, devlink,
117 DEVLINK_ATTR_NESTED_DEVLINK,
119 goto nla_put_failure;
121 genlmsg_end(msg, hdr);
125 genlmsg_cancel(msg, hdr);
129 static void devlink_linecard_notify(struct devlink_linecard *linecard,
130 enum devlink_command cmd)
132 struct devlink *devlink = linecard->devlink;
136 WARN_ON(cmd != DEVLINK_CMD_LINECARD_NEW &&
137 cmd != DEVLINK_CMD_LINECARD_DEL);
139 if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED))
142 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
146 err = devlink_nl_linecard_fill(msg, devlink, linecard, cmd, 0, 0, 0,
153 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
154 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
157 void devlink_linecards_notify_register(struct devlink *devlink)
159 struct devlink_linecard *linecard;
161 list_for_each_entry(linecard, &devlink->linecard_list, list)
162 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
165 void devlink_linecards_notify_unregister(struct devlink *devlink)
167 struct devlink_linecard *linecard;
169 list_for_each_entry_reverse(linecard, &devlink->linecard_list, list)
170 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL);
173 int devlink_nl_linecard_get_doit(struct sk_buff *skb, struct genl_info *info)
175 struct devlink *devlink = info->user_ptr[0];
176 struct devlink_linecard *linecard;
180 linecard = devlink_linecard_get_from_info(devlink, info);
181 if (IS_ERR(linecard))
182 return PTR_ERR(linecard);
184 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
188 mutex_lock(&linecard->state_lock);
189 err = devlink_nl_linecard_fill(msg, devlink, linecard,
190 DEVLINK_CMD_LINECARD_NEW,
191 info->snd_portid, info->snd_seq, 0,
193 mutex_unlock(&linecard->state_lock);
199 return genlmsg_reply(msg, info);
202 static int devlink_nl_linecard_get_dump_one(struct sk_buff *msg,
203 struct devlink *devlink,
204 struct netlink_callback *cb,
207 struct devlink_nl_dump_state *state = devlink_dump_state(cb);
208 struct devlink_linecard *linecard;
212 list_for_each_entry(linecard, &devlink->linecard_list, list) {
213 if (idx < state->idx) {
217 mutex_lock(&linecard->state_lock);
218 err = devlink_nl_linecard_fill(msg, devlink, linecard,
219 DEVLINK_CMD_LINECARD_NEW,
220 NETLINK_CB(cb->skb).portid,
221 cb->nlh->nlmsg_seq, flags,
223 mutex_unlock(&linecard->state_lock);
234 int devlink_nl_linecard_get_dumpit(struct sk_buff *skb,
235 struct netlink_callback *cb)
237 return devlink_nl_dumpit(skb, cb, devlink_nl_linecard_get_dump_one);
240 static struct devlink_linecard_type *
241 devlink_linecard_type_lookup(struct devlink_linecard *linecard,
244 struct devlink_linecard_type *linecard_type;
247 for (i = 0; i < linecard->types_count; i++) {
248 linecard_type = &linecard->types[i];
249 if (!strcmp(type, linecard_type->type))
250 return linecard_type;
255 static int devlink_linecard_type_set(struct devlink_linecard *linecard,
257 struct netlink_ext_ack *extack)
259 const struct devlink_linecard_ops *ops = linecard->ops;
260 struct devlink_linecard_type *linecard_type;
263 mutex_lock(&linecard->state_lock);
264 if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) {
265 NL_SET_ERR_MSG(extack, "Line card is currently being provisioned");
269 if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) {
270 NL_SET_ERR_MSG(extack, "Line card is currently being unprovisioned");
275 linecard_type = devlink_linecard_type_lookup(linecard, type);
276 if (!linecard_type) {
277 NL_SET_ERR_MSG(extack, "Unsupported line card type provided");
282 if (linecard->state != DEVLINK_LINECARD_STATE_UNPROVISIONED &&
283 linecard->state != DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) {
284 NL_SET_ERR_MSG(extack, "Line card already provisioned");
286 /* Check if the line card is provisioned in the same
287 * way the user asks. In case it is, make the operation
290 if (ops->same_provision &&
291 ops->same_provision(linecard, linecard->priv,
293 linecard_type->priv))
298 linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING;
299 linecard->type = linecard_type->type;
300 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
301 mutex_unlock(&linecard->state_lock);
302 err = ops->provision(linecard, linecard->priv, linecard_type->type,
303 linecard_type->priv, extack);
305 /* Provisioning failed. Assume the linecard is unprovisioned
306 * for future operations.
308 mutex_lock(&linecard->state_lock);
309 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
310 linecard->type = NULL;
311 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
312 mutex_unlock(&linecard->state_lock);
317 mutex_unlock(&linecard->state_lock);
321 static int devlink_linecard_type_unset(struct devlink_linecard *linecard,
322 struct netlink_ext_ack *extack)
326 mutex_lock(&linecard->state_lock);
327 if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) {
328 NL_SET_ERR_MSG(extack, "Line card is currently being provisioned");
332 if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) {
333 NL_SET_ERR_MSG(extack, "Line card is currently being unprovisioned");
337 if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) {
338 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
339 linecard->type = NULL;
340 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
345 if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONED) {
346 NL_SET_ERR_MSG(extack, "Line card is not provisioned");
350 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONING;
351 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
352 mutex_unlock(&linecard->state_lock);
353 err = linecard->ops->unprovision(linecard, linecard->priv,
356 /* Unprovisioning failed. Assume the linecard is unprovisioned
357 * for future operations.
359 mutex_lock(&linecard->state_lock);
360 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
361 linecard->type = NULL;
362 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
363 mutex_unlock(&linecard->state_lock);
368 mutex_unlock(&linecard->state_lock);
372 int devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb,
373 struct genl_info *info)
375 struct netlink_ext_ack *extack = info->extack;
376 struct devlink *devlink = info->user_ptr[0];
377 struct devlink_linecard *linecard;
380 linecard = devlink_linecard_get_from_info(devlink, info);
381 if (IS_ERR(linecard))
382 return PTR_ERR(linecard);
384 if (info->attrs[DEVLINK_ATTR_LINECARD_TYPE]) {
387 type = nla_data(info->attrs[DEVLINK_ATTR_LINECARD_TYPE]);
388 if (strcmp(type, "")) {
389 err = devlink_linecard_type_set(linecard, type, extack);
393 err = devlink_linecard_type_unset(linecard, extack);
402 static int devlink_linecard_types_init(struct devlink_linecard *linecard)
404 struct devlink_linecard_type *linecard_type;
408 count = linecard->ops->types_count(linecard, linecard->priv);
409 linecard->types = kmalloc_array(count, sizeof(*linecard_type),
411 if (!linecard->types)
413 linecard->types_count = count;
415 for (i = 0; i < count; i++) {
416 linecard_type = &linecard->types[i];
417 linecard->ops->types_get(linecard, linecard->priv, i,
418 &linecard_type->type,
419 &linecard_type->priv);
424 static void devlink_linecard_types_fini(struct devlink_linecard *linecard)
426 kfree(linecard->types);
430 * devl_linecard_create - Create devlink linecard
433 * @linecard_index: driver-specific numerical identifier of the linecard
434 * @ops: linecards ops
435 * @priv: user priv pointer
437 * Create devlink linecard instance with provided linecard index.
438 * Caller can use any indexing, even hw-related one.
440 * Return: Line card structure or an ERR_PTR() encoded error code.
442 struct devlink_linecard *
443 devl_linecard_create(struct devlink *devlink, unsigned int linecard_index,
444 const struct devlink_linecard_ops *ops, void *priv)
446 struct devlink_linecard *linecard;
449 if (WARN_ON(!ops || !ops->provision || !ops->unprovision ||
450 !ops->types_count || !ops->types_get))
451 return ERR_PTR(-EINVAL);
453 if (devlink_linecard_index_exists(devlink, linecard_index))
454 return ERR_PTR(-EEXIST);
456 linecard = kzalloc(sizeof(*linecard), GFP_KERNEL);
458 return ERR_PTR(-ENOMEM);
460 linecard->devlink = devlink;
461 linecard->index = linecard_index;
463 linecard->priv = priv;
464 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
465 mutex_init(&linecard->state_lock);
467 err = devlink_linecard_types_init(linecard);
469 mutex_destroy(&linecard->state_lock);
474 list_add_tail(&linecard->list, &devlink->linecard_list);
475 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
478 EXPORT_SYMBOL_GPL(devl_linecard_create);
481 * devl_linecard_destroy - Destroy devlink linecard
483 * @linecard: devlink linecard
485 void devl_linecard_destroy(struct devlink_linecard *linecard)
487 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL);
488 list_del(&linecard->list);
489 devlink_linecard_types_fini(linecard);
490 mutex_destroy(&linecard->state_lock);
493 EXPORT_SYMBOL_GPL(devl_linecard_destroy);
496 * devlink_linecard_provision_set - Set provisioning on linecard
498 * @linecard: devlink linecard
499 * @type: linecard type
501 * This is either called directly from the provision() op call or
502 * as a result of the provision() op call asynchronously.
504 void devlink_linecard_provision_set(struct devlink_linecard *linecard,
507 mutex_lock(&linecard->state_lock);
508 WARN_ON(linecard->type && strcmp(linecard->type, type));
509 linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED;
510 linecard->type = type;
511 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
512 mutex_unlock(&linecard->state_lock);
514 EXPORT_SYMBOL_GPL(devlink_linecard_provision_set);
517 * devlink_linecard_provision_clear - Clear provisioning on linecard
519 * @linecard: devlink linecard
521 * This is either called directly from the unprovision() op call or
522 * as a result of the unprovision() op call asynchronously.
524 void devlink_linecard_provision_clear(struct devlink_linecard *linecard)
526 mutex_lock(&linecard->state_lock);
527 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
528 linecard->type = NULL;
529 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
530 mutex_unlock(&linecard->state_lock);
532 EXPORT_SYMBOL_GPL(devlink_linecard_provision_clear);
535 * devlink_linecard_provision_fail - Fail provisioning on linecard
537 * @linecard: devlink linecard
539 * This is either called directly from the provision() op call or
540 * as a result of the provision() op call asynchronously.
542 void devlink_linecard_provision_fail(struct devlink_linecard *linecard)
544 mutex_lock(&linecard->state_lock);
545 linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING_FAILED;
546 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
547 mutex_unlock(&linecard->state_lock);
549 EXPORT_SYMBOL_GPL(devlink_linecard_provision_fail);
552 * devlink_linecard_activate - Set linecard active
554 * @linecard: devlink linecard
556 void devlink_linecard_activate(struct devlink_linecard *linecard)
558 mutex_lock(&linecard->state_lock);
559 WARN_ON(linecard->state != DEVLINK_LINECARD_STATE_PROVISIONED);
560 linecard->state = DEVLINK_LINECARD_STATE_ACTIVE;
561 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
562 mutex_unlock(&linecard->state_lock);
564 EXPORT_SYMBOL_GPL(devlink_linecard_activate);
567 * devlink_linecard_deactivate - Set linecard inactive
569 * @linecard: devlink linecard
571 void devlink_linecard_deactivate(struct devlink_linecard *linecard)
573 mutex_lock(&linecard->state_lock);
574 switch (linecard->state) {
575 case DEVLINK_LINECARD_STATE_ACTIVE:
576 linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED;
577 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
579 case DEVLINK_LINECARD_STATE_UNPROVISIONING:
580 /* Line card is being deactivated as part
581 * of unprovisioning flow.
588 mutex_unlock(&linecard->state_lock);
590 EXPORT_SYMBOL_GPL(devlink_linecard_deactivate);
592 static void devlink_linecard_rel_notify_cb(struct devlink *devlink,
595 struct devlink_linecard *linecard;
597 linecard = devlink_linecard_get_by_index(devlink, linecard_index);
600 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
603 static void devlink_linecard_rel_cleanup_cb(struct devlink *devlink,
604 u32 linecard_index, u32 rel_index)
606 struct devlink_linecard *linecard;
608 linecard = devlink_linecard_get_by_index(devlink, linecard_index);
609 if (linecard && linecard->rel_index == rel_index)
610 linecard->rel_index = 0;
614 * devlink_linecard_nested_dl_set - Attach/detach nested devlink
615 * instance to linecard.
617 * @linecard: devlink linecard
618 * @nested_devlink: devlink instance to attach or NULL to detach
620 int devlink_linecard_nested_dl_set(struct devlink_linecard *linecard,
621 struct devlink *nested_devlink)
623 return devlink_rel_nested_in_add(&linecard->rel_index,
624 linecard->devlink->index,
626 devlink_linecard_rel_notify_cb,
627 devlink_linecard_rel_cleanup_cb,
630 EXPORT_SYMBOL_GPL(devlink_linecard_nested_dl_set);