1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2016 Mellanox Technologies. All rights reserved. 4 * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com> 5 */ 6 7 #include "devl_internal.h" 8 9 static struct devlink_linecard * 10 devlink_linecard_get_by_index(struct devlink *devlink, 11 unsigned int linecard_index) 12 { 13 struct devlink_linecard *devlink_linecard; 14 15 list_for_each_entry(devlink_linecard, &devlink->linecard_list, list) { 16 if (devlink_linecard->index == linecard_index) 17 return devlink_linecard; 18 } 19 return NULL; 20 } 21 22 static bool devlink_linecard_index_exists(struct devlink *devlink, 23 unsigned int linecard_index) 24 { 25 return devlink_linecard_get_by_index(devlink, linecard_index); 26 } 27 28 static struct devlink_linecard * 29 devlink_linecard_get_from_attrs(struct devlink *devlink, struct nlattr **attrs) 30 { 31 if (attrs[DEVLINK_ATTR_LINECARD_INDEX]) { 32 u32 linecard_index = nla_get_u32(attrs[DEVLINK_ATTR_LINECARD_INDEX]); 33 struct devlink_linecard *linecard; 34 35 linecard = devlink_linecard_get_by_index(devlink, linecard_index); 36 if (!linecard) 37 return ERR_PTR(-ENODEV); 38 return linecard; 39 } 40 return ERR_PTR(-EINVAL); 41 } 42 43 static struct devlink_linecard * 44 devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info) 45 { 46 return devlink_linecard_get_from_attrs(devlink, info->attrs); 47 } 48 49 static int devlink_nl_put_nested_handle(struct sk_buff *msg, struct devlink *devlink) 50 { 51 struct nlattr *nested_attr; 52 53 nested_attr = nla_nest_start(msg, DEVLINK_ATTR_NESTED_DEVLINK); 54 if (!nested_attr) 55 return -EMSGSIZE; 56 if (devlink_nl_put_handle(msg, devlink)) 57 goto nla_put_failure; 58 59 nla_nest_end(msg, nested_attr); 60 return 0; 61 62 nla_put_failure: 63 nla_nest_cancel(msg, nested_attr); 64 return -EMSGSIZE; 65 } 66 67 struct devlink_linecard_type { 68 const char *type; 69 const void *priv; 70 }; 71 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, 76 u32 seq, int flags, 77 struct netlink_ext_ack *extack) 78 { 79 struct devlink_linecard_type *linecard_type; 80 struct nlattr *attr; 81 void *hdr; 82 int i; 83 84 hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); 85 if (!hdr) 86 return -EMSGSIZE; 87 88 if (devlink_nl_put_handle(msg, devlink)) 89 goto nla_put_failure; 90 if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index)) 91 goto nla_put_failure; 92 if (nla_put_u8(msg, DEVLINK_ATTR_LINECARD_STATE, linecard->state)) 93 goto nla_put_failure; 94 if (linecard->type && 95 nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE, linecard->type)) 96 goto nla_put_failure; 97 98 if (linecard->types_count) { 99 attr = nla_nest_start(msg, 100 DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES); 101 if (!attr) 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; 109 } 110 } 111 nla_nest_end(msg, attr); 112 } 113 114 if (linecard->nested_devlink && 115 devlink_nl_put_nested_handle(msg, linecard->nested_devlink)) 116 goto nla_put_failure; 117 118 genlmsg_end(msg, hdr); 119 return 0; 120 121 nla_put_failure: 122 genlmsg_cancel(msg, hdr); 123 return -EMSGSIZE; 124 } 125 126 static void devlink_linecard_notify(struct devlink_linecard *linecard, 127 enum devlink_command cmd) 128 { 129 struct devlink *devlink = linecard->devlink; 130 struct sk_buff *msg; 131 int err; 132 133 WARN_ON(cmd != DEVLINK_CMD_LINECARD_NEW && 134 cmd != DEVLINK_CMD_LINECARD_DEL); 135 136 if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED)) 137 return; 138 139 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 140 if (!msg) 141 return; 142 143 err = devlink_nl_linecard_fill(msg, devlink, linecard, cmd, 0, 0, 0, 144 NULL); 145 if (err) { 146 nlmsg_free(msg); 147 return; 148 } 149 150 genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), 151 msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); 152 } 153 154 void devlink_linecards_notify_register(struct devlink *devlink) 155 { 156 struct devlink_linecard *linecard; 157 158 list_for_each_entry(linecard, &devlink->linecard_list, list) 159 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); 160 } 161 162 void devlink_linecards_notify_unregister(struct devlink *devlink) 163 { 164 struct devlink_linecard *linecard; 165 166 list_for_each_entry_reverse(linecard, &devlink->linecard_list, list) 167 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL); 168 } 169 170 int devlink_nl_linecard_get_doit(struct sk_buff *skb, struct genl_info *info) 171 { 172 struct devlink *devlink = info->user_ptr[0]; 173 struct devlink_linecard *linecard; 174 struct sk_buff *msg; 175 int err; 176 177 linecard = devlink_linecard_get_from_info(devlink, info); 178 if (IS_ERR(linecard)) 179 return PTR_ERR(linecard); 180 181 msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 182 if (!msg) 183 return -ENOMEM; 184 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, 189 info->extack); 190 mutex_unlock(&linecard->state_lock); 191 if (err) { 192 nlmsg_free(msg); 193 return err; 194 } 195 196 return genlmsg_reply(msg, info); 197 } 198 199 static int devlink_nl_linecard_get_dump_one(struct sk_buff *msg, 200 struct devlink *devlink, 201 struct netlink_callback *cb, 202 int flags) 203 { 204 struct devlink_nl_dump_state *state = devlink_dump_state(cb); 205 struct devlink_linecard *linecard; 206 int idx = 0; 207 int err = 0; 208 209 list_for_each_entry(linecard, &devlink->linecard_list, list) { 210 if (idx < state->idx) { 211 idx++; 212 continue; 213 } 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, 219 cb->extack); 220 mutex_unlock(&linecard->state_lock); 221 if (err) { 222 state->idx = idx; 223 break; 224 } 225 idx++; 226 } 227 228 return err; 229 } 230 231 int devlink_nl_linecard_get_dumpit(struct sk_buff *skb, 232 struct netlink_callback *cb) 233 { 234 return devlink_nl_dumpit(skb, cb, devlink_nl_linecard_get_dump_one); 235 } 236 237 static struct devlink_linecard_type * 238 devlink_linecard_type_lookup(struct devlink_linecard *linecard, 239 const char *type) 240 { 241 struct devlink_linecard_type *linecard_type; 242 int i; 243 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; 248 } 249 return NULL; 250 } 251 252 static int devlink_linecard_type_set(struct devlink_linecard *linecard, 253 const char *type, 254 struct netlink_ext_ack *extack) 255 { 256 const struct devlink_linecard_ops *ops = linecard->ops; 257 struct devlink_linecard_type *linecard_type; 258 int err; 259 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"); 263 err = -EBUSY; 264 goto out; 265 } 266 if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) { 267 NL_SET_ERR_MSG(extack, "Line card is currently being unprovisioned"); 268 err = -EBUSY; 269 goto out; 270 } 271 272 linecard_type = devlink_linecard_type_lookup(linecard, type); 273 if (!linecard_type) { 274 NL_SET_ERR_MSG(extack, "Unsupported line card type provided"); 275 err = -EINVAL; 276 goto out; 277 } 278 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"); 282 err = -EBUSY; 283 /* Check if the line card is provisioned in the same 284 * way the user asks. In case it is, make the operation 285 * to return success. 286 */ 287 if (ops->same_provision && 288 ops->same_provision(linecard, linecard->priv, 289 linecard_type->type, 290 linecard_type->priv)) 291 err = 0; 292 goto out; 293 } 294 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); 301 if (err) { 302 /* Provisioning failed. Assume the linecard is unprovisioned 303 * for future operations. 304 */ 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); 310 } 311 return err; 312 313 out: 314 mutex_unlock(&linecard->state_lock); 315 return err; 316 } 317 318 static int devlink_linecard_type_unset(struct devlink_linecard *linecard, 319 struct netlink_ext_ack *extack) 320 { 321 int err; 322 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"); 326 err = -EBUSY; 327 goto out; 328 } 329 if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) { 330 NL_SET_ERR_MSG(extack, "Line card is currently being unprovisioned"); 331 err = -EBUSY; 332 goto out; 333 } 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); 338 err = 0; 339 goto out; 340 } 341 342 if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONED) { 343 NL_SET_ERR_MSG(extack, "Line card is not provisioned"); 344 err = 0; 345 goto out; 346 } 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, 351 extack); 352 if (err) { 353 /* Unprovisioning failed. Assume the linecard is unprovisioned 354 * for future operations. 355 */ 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); 361 } 362 return err; 363 364 out: 365 mutex_unlock(&linecard->state_lock); 366 return err; 367 } 368 369 int devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb, 370 struct genl_info *info) 371 { 372 struct netlink_ext_ack *extack = info->extack; 373 struct devlink *devlink = info->user_ptr[0]; 374 struct devlink_linecard *linecard; 375 int err; 376 377 linecard = devlink_linecard_get_from_info(devlink, info); 378 if (IS_ERR(linecard)) 379 return PTR_ERR(linecard); 380 381 if (info->attrs[DEVLINK_ATTR_LINECARD_TYPE]) { 382 const char *type; 383 384 type = nla_data(info->attrs[DEVLINK_ATTR_LINECARD_TYPE]); 385 if (strcmp(type, "")) { 386 err = devlink_linecard_type_set(linecard, type, extack); 387 if (err) 388 return err; 389 } else { 390 err = devlink_linecard_type_unset(linecard, extack); 391 if (err) 392 return err; 393 } 394 } 395 396 return 0; 397 } 398 399 static int devlink_linecard_types_init(struct devlink_linecard *linecard) 400 { 401 struct devlink_linecard_type *linecard_type; 402 unsigned int count; 403 int i; 404 405 count = linecard->ops->types_count(linecard, linecard->priv); 406 linecard->types = kmalloc_array(count, sizeof(*linecard_type), 407 GFP_KERNEL); 408 if (!linecard->types) 409 return -ENOMEM; 410 linecard->types_count = count; 411 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); 417 } 418 return 0; 419 } 420 421 static void devlink_linecard_types_fini(struct devlink_linecard *linecard) 422 { 423 kfree(linecard->types); 424 } 425 426 /** 427 * devl_linecard_create - Create devlink linecard 428 * 429 * @devlink: devlink 430 * @linecard_index: driver-specific numerical identifier of the linecard 431 * @ops: linecards ops 432 * @priv: user priv pointer 433 * 434 * Create devlink linecard instance with provided linecard index. 435 * Caller can use any indexing, even hw-related one. 436 * 437 * Return: Line card structure or an ERR_PTR() encoded error code. 438 */ 439 struct devlink_linecard * 440 devl_linecard_create(struct devlink *devlink, unsigned int linecard_index, 441 const struct devlink_linecard_ops *ops, void *priv) 442 { 443 struct devlink_linecard *linecard; 444 int err; 445 446 if (WARN_ON(!ops || !ops->provision || !ops->unprovision || 447 !ops->types_count || !ops->types_get)) 448 return ERR_PTR(-EINVAL); 449 450 if (devlink_linecard_index_exists(devlink, linecard_index)) 451 return ERR_PTR(-EEXIST); 452 453 linecard = kzalloc(sizeof(*linecard), GFP_KERNEL); 454 if (!linecard) 455 return ERR_PTR(-ENOMEM); 456 457 linecard->devlink = devlink; 458 linecard->index = linecard_index; 459 linecard->ops = ops; 460 linecard->priv = priv; 461 linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; 462 mutex_init(&linecard->state_lock); 463 464 err = devlink_linecard_types_init(linecard); 465 if (err) { 466 mutex_destroy(&linecard->state_lock); 467 kfree(linecard); 468 return ERR_PTR(err); 469 } 470 471 list_add_tail(&linecard->list, &devlink->linecard_list); 472 devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); 473 return linecard; 474 } 475 EXPORT_SYMBOL_GPL(devl_linecard_create); 476 477 /** 478 * devl_linecard_destroy - Destroy devlink linecard 479 * 480 * @linecard: devlink linecard 481 */ 482 void devl_linecard_destroy(struct devlink_linecard *linecard) 483 { 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); 488 kfree(linecard); 489 } 490 EXPORT_SYMBOL_GPL(devl_linecard_destroy); 491 492 /** 493 * devlink_linecard_provision_set - Set provisioning on linecard 494 * 495 * @linecard: devlink linecard 496 * @type: linecard type 497 * 498 * This is either called directly from the provision() op call or 499 * as a result of the provision() op call asynchronously. 500 */ 501 void devlink_linecard_provision_set(struct devlink_linecard *linecard, 502 const char *type) 503 { 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); 510 } 511 EXPORT_SYMBOL_GPL(devlink_linecard_provision_set); 512 513 /** 514 * devlink_linecard_provision_clear - Clear provisioning on linecard 515 * 516 * @linecard: devlink linecard 517 * 518 * This is either called directly from the unprovision() op call or 519 * as a result of the unprovision() op call asynchronously. 520 */ 521 void devlink_linecard_provision_clear(struct devlink_linecard *linecard) 522 { 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); 529 } 530 EXPORT_SYMBOL_GPL(devlink_linecard_provision_clear); 531 532 /** 533 * devlink_linecard_provision_fail - Fail provisioning on linecard 534 * 535 * @linecard: devlink linecard 536 * 537 * This is either called directly from the provision() op call or 538 * as a result of the provision() op call asynchronously. 539 */ 540 void devlink_linecard_provision_fail(struct devlink_linecard *linecard) 541 { 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); 547 } 548 EXPORT_SYMBOL_GPL(devlink_linecard_provision_fail); 549 550 /** 551 * devlink_linecard_activate - Set linecard active 552 * 553 * @linecard: devlink linecard 554 */ 555 void devlink_linecard_activate(struct devlink_linecard *linecard) 556 { 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); 562 } 563 EXPORT_SYMBOL_GPL(devlink_linecard_activate); 564 565 /** 566 * devlink_linecard_deactivate - Set linecard inactive 567 * 568 * @linecard: devlink linecard 569 */ 570 void devlink_linecard_deactivate(struct devlink_linecard *linecard) 571 { 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); 577 break; 578 case DEVLINK_LINECARD_STATE_UNPROVISIONING: 579 /* Line card is being deactivated as part 580 * of unprovisioning flow. 581 */ 582 break; 583 default: 584 WARN_ON(1); 585 break; 586 } 587 mutex_unlock(&linecard->state_lock); 588 } 589 EXPORT_SYMBOL_GPL(devlink_linecard_deactivate); 590 591 /** 592 * devlink_linecard_nested_dl_set - Attach/detach nested devlink 593 * instance to linecard. 594 * 595 * @linecard: devlink linecard 596 * @nested_devlink: devlink instance to attach or NULL to detach 597 */ 598 void devlink_linecard_nested_dl_set(struct devlink_linecard *linecard, 599 struct devlink *nested_devlink) 600 { 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); 605 } 606 EXPORT_SYMBOL_GPL(devlink_linecard_nested_dl_set); 607