linecard.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  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. #include "devl_internal.h"
  7. struct devlink_linecard {
  8. struct list_head list;
  9. struct devlink *devlink;
  10. unsigned int index;
  11. const struct devlink_linecard_ops *ops;
  12. void *priv;
  13. enum devlink_linecard_state state;
  14. struct mutex state_lock; /* Protects state */
  15. const char *type;
  16. struct devlink_linecard_type *types;
  17. unsigned int types_count;
  18. u32 rel_index;
  19. };
  20. unsigned int devlink_linecard_index(struct devlink_linecard *linecard)
  21. {
  22. return linecard->index;
  23. }
  24. static struct devlink_linecard *
  25. devlink_linecard_get_by_index(struct devlink *devlink,
  26. unsigned int linecard_index)
  27. {
  28. struct devlink_linecard *devlink_linecard;
  29. list_for_each_entry(devlink_linecard, &devlink->linecard_list, list) {
  30. if (devlink_linecard->index == linecard_index)
  31. return devlink_linecard;
  32. }
  33. return NULL;
  34. }
  35. static bool devlink_linecard_index_exists(struct devlink *devlink,
  36. unsigned int linecard_index)
  37. {
  38. return devlink_linecard_get_by_index(devlink, linecard_index);
  39. }
  40. static struct devlink_linecard *
  41. devlink_linecard_get_from_attrs(struct devlink *devlink, struct nlattr **attrs)
  42. {
  43. if (attrs[DEVLINK_ATTR_LINECARD_INDEX]) {
  44. u32 linecard_index = nla_get_u32(attrs[DEVLINK_ATTR_LINECARD_INDEX]);
  45. struct devlink_linecard *linecard;
  46. linecard = devlink_linecard_get_by_index(devlink, linecard_index);
  47. if (!linecard)
  48. return ERR_PTR(-ENODEV);
  49. return linecard;
  50. }
  51. return ERR_PTR(-EINVAL);
  52. }
  53. static struct devlink_linecard *
  54. devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info)
  55. {
  56. return devlink_linecard_get_from_attrs(devlink, info->attrs);
  57. }
  58. struct devlink_linecard_type {
  59. const char *type;
  60. const void *priv;
  61. };
  62. static int devlink_nl_linecard_fill(struct sk_buff *msg,
  63. struct devlink *devlink,
  64. struct devlink_linecard *linecard,
  65. enum devlink_command cmd, u32 portid,
  66. u32 seq, int flags,
  67. struct netlink_ext_ack *extack)
  68. {
  69. struct devlink_linecard_type *linecard_type;
  70. struct nlattr *attr;
  71. void *hdr;
  72. int i;
  73. hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
  74. if (!hdr)
  75. return -EMSGSIZE;
  76. if (devlink_nl_put_handle(msg, devlink))
  77. goto nla_put_failure;
  78. if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index))
  79. goto nla_put_failure;
  80. if (nla_put_u8(msg, DEVLINK_ATTR_LINECARD_STATE, linecard->state))
  81. goto nla_put_failure;
  82. if (linecard->type &&
  83. nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE, linecard->type))
  84. goto nla_put_failure;
  85. if (linecard->types_count) {
  86. attr = nla_nest_start(msg,
  87. DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES);
  88. if (!attr)
  89. goto nla_put_failure;
  90. for (i = 0; i < linecard->types_count; i++) {
  91. linecard_type = &linecard->types[i];
  92. if (nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE,
  93. linecard_type->type)) {
  94. nla_nest_cancel(msg, attr);
  95. goto nla_put_failure;
  96. }
  97. }
  98. nla_nest_end(msg, attr);
  99. }
  100. if (devlink_rel_devlink_handle_put(msg, devlink,
  101. linecard->rel_index,
  102. DEVLINK_ATTR_NESTED_DEVLINK,
  103. NULL))
  104. goto nla_put_failure;
  105. genlmsg_end(msg, hdr);
  106. return 0;
  107. nla_put_failure:
  108. genlmsg_cancel(msg, hdr);
  109. return -EMSGSIZE;
  110. }
  111. static void devlink_linecard_notify(struct devlink_linecard *linecard,
  112. enum devlink_command cmd)
  113. {
  114. struct devlink *devlink = linecard->devlink;
  115. struct sk_buff *msg;
  116. int err;
  117. WARN_ON(cmd != DEVLINK_CMD_LINECARD_NEW &&
  118. cmd != DEVLINK_CMD_LINECARD_DEL);
  119. if (!__devl_is_registered(devlink) || !devlink_nl_notify_need(devlink))
  120. return;
  121. msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  122. if (!msg)
  123. return;
  124. err = devlink_nl_linecard_fill(msg, devlink, linecard, cmd, 0, 0, 0,
  125. NULL);
  126. if (err) {
  127. nlmsg_free(msg);
  128. return;
  129. }
  130. devlink_nl_notify_send(devlink, msg);
  131. }
  132. void devlink_linecards_notify_register(struct devlink *devlink)
  133. {
  134. struct devlink_linecard *linecard;
  135. list_for_each_entry(linecard, &devlink->linecard_list, list)
  136. devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
  137. }
  138. void devlink_linecards_notify_unregister(struct devlink *devlink)
  139. {
  140. struct devlink_linecard *linecard;
  141. list_for_each_entry_reverse(linecard, &devlink->linecard_list, list)
  142. devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL);
  143. }
  144. int devlink_nl_linecard_get_doit(struct sk_buff *skb, struct genl_info *info)
  145. {
  146. struct devlink *devlink = info->user_ptr[0];
  147. struct devlink_linecard *linecard;
  148. struct sk_buff *msg;
  149. int err;
  150. linecard = devlink_linecard_get_from_info(devlink, info);
  151. if (IS_ERR(linecard))
  152. return PTR_ERR(linecard);
  153. msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
  154. if (!msg)
  155. return -ENOMEM;
  156. mutex_lock(&linecard->state_lock);
  157. err = devlink_nl_linecard_fill(msg, devlink, linecard,
  158. DEVLINK_CMD_LINECARD_NEW,
  159. info->snd_portid, info->snd_seq, 0,
  160. info->extack);
  161. mutex_unlock(&linecard->state_lock);
  162. if (err) {
  163. nlmsg_free(msg);
  164. return err;
  165. }
  166. return genlmsg_reply(msg, info);
  167. }
  168. static int devlink_nl_linecard_get_dump_one(struct sk_buff *msg,
  169. struct devlink *devlink,
  170. struct netlink_callback *cb,
  171. int flags)
  172. {
  173. struct devlink_nl_dump_state *state = devlink_dump_state(cb);
  174. struct devlink_linecard *linecard;
  175. int idx = 0;
  176. int err = 0;
  177. list_for_each_entry(linecard, &devlink->linecard_list, list) {
  178. if (idx < state->idx) {
  179. idx++;
  180. continue;
  181. }
  182. mutex_lock(&linecard->state_lock);
  183. err = devlink_nl_linecard_fill(msg, devlink, linecard,
  184. DEVLINK_CMD_LINECARD_NEW,
  185. NETLINK_CB(cb->skb).portid,
  186. cb->nlh->nlmsg_seq, flags,
  187. cb->extack);
  188. mutex_unlock(&linecard->state_lock);
  189. if (err) {
  190. state->idx = idx;
  191. break;
  192. }
  193. idx++;
  194. }
  195. return err;
  196. }
  197. int devlink_nl_linecard_get_dumpit(struct sk_buff *skb,
  198. struct netlink_callback *cb)
  199. {
  200. return devlink_nl_dumpit(skb, cb, devlink_nl_linecard_get_dump_one);
  201. }
  202. static struct devlink_linecard_type *
  203. devlink_linecard_type_lookup(struct devlink_linecard *linecard,
  204. const char *type)
  205. {
  206. struct devlink_linecard_type *linecard_type;
  207. int i;
  208. for (i = 0; i < linecard->types_count; i++) {
  209. linecard_type = &linecard->types[i];
  210. if (!strcmp(type, linecard_type->type))
  211. return linecard_type;
  212. }
  213. return NULL;
  214. }
  215. static int devlink_linecard_type_set(struct devlink_linecard *linecard,
  216. const char *type,
  217. struct netlink_ext_ack *extack)
  218. {
  219. const struct devlink_linecard_ops *ops = linecard->ops;
  220. struct devlink_linecard_type *linecard_type;
  221. int err;
  222. mutex_lock(&linecard->state_lock);
  223. if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) {
  224. NL_SET_ERR_MSG(extack, "Line card is currently being provisioned");
  225. err = -EBUSY;
  226. goto out;
  227. }
  228. if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) {
  229. NL_SET_ERR_MSG(extack, "Line card is currently being unprovisioned");
  230. err = -EBUSY;
  231. goto out;
  232. }
  233. linecard_type = devlink_linecard_type_lookup(linecard, type);
  234. if (!linecard_type) {
  235. NL_SET_ERR_MSG(extack, "Unsupported line card type provided");
  236. err = -EINVAL;
  237. goto out;
  238. }
  239. if (linecard->state != DEVLINK_LINECARD_STATE_UNPROVISIONED &&
  240. linecard->state != DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) {
  241. NL_SET_ERR_MSG(extack, "Line card already provisioned");
  242. err = -EBUSY;
  243. /* Check if the line card is provisioned in the same
  244. * way the user asks. In case it is, make the operation
  245. * to return success.
  246. */
  247. if (ops->same_provision &&
  248. ops->same_provision(linecard, linecard->priv,
  249. linecard_type->type,
  250. linecard_type->priv))
  251. err = 0;
  252. goto out;
  253. }
  254. linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING;
  255. linecard->type = linecard_type->type;
  256. devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
  257. mutex_unlock(&linecard->state_lock);
  258. err = ops->provision(linecard, linecard->priv, linecard_type->type,
  259. linecard_type->priv, extack);
  260. if (err) {
  261. /* Provisioning failed. Assume the linecard is unprovisioned
  262. * for future operations.
  263. */
  264. mutex_lock(&linecard->state_lock);
  265. linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
  266. linecard->type = NULL;
  267. devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
  268. mutex_unlock(&linecard->state_lock);
  269. }
  270. return err;
  271. out:
  272. mutex_unlock(&linecard->state_lock);
  273. return err;
  274. }
  275. static int devlink_linecard_type_unset(struct devlink_linecard *linecard,
  276. struct netlink_ext_ack *extack)
  277. {
  278. int err;
  279. mutex_lock(&linecard->state_lock);
  280. if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) {
  281. NL_SET_ERR_MSG(extack, "Line card is currently being provisioned");
  282. err = -EBUSY;
  283. goto out;
  284. }
  285. if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) {
  286. NL_SET_ERR_MSG(extack, "Line card is currently being unprovisioned");
  287. err = -EBUSY;
  288. goto out;
  289. }
  290. if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) {
  291. linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
  292. linecard->type = NULL;
  293. devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
  294. err = 0;
  295. goto out;
  296. }
  297. if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONED) {
  298. NL_SET_ERR_MSG(extack, "Line card is not provisioned");
  299. err = 0;
  300. goto out;
  301. }
  302. linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONING;
  303. devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
  304. mutex_unlock(&linecard->state_lock);
  305. err = linecard->ops->unprovision(linecard, linecard->priv,
  306. extack);
  307. if (err) {
  308. /* Unprovisioning failed. Assume the linecard is unprovisioned
  309. * for future operations.
  310. */
  311. mutex_lock(&linecard->state_lock);
  312. linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
  313. linecard->type = NULL;
  314. devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
  315. mutex_unlock(&linecard->state_lock);
  316. }
  317. return err;
  318. out:
  319. mutex_unlock(&linecard->state_lock);
  320. return err;
  321. }
  322. int devlink_nl_linecard_set_doit(struct sk_buff *skb, struct genl_info *info)
  323. {
  324. struct netlink_ext_ack *extack = info->extack;
  325. struct devlink *devlink = info->user_ptr[0];
  326. struct devlink_linecard *linecard;
  327. int err;
  328. linecard = devlink_linecard_get_from_info(devlink, info);
  329. if (IS_ERR(linecard))
  330. return PTR_ERR(linecard);
  331. if (info->attrs[DEVLINK_ATTR_LINECARD_TYPE]) {
  332. const char *type;
  333. type = nla_data(info->attrs[DEVLINK_ATTR_LINECARD_TYPE]);
  334. if (strcmp(type, "")) {
  335. err = devlink_linecard_type_set(linecard, type, extack);
  336. if (err)
  337. return err;
  338. } else {
  339. err = devlink_linecard_type_unset(linecard, extack);
  340. if (err)
  341. return err;
  342. }
  343. }
  344. return 0;
  345. }
  346. static int devlink_linecard_types_init(struct devlink_linecard *linecard)
  347. {
  348. struct devlink_linecard_type *linecard_type;
  349. unsigned int count;
  350. int i;
  351. count = linecard->ops->types_count(linecard, linecard->priv);
  352. linecard->types = kmalloc_array(count, sizeof(*linecard_type),
  353. GFP_KERNEL);
  354. if (!linecard->types)
  355. return -ENOMEM;
  356. linecard->types_count = count;
  357. for (i = 0; i < count; i++) {
  358. linecard_type = &linecard->types[i];
  359. linecard->ops->types_get(linecard, linecard->priv, i,
  360. &linecard_type->type,
  361. &linecard_type->priv);
  362. }
  363. return 0;
  364. }
  365. static void devlink_linecard_types_fini(struct devlink_linecard *linecard)
  366. {
  367. kfree(linecard->types);
  368. }
  369. /**
  370. * devl_linecard_create - Create devlink linecard
  371. *
  372. * @devlink: devlink
  373. * @linecard_index: driver-specific numerical identifier of the linecard
  374. * @ops: linecards ops
  375. * @priv: user priv pointer
  376. *
  377. * Create devlink linecard instance with provided linecard index.
  378. * Caller can use any indexing, even hw-related one.
  379. *
  380. * Return: Line card structure or an ERR_PTR() encoded error code.
  381. */
  382. struct devlink_linecard *
  383. devl_linecard_create(struct devlink *devlink, unsigned int linecard_index,
  384. const struct devlink_linecard_ops *ops, void *priv)
  385. {
  386. struct devlink_linecard *linecard;
  387. int err;
  388. if (WARN_ON(!ops || !ops->provision || !ops->unprovision ||
  389. !ops->types_count || !ops->types_get))
  390. return ERR_PTR(-EINVAL);
  391. if (devlink_linecard_index_exists(devlink, linecard_index))
  392. return ERR_PTR(-EEXIST);
  393. linecard = kzalloc(sizeof(*linecard), GFP_KERNEL);
  394. if (!linecard)
  395. return ERR_PTR(-ENOMEM);
  396. linecard->devlink = devlink;
  397. linecard->index = linecard_index;
  398. linecard->ops = ops;
  399. linecard->priv = priv;
  400. linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
  401. mutex_init(&linecard->state_lock);
  402. err = devlink_linecard_types_init(linecard);
  403. if (err) {
  404. mutex_destroy(&linecard->state_lock);
  405. kfree(linecard);
  406. return ERR_PTR(err);
  407. }
  408. list_add_tail(&linecard->list, &devlink->linecard_list);
  409. devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
  410. return linecard;
  411. }
  412. EXPORT_SYMBOL_GPL(devl_linecard_create);
  413. /**
  414. * devl_linecard_destroy - Destroy devlink linecard
  415. *
  416. * @linecard: devlink linecard
  417. */
  418. void devl_linecard_destroy(struct devlink_linecard *linecard)
  419. {
  420. devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL);
  421. list_del(&linecard->list);
  422. devlink_linecard_types_fini(linecard);
  423. mutex_destroy(&linecard->state_lock);
  424. kfree(linecard);
  425. }
  426. EXPORT_SYMBOL_GPL(devl_linecard_destroy);
  427. /**
  428. * devlink_linecard_provision_set - Set provisioning on linecard
  429. *
  430. * @linecard: devlink linecard
  431. * @type: linecard type
  432. *
  433. * This is either called directly from the provision() op call or
  434. * as a result of the provision() op call asynchronously.
  435. */
  436. void devlink_linecard_provision_set(struct devlink_linecard *linecard,
  437. const char *type)
  438. {
  439. mutex_lock(&linecard->state_lock);
  440. WARN_ON(linecard->type && strcmp(linecard->type, type));
  441. linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED;
  442. linecard->type = type;
  443. devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
  444. mutex_unlock(&linecard->state_lock);
  445. }
  446. EXPORT_SYMBOL_GPL(devlink_linecard_provision_set);
  447. /**
  448. * devlink_linecard_provision_clear - Clear provisioning on linecard
  449. *
  450. * @linecard: devlink linecard
  451. *
  452. * This is either called directly from the unprovision() op call or
  453. * as a result of the unprovision() op call asynchronously.
  454. */
  455. void devlink_linecard_provision_clear(struct devlink_linecard *linecard)
  456. {
  457. mutex_lock(&linecard->state_lock);
  458. linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED;
  459. linecard->type = NULL;
  460. devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
  461. mutex_unlock(&linecard->state_lock);
  462. }
  463. EXPORT_SYMBOL_GPL(devlink_linecard_provision_clear);
  464. /**
  465. * devlink_linecard_provision_fail - Fail provisioning on linecard
  466. *
  467. * @linecard: devlink linecard
  468. *
  469. * This is either called directly from the provision() op call or
  470. * as a result of the provision() op call asynchronously.
  471. */
  472. void devlink_linecard_provision_fail(struct devlink_linecard *linecard)
  473. {
  474. mutex_lock(&linecard->state_lock);
  475. linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING_FAILED;
  476. devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
  477. mutex_unlock(&linecard->state_lock);
  478. }
  479. EXPORT_SYMBOL_GPL(devlink_linecard_provision_fail);
  480. /**
  481. * devlink_linecard_activate - Set linecard active
  482. *
  483. * @linecard: devlink linecard
  484. */
  485. void devlink_linecard_activate(struct devlink_linecard *linecard)
  486. {
  487. mutex_lock(&linecard->state_lock);
  488. WARN_ON(linecard->state != DEVLINK_LINECARD_STATE_PROVISIONED);
  489. linecard->state = DEVLINK_LINECARD_STATE_ACTIVE;
  490. devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
  491. mutex_unlock(&linecard->state_lock);
  492. }
  493. EXPORT_SYMBOL_GPL(devlink_linecard_activate);
  494. /**
  495. * devlink_linecard_deactivate - Set linecard inactive
  496. *
  497. * @linecard: devlink linecard
  498. */
  499. void devlink_linecard_deactivate(struct devlink_linecard *linecard)
  500. {
  501. mutex_lock(&linecard->state_lock);
  502. switch (linecard->state) {
  503. case DEVLINK_LINECARD_STATE_ACTIVE:
  504. linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED;
  505. devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
  506. break;
  507. case DEVLINK_LINECARD_STATE_UNPROVISIONING:
  508. /* Line card is being deactivated as part
  509. * of unprovisioning flow.
  510. */
  511. break;
  512. default:
  513. WARN_ON(1);
  514. break;
  515. }
  516. mutex_unlock(&linecard->state_lock);
  517. }
  518. EXPORT_SYMBOL_GPL(devlink_linecard_deactivate);
  519. static void devlink_linecard_rel_notify_cb(struct devlink *devlink,
  520. u32 linecard_index)
  521. {
  522. struct devlink_linecard *linecard;
  523. linecard = devlink_linecard_get_by_index(devlink, linecard_index);
  524. if (!linecard)
  525. return;
  526. devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW);
  527. }
  528. static void devlink_linecard_rel_cleanup_cb(struct devlink *devlink,
  529. u32 linecard_index, u32 rel_index)
  530. {
  531. struct devlink_linecard *linecard;
  532. linecard = devlink_linecard_get_by_index(devlink, linecard_index);
  533. if (linecard && linecard->rel_index == rel_index)
  534. linecard->rel_index = 0;
  535. }
  536. /**
  537. * devlink_linecard_nested_dl_set - Attach/detach nested devlink
  538. * instance to linecard.
  539. *
  540. * @linecard: devlink linecard
  541. * @nested_devlink: devlink instance to attach or NULL to detach
  542. */
  543. int devlink_linecard_nested_dl_set(struct devlink_linecard *linecard,
  544. struct devlink *nested_devlink)
  545. {
  546. return devlink_rel_nested_in_add(&linecard->rel_index,
  547. linecard->devlink->index,
  548. linecard->index,
  549. devlink_linecard_rel_notify_cb,
  550. devlink_linecard_rel_cleanup_cb,
  551. nested_devlink);
  552. }
  553. EXPORT_SYMBOL_GPL(devlink_linecard_nested_dl_set);