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 (!__devl_is_registered(devlink
) || !devlink_nl_notify_need(devlink
))
142 msg
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
146 err
= devlink_nl_linecard_fill(msg
, devlink
, linecard
, cmd
, 0, 0, 0,
153 devlink_nl_notify_send(devlink
, msg
);
156 void devlink_linecards_notify_register(struct devlink
*devlink
)
158 struct devlink_linecard
*linecard
;
160 list_for_each_entry(linecard
, &devlink
->linecard_list
, list
)
161 devlink_linecard_notify(linecard
, DEVLINK_CMD_LINECARD_NEW
);
164 void devlink_linecards_notify_unregister(struct devlink
*devlink
)
166 struct devlink_linecard
*linecard
;
168 list_for_each_entry_reverse(linecard
, &devlink
->linecard_list
, list
)
169 devlink_linecard_notify(linecard
, DEVLINK_CMD_LINECARD_DEL
);
172 int devlink_nl_linecard_get_doit(struct sk_buff
*skb
, struct genl_info
*info
)
174 struct devlink
*devlink
= info
->user_ptr
[0];
175 struct devlink_linecard
*linecard
;
179 linecard
= devlink_linecard_get_from_info(devlink
, info
);
180 if (IS_ERR(linecard
))
181 return PTR_ERR(linecard
);
183 msg
= nlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
187 mutex_lock(&linecard
->state_lock
);
188 err
= devlink_nl_linecard_fill(msg
, devlink
, linecard
,
189 DEVLINK_CMD_LINECARD_NEW
,
190 info
->snd_portid
, info
->snd_seq
, 0,
192 mutex_unlock(&linecard
->state_lock
);
198 return genlmsg_reply(msg
, info
);
201 static int devlink_nl_linecard_get_dump_one(struct sk_buff
*msg
,
202 struct devlink
*devlink
,
203 struct netlink_callback
*cb
,
206 struct devlink_nl_dump_state
*state
= devlink_dump_state(cb
);
207 struct devlink_linecard
*linecard
;
211 list_for_each_entry(linecard
, &devlink
->linecard_list
, list
) {
212 if (idx
< state
->idx
) {
216 mutex_lock(&linecard
->state_lock
);
217 err
= devlink_nl_linecard_fill(msg
, devlink
, linecard
,
218 DEVLINK_CMD_LINECARD_NEW
,
219 NETLINK_CB(cb
->skb
).portid
,
220 cb
->nlh
->nlmsg_seq
, flags
,
222 mutex_unlock(&linecard
->state_lock
);
233 int devlink_nl_linecard_get_dumpit(struct sk_buff
*skb
,
234 struct netlink_callback
*cb
)
236 return devlink_nl_dumpit(skb
, cb
, devlink_nl_linecard_get_dump_one
);
239 static struct devlink_linecard_type
*
240 devlink_linecard_type_lookup(struct devlink_linecard
*linecard
,
243 struct devlink_linecard_type
*linecard_type
;
246 for (i
= 0; i
< linecard
->types_count
; i
++) {
247 linecard_type
= &linecard
->types
[i
];
248 if (!strcmp(type
, linecard_type
->type
))
249 return linecard_type
;
254 static int devlink_linecard_type_set(struct devlink_linecard
*linecard
,
256 struct netlink_ext_ack
*extack
)
258 const struct devlink_linecard_ops
*ops
= linecard
->ops
;
259 struct devlink_linecard_type
*linecard_type
;
262 mutex_lock(&linecard
->state_lock
);
263 if (linecard
->state
== DEVLINK_LINECARD_STATE_PROVISIONING
) {
264 NL_SET_ERR_MSG(extack
, "Line card is currently being provisioned");
268 if (linecard
->state
== DEVLINK_LINECARD_STATE_UNPROVISIONING
) {
269 NL_SET_ERR_MSG(extack
, "Line card is currently being unprovisioned");
274 linecard_type
= devlink_linecard_type_lookup(linecard
, type
);
275 if (!linecard_type
) {
276 NL_SET_ERR_MSG(extack
, "Unsupported line card type provided");
281 if (linecard
->state
!= DEVLINK_LINECARD_STATE_UNPROVISIONED
&&
282 linecard
->state
!= DEVLINK_LINECARD_STATE_PROVISIONING_FAILED
) {
283 NL_SET_ERR_MSG(extack
, "Line card already provisioned");
285 /* Check if the line card is provisioned in the same
286 * way the user asks. In case it is, make the operation
289 if (ops
->same_provision
&&
290 ops
->same_provision(linecard
, linecard
->priv
,
292 linecard_type
->priv
))
297 linecard
->state
= DEVLINK_LINECARD_STATE_PROVISIONING
;
298 linecard
->type
= linecard_type
->type
;
299 devlink_linecard_notify(linecard
, DEVLINK_CMD_LINECARD_NEW
);
300 mutex_unlock(&linecard
->state_lock
);
301 err
= ops
->provision(linecard
, linecard
->priv
, linecard_type
->type
,
302 linecard_type
->priv
, extack
);
304 /* Provisioning failed. Assume the linecard is unprovisioned
305 * for future operations.
307 mutex_lock(&linecard
->state_lock
);
308 linecard
->state
= DEVLINK_LINECARD_STATE_UNPROVISIONED
;
309 linecard
->type
= NULL
;
310 devlink_linecard_notify(linecard
, DEVLINK_CMD_LINECARD_NEW
);
311 mutex_unlock(&linecard
->state_lock
);
316 mutex_unlock(&linecard
->state_lock
);
320 static int devlink_linecard_type_unset(struct devlink_linecard
*linecard
,
321 struct netlink_ext_ack
*extack
)
325 mutex_lock(&linecard
->state_lock
);
326 if (linecard
->state
== DEVLINK_LINECARD_STATE_PROVISIONING
) {
327 NL_SET_ERR_MSG(extack
, "Line card is currently being provisioned");
331 if (linecard
->state
== DEVLINK_LINECARD_STATE_UNPROVISIONING
) {
332 NL_SET_ERR_MSG(extack
, "Line card is currently being unprovisioned");
336 if (linecard
->state
== DEVLINK_LINECARD_STATE_PROVISIONING_FAILED
) {
337 linecard
->state
= DEVLINK_LINECARD_STATE_UNPROVISIONED
;
338 linecard
->type
= NULL
;
339 devlink_linecard_notify(linecard
, DEVLINK_CMD_LINECARD_NEW
);
344 if (linecard
->state
== DEVLINK_LINECARD_STATE_UNPROVISIONED
) {
345 NL_SET_ERR_MSG(extack
, "Line card is not provisioned");
349 linecard
->state
= DEVLINK_LINECARD_STATE_UNPROVISIONING
;
350 devlink_linecard_notify(linecard
, DEVLINK_CMD_LINECARD_NEW
);
351 mutex_unlock(&linecard
->state_lock
);
352 err
= linecard
->ops
->unprovision(linecard
, linecard
->priv
,
355 /* Unprovisioning failed. Assume the linecard is unprovisioned
356 * for future operations.
358 mutex_lock(&linecard
->state_lock
);
359 linecard
->state
= DEVLINK_LINECARD_STATE_UNPROVISIONED
;
360 linecard
->type
= NULL
;
361 devlink_linecard_notify(linecard
, DEVLINK_CMD_LINECARD_NEW
);
362 mutex_unlock(&linecard
->state_lock
);
367 mutex_unlock(&linecard
->state_lock
);
371 int devlink_nl_linecard_set_doit(struct sk_buff
*skb
, struct genl_info
*info
)
373 struct netlink_ext_ack
*extack
= info
->extack
;
374 struct devlink
*devlink
= info
->user_ptr
[0];
375 struct devlink_linecard
*linecard
;
378 linecard
= devlink_linecard_get_from_info(devlink
, info
);
379 if (IS_ERR(linecard
))
380 return PTR_ERR(linecard
);
382 if (info
->attrs
[DEVLINK_ATTR_LINECARD_TYPE
]) {
385 type
= nla_data(info
->attrs
[DEVLINK_ATTR_LINECARD_TYPE
]);
386 if (strcmp(type
, "")) {
387 err
= devlink_linecard_type_set(linecard
, type
, extack
);
391 err
= devlink_linecard_type_unset(linecard
, extack
);
400 static int devlink_linecard_types_init(struct devlink_linecard
*linecard
)
402 struct devlink_linecard_type
*linecard_type
;
406 count
= linecard
->ops
->types_count(linecard
, linecard
->priv
);
407 linecard
->types
= kmalloc_array(count
, sizeof(*linecard_type
),
409 if (!linecard
->types
)
411 linecard
->types_count
= count
;
413 for (i
= 0; i
< count
; i
++) {
414 linecard_type
= &linecard
->types
[i
];
415 linecard
->ops
->types_get(linecard
, linecard
->priv
, i
,
416 &linecard_type
->type
,
417 &linecard_type
->priv
);
422 static void devlink_linecard_types_fini(struct devlink_linecard
*linecard
)
424 kfree(linecard
->types
);
428 * devl_linecard_create - Create devlink linecard
431 * @linecard_index: driver-specific numerical identifier of the linecard
432 * @ops: linecards ops
433 * @priv: user priv pointer
435 * Create devlink linecard instance with provided linecard index.
436 * Caller can use any indexing, even hw-related one.
438 * Return: Line card structure or an ERR_PTR() encoded error code.
440 struct devlink_linecard
*
441 devl_linecard_create(struct devlink
*devlink
, unsigned int linecard_index
,
442 const struct devlink_linecard_ops
*ops
, void *priv
)
444 struct devlink_linecard
*linecard
;
447 if (WARN_ON(!ops
|| !ops
->provision
|| !ops
->unprovision
||
448 !ops
->types_count
|| !ops
->types_get
))
449 return ERR_PTR(-EINVAL
);
451 if (devlink_linecard_index_exists(devlink
, linecard_index
))
452 return ERR_PTR(-EEXIST
);
454 linecard
= kzalloc(sizeof(*linecard
), GFP_KERNEL
);
456 return ERR_PTR(-ENOMEM
);
458 linecard
->devlink
= devlink
;
459 linecard
->index
= linecard_index
;
461 linecard
->priv
= priv
;
462 linecard
->state
= DEVLINK_LINECARD_STATE_UNPROVISIONED
;
463 mutex_init(&linecard
->state_lock
);
465 err
= devlink_linecard_types_init(linecard
);
467 mutex_destroy(&linecard
->state_lock
);
472 list_add_tail(&linecard
->list
, &devlink
->linecard_list
);
473 devlink_linecard_notify(linecard
, DEVLINK_CMD_LINECARD_NEW
);
476 EXPORT_SYMBOL_GPL(devl_linecard_create
);
479 * devl_linecard_destroy - Destroy devlink linecard
481 * @linecard: devlink linecard
483 void devl_linecard_destroy(struct devlink_linecard
*linecard
)
485 devlink_linecard_notify(linecard
, DEVLINK_CMD_LINECARD_DEL
);
486 list_del(&linecard
->list
);
487 devlink_linecard_types_fini(linecard
);
488 mutex_destroy(&linecard
->state_lock
);
491 EXPORT_SYMBOL_GPL(devl_linecard_destroy
);
494 * devlink_linecard_provision_set - Set provisioning on linecard
496 * @linecard: devlink linecard
497 * @type: linecard type
499 * This is either called directly from the provision() op call or
500 * as a result of the provision() op call asynchronously.
502 void devlink_linecard_provision_set(struct devlink_linecard
*linecard
,
505 mutex_lock(&linecard
->state_lock
);
506 WARN_ON(linecard
->type
&& strcmp(linecard
->type
, type
));
507 linecard
->state
= DEVLINK_LINECARD_STATE_PROVISIONED
;
508 linecard
->type
= type
;
509 devlink_linecard_notify(linecard
, DEVLINK_CMD_LINECARD_NEW
);
510 mutex_unlock(&linecard
->state_lock
);
512 EXPORT_SYMBOL_GPL(devlink_linecard_provision_set
);
515 * devlink_linecard_provision_clear - Clear provisioning on linecard
517 * @linecard: devlink linecard
519 * This is either called directly from the unprovision() op call or
520 * as a result of the unprovision() op call asynchronously.
522 void devlink_linecard_provision_clear(struct devlink_linecard
*linecard
)
524 mutex_lock(&linecard
->state_lock
);
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 linecard
->state
= DEVLINK_LINECARD_STATE_PROVISIONING_FAILED
;
544 devlink_linecard_notify(linecard
, DEVLINK_CMD_LINECARD_NEW
);
545 mutex_unlock(&linecard
->state_lock
);
547 EXPORT_SYMBOL_GPL(devlink_linecard_provision_fail
);
550 * devlink_linecard_activate - Set linecard active
552 * @linecard: devlink linecard
554 void devlink_linecard_activate(struct devlink_linecard
*linecard
)
556 mutex_lock(&linecard
->state_lock
);
557 WARN_ON(linecard
->state
!= DEVLINK_LINECARD_STATE_PROVISIONED
);
558 linecard
->state
= DEVLINK_LINECARD_STATE_ACTIVE
;
559 devlink_linecard_notify(linecard
, DEVLINK_CMD_LINECARD_NEW
);
560 mutex_unlock(&linecard
->state_lock
);
562 EXPORT_SYMBOL_GPL(devlink_linecard_activate
);
565 * devlink_linecard_deactivate - Set linecard inactive
567 * @linecard: devlink linecard
569 void devlink_linecard_deactivate(struct devlink_linecard
*linecard
)
571 mutex_lock(&linecard
->state_lock
);
572 switch (linecard
->state
) {
573 case DEVLINK_LINECARD_STATE_ACTIVE
:
574 linecard
->state
= DEVLINK_LINECARD_STATE_PROVISIONED
;
575 devlink_linecard_notify(linecard
, DEVLINK_CMD_LINECARD_NEW
);
577 case DEVLINK_LINECARD_STATE_UNPROVISIONING
:
578 /* Line card is being deactivated as part
579 * of unprovisioning flow.
586 mutex_unlock(&linecard
->state_lock
);
588 EXPORT_SYMBOL_GPL(devlink_linecard_deactivate
);
590 static void devlink_linecard_rel_notify_cb(struct devlink
*devlink
,
593 struct devlink_linecard
*linecard
;
595 linecard
= devlink_linecard_get_by_index(devlink
, linecard_index
);
598 devlink_linecard_notify(linecard
, DEVLINK_CMD_LINECARD_NEW
);
601 static void devlink_linecard_rel_cleanup_cb(struct devlink
*devlink
,
602 u32 linecard_index
, u32 rel_index
)
604 struct devlink_linecard
*linecard
;
606 linecard
= devlink_linecard_get_by_index(devlink
, linecard_index
);
607 if (linecard
&& linecard
->rel_index
== rel_index
)
608 linecard
->rel_index
= 0;
612 * devlink_linecard_nested_dl_set - Attach/detach nested devlink
613 * instance to linecard.
615 * @linecard: devlink linecard
616 * @nested_devlink: devlink instance to attach or NULL to detach
618 int devlink_linecard_nested_dl_set(struct devlink_linecard
*linecard
,
619 struct devlink
*nested_devlink
)
621 return devlink_rel_nested_in_add(&linecard
->rel_index
,
622 linecard
->devlink
->index
,
624 devlink_linecard_rel_notify_cb
,
625 devlink_linecard_rel_cleanup_cb
,
628 EXPORT_SYMBOL_GPL(devlink_linecard_nested_dl_set
);