fbnic_devlink.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. // SPDX-License-Identifier: GPL-2.0
  2. /* Copyright (c) Meta Platforms, Inc. and affiliates. */
  3. #include <linux/unaligned.h>
  4. #include <linux/pci.h>
  5. #include <linux/pldmfw.h>
  6. #include <linux/types.h>
  7. #include <net/devlink.h>
  8. #include "fbnic.h"
  9. #include "fbnic_fw.h"
  10. #include "fbnic_tlv.h"
  11. #define FBNIC_SN_STR_LEN 24
  12. static int fbnic_version_running_put(struct devlink_info_req *req,
  13. struct fbnic_fw_ver *fw_ver,
  14. char *ver_name)
  15. {
  16. char running_ver[FBNIC_FW_VER_MAX_SIZE];
  17. int err;
  18. fbnic_mk_fw_ver_str(fw_ver->version, running_ver);
  19. err = devlink_info_version_running_put(req, ver_name, running_ver);
  20. if (err)
  21. return err;
  22. if (strlen(fw_ver->commit) > 0) {
  23. char commit_name[FBNIC_SN_STR_LEN];
  24. snprintf(commit_name, FBNIC_SN_STR_LEN, "%s.commit", ver_name);
  25. err = devlink_info_version_running_put(req, commit_name,
  26. fw_ver->commit);
  27. if (err)
  28. return err;
  29. }
  30. return 0;
  31. }
  32. static int fbnic_version_stored_put(struct devlink_info_req *req,
  33. struct fbnic_fw_ver *fw_ver,
  34. char *ver_name)
  35. {
  36. char stored_ver[FBNIC_FW_VER_MAX_SIZE];
  37. int err;
  38. fbnic_mk_fw_ver_str(fw_ver->version, stored_ver);
  39. err = devlink_info_version_stored_put(req, ver_name, stored_ver);
  40. if (err)
  41. return err;
  42. if (strlen(fw_ver->commit) > 0) {
  43. char commit_name[FBNIC_SN_STR_LEN];
  44. snprintf(commit_name, FBNIC_SN_STR_LEN, "%s.commit", ver_name);
  45. err = devlink_info_version_stored_put(req, commit_name,
  46. fw_ver->commit);
  47. if (err)
  48. return err;
  49. }
  50. return 0;
  51. }
  52. static int fbnic_devlink_info_get(struct devlink *devlink,
  53. struct devlink_info_req *req,
  54. struct netlink_ext_ack *extack)
  55. {
  56. struct fbnic_dev *fbd = devlink_priv(devlink);
  57. int err;
  58. err = fbnic_version_running_put(req, &fbd->fw_cap.running.mgmt,
  59. DEVLINK_INFO_VERSION_GENERIC_FW);
  60. if (err)
  61. return err;
  62. err = fbnic_version_running_put(req, &fbd->fw_cap.running.bootloader,
  63. DEVLINK_INFO_VERSION_GENERIC_FW_BOOTLOADER);
  64. if (err)
  65. return err;
  66. err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.mgmt,
  67. DEVLINK_INFO_VERSION_GENERIC_FW);
  68. if (err)
  69. return err;
  70. err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.bootloader,
  71. DEVLINK_INFO_VERSION_GENERIC_FW_BOOTLOADER);
  72. if (err)
  73. return err;
  74. err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.undi,
  75. DEVLINK_INFO_VERSION_GENERIC_FW_UNDI);
  76. if (err)
  77. return err;
  78. if (fbd->dsn) {
  79. unsigned char serial[FBNIC_SN_STR_LEN];
  80. u8 dsn[8];
  81. put_unaligned_be64(fbd->dsn, dsn);
  82. err = snprintf(serial, FBNIC_SN_STR_LEN, "%8phD", dsn);
  83. if (err < 0)
  84. return err;
  85. err = devlink_info_serial_number_put(req, serial);
  86. if (err)
  87. return err;
  88. }
  89. return 0;
  90. }
  91. static bool
  92. fbnic_pldm_match_record(struct pldmfw *context, struct pldmfw_record *record)
  93. {
  94. struct pldmfw_desc_tlv *desc;
  95. u32 anti_rollback_ver = 0;
  96. struct devlink *devlink;
  97. struct fbnic_dev *fbd;
  98. struct pci_dev *pdev;
  99. /* First, use the standard PCI matching function */
  100. if (!pldmfw_op_pci_match_record(context, record))
  101. return false;
  102. pdev = to_pci_dev(context->dev);
  103. fbd = pci_get_drvdata(pdev);
  104. devlink = priv_to_devlink(fbd);
  105. /* If PCI match is successful, check for vendor-specific descriptors */
  106. list_for_each_entry(desc, &record->descs, entry) {
  107. if (desc->type != PLDM_DESC_ID_VENDOR_DEFINED)
  108. continue;
  109. if (desc->size < 21 || desc->data[0] != 1 ||
  110. desc->data[1] != 15)
  111. continue;
  112. if (memcmp(desc->data + 2, "AntiRollbackVer", 15) != 0)
  113. continue;
  114. anti_rollback_ver = get_unaligned_le32(desc->data + 17);
  115. break;
  116. }
  117. /* Compare versions and return error if they do not match */
  118. if (anti_rollback_ver < fbd->fw_cap.anti_rollback_version) {
  119. char buf[128];
  120. snprintf(buf, sizeof(buf),
  121. "New firmware anti-rollback version (0x%x) is older than device version (0x%x)!",
  122. anti_rollback_ver, fbd->fw_cap.anti_rollback_version);
  123. devlink_flash_update_status_notify(devlink, buf,
  124. "Anti-Rollback", 0, 0);
  125. return false;
  126. }
  127. return true;
  128. }
  129. static int
  130. fbnic_flash_start(struct fbnic_dev *fbd, struct pldmfw_component *component)
  131. {
  132. struct fbnic_fw_completion *cmpl;
  133. int err;
  134. cmpl = fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_FW_START_UPGRADE_REQ);
  135. if (!cmpl)
  136. return -ENOMEM;
  137. err = fbnic_fw_xmit_fw_start_upgrade(fbd, cmpl,
  138. component->identifier,
  139. component->component_size);
  140. if (err)
  141. goto cmpl_free;
  142. /* Wait for firmware to ack firmware upgrade start */
  143. if (fbnic_mbx_wait_for_cmpl(cmpl))
  144. err = cmpl->result;
  145. else
  146. err = -ETIMEDOUT;
  147. fbnic_mbx_clear_cmpl(fbd, cmpl);
  148. cmpl_free:
  149. fbnic_fw_put_cmpl(cmpl);
  150. return err;
  151. }
  152. static int
  153. fbnic_flash_component(struct pldmfw *context,
  154. struct pldmfw_component *component)
  155. {
  156. const u8 *data = component->component_data;
  157. const u32 size = component->component_size;
  158. struct fbnic_fw_completion *cmpl;
  159. const char *component_name;
  160. struct devlink *devlink;
  161. struct fbnic_dev *fbd;
  162. struct pci_dev *pdev;
  163. u32 offset = 0;
  164. u32 length = 0;
  165. char buf[32];
  166. int err;
  167. pdev = to_pci_dev(context->dev);
  168. fbd = pci_get_drvdata(pdev);
  169. devlink = priv_to_devlink(fbd);
  170. switch (component->identifier) {
  171. case QSPI_SECTION_CMRT:
  172. component_name = "boot1";
  173. break;
  174. case QSPI_SECTION_CONTROL_FW:
  175. component_name = "boot2";
  176. break;
  177. case QSPI_SECTION_OPTION_ROM:
  178. component_name = "option-rom";
  179. break;
  180. default:
  181. snprintf(buf, sizeof(buf), "Unknown component ID %u!",
  182. component->identifier);
  183. devlink_flash_update_status_notify(devlink, buf, NULL, 0,
  184. size);
  185. return -EINVAL;
  186. }
  187. /* Once firmware receives the request to start upgrading it responds
  188. * with two messages:
  189. * 1. An ACK that it received the message and possible error code
  190. * indicating that an upgrade is not currently possible.
  191. * 2. A request for the first chunk of data
  192. *
  193. * Setup completions for write before issuing the start message so
  194. * the driver can catch both messages.
  195. */
  196. cmpl = fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_FW_WRITE_CHUNK_REQ);
  197. if (!cmpl)
  198. return -ENOMEM;
  199. err = fbnic_mbx_set_cmpl(fbd, cmpl);
  200. if (err)
  201. goto cmpl_free;
  202. devlink_flash_update_timeout_notify(devlink, "Initializing",
  203. component_name, 15);
  204. err = fbnic_flash_start(fbd, component);
  205. if (err)
  206. goto err_no_msg;
  207. while (offset < size) {
  208. if (!fbnic_mbx_wait_for_cmpl(cmpl)) {
  209. err = -ETIMEDOUT;
  210. break;
  211. }
  212. err = cmpl->result;
  213. if (err)
  214. break;
  215. /* Verify firmware is requesting the next chunk in the seq. */
  216. if (cmpl->u.fw_update.offset != offset + length) {
  217. err = -EFAULT;
  218. break;
  219. }
  220. offset = cmpl->u.fw_update.offset;
  221. length = cmpl->u.fw_update.length;
  222. if (length > TLV_MAX_DATA || offset + length > size) {
  223. err = -EFAULT;
  224. break;
  225. }
  226. devlink_flash_update_status_notify(devlink, "Flashing",
  227. component_name,
  228. offset, size);
  229. /* Mailbox will set length to 0 once it receives the finish
  230. * message.
  231. */
  232. if (!length)
  233. continue;
  234. reinit_completion(&cmpl->done);
  235. err = fbnic_fw_xmit_fw_write_chunk(fbd, data, offset, length,
  236. 0);
  237. if (err)
  238. break;
  239. }
  240. if (err) {
  241. fbnic_fw_xmit_fw_write_chunk(fbd, NULL, 0, 0, err);
  242. err_no_msg:
  243. snprintf(buf, sizeof(buf), "Mailbox encountered error %d!",
  244. err);
  245. devlink_flash_update_status_notify(devlink, buf,
  246. component_name, 0, 0);
  247. }
  248. fbnic_mbx_clear_cmpl(fbd, cmpl);
  249. cmpl_free:
  250. fbnic_fw_put_cmpl(cmpl);
  251. return err;
  252. }
  253. static const struct pldmfw_ops fbnic_pldmfw_ops = {
  254. .match_record = fbnic_pldm_match_record,
  255. .flash_component = fbnic_flash_component,
  256. };
  257. static int
  258. fbnic_devlink_flash_update(struct devlink *devlink,
  259. struct devlink_flash_update_params *params,
  260. struct netlink_ext_ack *extack)
  261. {
  262. struct fbnic_dev *fbd = devlink_priv(devlink);
  263. const struct firmware *fw = params->fw;
  264. struct device *dev = fbd->dev;
  265. struct pldmfw context;
  266. char *err_msg;
  267. int err;
  268. context.ops = &fbnic_pldmfw_ops;
  269. context.dev = dev;
  270. err = pldmfw_flash_image(&context, fw);
  271. if (err) {
  272. switch (err) {
  273. case -EINVAL:
  274. err_msg = "Invalid image";
  275. break;
  276. case -EOPNOTSUPP:
  277. err_msg = "Unsupported image";
  278. break;
  279. case -ENOMEM:
  280. err_msg = "Out of memory";
  281. break;
  282. case -EFAULT:
  283. err_msg = "Invalid header";
  284. break;
  285. case -ENOENT:
  286. err_msg = "No matching record";
  287. break;
  288. case -ENODEV:
  289. err_msg = "No matching device";
  290. break;
  291. case -ETIMEDOUT:
  292. err_msg = "Timed out waiting for reply";
  293. break;
  294. default:
  295. err_msg = "Unknown error";
  296. break;
  297. }
  298. NL_SET_ERR_MSG_FMT_MOD(extack,
  299. "Failed to flash PLDM Image: %s (error: %d)",
  300. err_msg, err);
  301. }
  302. return err;
  303. }
  304. static const struct devlink_ops fbnic_devlink_ops = {
  305. .info_get = fbnic_devlink_info_get,
  306. .flash_update = fbnic_devlink_flash_update,
  307. };
  308. static int fbnic_fw_reporter_dump(struct devlink_health_reporter *reporter,
  309. struct devlink_fmsg *fmsg, void *priv_ctx,
  310. struct netlink_ext_ack *extack)
  311. {
  312. struct fbnic_dev *fbd = devlink_health_reporter_priv(reporter);
  313. u32 offset, index, index_count, length, size;
  314. struct fbnic_fw_completion *fw_cmpl;
  315. u8 *dump_data, **data;
  316. int err;
  317. fw_cmpl = fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_COREDUMP_GET_INFO_RESP);
  318. if (!fw_cmpl)
  319. return -ENOMEM;
  320. err = fbnic_fw_xmit_coredump_info_msg(fbd, fw_cmpl, true);
  321. if (err) {
  322. NL_SET_ERR_MSG_MOD(extack,
  323. "Failed to transmit core dump info msg");
  324. goto cmpl_free;
  325. }
  326. if (!fbnic_mbx_wait_for_cmpl(fw_cmpl)) {
  327. NL_SET_ERR_MSG_MOD(extack,
  328. "Timed out waiting on core dump info");
  329. err = -ETIMEDOUT;
  330. goto cmpl_cleanup;
  331. }
  332. size = fw_cmpl->u.coredump_info.size;
  333. err = fw_cmpl->result;
  334. fbnic_mbx_clear_cmpl(fbd, fw_cmpl);
  335. fbnic_fw_put_cmpl(fw_cmpl);
  336. /* Handle error returned by firmware */
  337. if (err) {
  338. NL_SET_ERR_MSG_MOD(extack, "Firmware core dump returned error");
  339. return err;
  340. }
  341. if (!size) {
  342. NL_SET_ERR_MSG_MOD(extack,
  343. "Firmware core dump returned size 0");
  344. return -EIO;
  345. }
  346. /* Read the dump, we can only transfer TLV_MAX_DATA at a time */
  347. index_count = DIV_ROUND_UP(size, TLV_MAX_DATA);
  348. fw_cmpl = __fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_COREDUMP_READ_RESP,
  349. sizeof(void *) * index_count + size);
  350. if (!fw_cmpl)
  351. return -ENOMEM;
  352. /* Populate pointer table w/ pointer offsets */
  353. dump_data = (void *)&fw_cmpl->u.coredump.data[index_count];
  354. data = fw_cmpl->u.coredump.data;
  355. fw_cmpl->u.coredump.size = size;
  356. fw_cmpl->u.coredump.stride = TLV_MAX_DATA;
  357. for (index = 0; index < index_count; index++) {
  358. /* First iteration installs completion */
  359. struct fbnic_fw_completion *cmpl_arg = index ? NULL : fw_cmpl;
  360. offset = index * TLV_MAX_DATA;
  361. length = min(size - offset, TLV_MAX_DATA);
  362. data[index] = dump_data + offset;
  363. err = fbnic_fw_xmit_coredump_read_msg(fbd, cmpl_arg,
  364. offset, length);
  365. if (err) {
  366. NL_SET_ERR_MSG_MOD(extack,
  367. "Failed to transmit core dump msg");
  368. if (cmpl_arg)
  369. goto cmpl_free;
  370. else
  371. goto cmpl_cleanup;
  372. }
  373. if (fbnic_mbx_wait_for_cmpl(fw_cmpl)) {
  374. reinit_completion(&fw_cmpl->done);
  375. } else {
  376. NL_SET_ERR_MSG_FMT_MOD(extack,
  377. "Timed out waiting on core dump (%d/%d)",
  378. index + 1, index_count);
  379. err = -ETIMEDOUT;
  380. goto cmpl_cleanup;
  381. }
  382. /* If we didn't see the reply record as incomplete */
  383. if (fw_cmpl->u.coredump.data[index]) {
  384. NL_SET_ERR_MSG_FMT_MOD(extack,
  385. "No data for core dump chunk (%d/%d)",
  386. index + 1, index_count);
  387. err = -EIO;
  388. goto cmpl_cleanup;
  389. }
  390. }
  391. devlink_fmsg_binary_pair_nest_start(fmsg, "FW coredump");
  392. for (offset = 0; offset < size; offset += length) {
  393. length = min_t(u32, size - offset, TLV_MAX_DATA);
  394. devlink_fmsg_binary_put(fmsg, dump_data + offset, length);
  395. }
  396. devlink_fmsg_binary_pair_nest_end(fmsg);
  397. cmpl_cleanup:
  398. fbnic_mbx_clear_cmpl(fbd, fw_cmpl);
  399. cmpl_free:
  400. fbnic_fw_put_cmpl(fw_cmpl);
  401. return err;
  402. }
  403. static int
  404. fbnic_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
  405. struct devlink_fmsg *fmsg,
  406. struct netlink_ext_ack *extack)
  407. {
  408. struct fbnic_dev *fbd = devlink_health_reporter_priv(reporter);
  409. u32 sec, msec;
  410. /* Device is most likely down, we're not exchanging heartbeats */
  411. if (!fbd->prev_firmware_time)
  412. return 0;
  413. sec = div_u64_rem(fbd->firmware_time, MSEC_PER_SEC, &msec);
  414. devlink_fmsg_pair_nest_start(fmsg, "last_heartbeat");
  415. devlink_fmsg_obj_nest_start(fmsg);
  416. devlink_fmsg_pair_nest_start(fmsg, "fw_uptime");
  417. devlink_fmsg_obj_nest_start(fmsg);
  418. devlink_fmsg_u32_pair_put(fmsg, "sec", sec);
  419. devlink_fmsg_u32_pair_put(fmsg, "msec", msec);
  420. devlink_fmsg_obj_nest_end(fmsg);
  421. devlink_fmsg_pair_nest_end(fmsg);
  422. devlink_fmsg_obj_nest_end(fmsg);
  423. devlink_fmsg_pair_nest_end(fmsg);
  424. return 0;
  425. }
  426. void __printf(2, 3)
  427. fbnic_devlink_fw_report(struct fbnic_dev *fbd, const char *format, ...)
  428. {
  429. char msg[FBNIC_FW_LOG_MAX_SIZE];
  430. va_list args;
  431. va_start(args, format);
  432. vsnprintf(msg, FBNIC_FW_LOG_MAX_SIZE, format, args);
  433. va_end(args);
  434. devlink_health_report(fbd->fw_reporter, msg, fbd);
  435. if (fbnic_fw_log_ready(fbd))
  436. fbnic_fw_log_write(fbd, 0, fbd->firmware_time, msg);
  437. }
  438. static const struct devlink_health_reporter_ops fbnic_fw_ops = {
  439. .name = "fw",
  440. .dump = fbnic_fw_reporter_dump,
  441. .diagnose = fbnic_fw_reporter_diagnose,
  442. };
  443. static u32 fbnic_read_otp_status(struct fbnic_dev *fbd)
  444. {
  445. return fbnic_fw_rd32(fbd, FBNIC_NS_OTP_STATUS);
  446. }
  447. static int
  448. fbnic_otp_reporter_dump(struct devlink_health_reporter *reporter,
  449. struct devlink_fmsg *fmsg, void *priv_ctx,
  450. struct netlink_ext_ack *extack)
  451. {
  452. struct fbnic_dev *fbd = devlink_health_reporter_priv(reporter);
  453. u32 otp_status, otp_write_status, m;
  454. otp_status = fbnic_read_otp_status(fbd);
  455. otp_write_status = fbnic_fw_rd32(fbd, FBNIC_NS_OTP_WRITE_STATUS);
  456. /* Dump OTP status */
  457. devlink_fmsg_pair_nest_start(fmsg, "OTP");
  458. devlink_fmsg_obj_nest_start(fmsg);
  459. devlink_fmsg_u32_pair_put(fmsg, "Status", otp_status);
  460. /* Extract OTP Write Data status */
  461. m = FBNIC_NS_OTP_WRITE_DATA_STATUS_MASK;
  462. devlink_fmsg_u32_pair_put(fmsg, "Data",
  463. FIELD_GET(m, otp_write_status));
  464. /* Extract OTP Write ECC status */
  465. m = FBNIC_NS_OTP_WRITE_ECC_STATUS_MASK;
  466. devlink_fmsg_u32_pair_put(fmsg, "ECC",
  467. FIELD_GET(m, otp_write_status));
  468. devlink_fmsg_obj_nest_end(fmsg);
  469. devlink_fmsg_pair_nest_end(fmsg);
  470. return 0;
  471. }
  472. void fbnic_devlink_otp_check(struct fbnic_dev *fbd, const char *msg)
  473. {
  474. /* Check if there is anything to report */
  475. if (!fbnic_read_otp_status(fbd))
  476. return;
  477. devlink_health_report(fbd->otp_reporter, msg, fbd);
  478. if (fbnic_fw_log_ready(fbd))
  479. fbnic_fw_log_write(fbd, 0, fbd->firmware_time, msg);
  480. }
  481. static const struct devlink_health_reporter_ops fbnic_otp_ops = {
  482. .name = "otp",
  483. .dump = fbnic_otp_reporter_dump,
  484. };
  485. int fbnic_devlink_health_create(struct fbnic_dev *fbd)
  486. {
  487. fbd->fw_reporter = devlink_health_reporter_create(priv_to_devlink(fbd),
  488. &fbnic_fw_ops, fbd);
  489. if (IS_ERR(fbd->fw_reporter)) {
  490. dev_warn(fbd->dev,
  491. "Failed to create FW fault reporter: %pe\n",
  492. fbd->fw_reporter);
  493. return PTR_ERR(fbd->fw_reporter);
  494. }
  495. fbd->otp_reporter = devlink_health_reporter_create(priv_to_devlink(fbd),
  496. &fbnic_otp_ops, fbd);
  497. if (IS_ERR(fbd->otp_reporter)) {
  498. devlink_health_reporter_destroy(fbd->fw_reporter);
  499. dev_warn(fbd->dev,
  500. "Failed to create OTP fault reporter: %pe\n",
  501. fbd->otp_reporter);
  502. return PTR_ERR(fbd->otp_reporter);
  503. }
  504. return 0;
  505. }
  506. void fbnic_devlink_health_destroy(struct fbnic_dev *fbd)
  507. {
  508. devlink_health_reporter_destroy(fbd->otp_reporter);
  509. devlink_health_reporter_destroy(fbd->fw_reporter);
  510. }
  511. void fbnic_devlink_free(struct fbnic_dev *fbd)
  512. {
  513. struct devlink *devlink = priv_to_devlink(fbd);
  514. devlink_free(devlink);
  515. }
  516. struct fbnic_dev *fbnic_devlink_alloc(struct pci_dev *pdev)
  517. {
  518. void __iomem * const *iomap_table;
  519. struct devlink *devlink;
  520. struct fbnic_dev *fbd;
  521. devlink = devlink_alloc(&fbnic_devlink_ops, sizeof(struct fbnic_dev),
  522. &pdev->dev);
  523. if (!devlink)
  524. return NULL;
  525. fbd = devlink_priv(devlink);
  526. pci_set_drvdata(pdev, fbd);
  527. fbd->dev = &pdev->dev;
  528. iomap_table = pcim_iomap_table(pdev);
  529. fbd->uc_addr0 = iomap_table[0];
  530. fbd->uc_addr4 = iomap_table[4];
  531. fbd->dsn = pci_get_dsn(pdev);
  532. fbd->mps = pcie_get_mps(pdev);
  533. fbd->readrq = pcie_get_readrq(pdev);
  534. fbd->mac_addr_boundary = FBNIC_RPC_TCAM_MACDA_DEFAULT_BOUNDARY;
  535. return fbd;
  536. }
  537. void fbnic_devlink_register(struct fbnic_dev *fbd)
  538. {
  539. struct devlink *devlink = priv_to_devlink(fbd);
  540. devlink_register(devlink);
  541. }
  542. void fbnic_devlink_unregister(struct fbnic_dev *fbd)
  543. {
  544. struct devlink *devlink = priv_to_devlink(fbd);
  545. devlink_unregister(devlink);
  546. }