// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) Meta Platforms, Inc. and affiliates. */ #include #include #include #include #include "fbnic.h" #define FBNIC_SN_STR_LEN 24 static int fbnic_version_running_put(struct devlink_info_req *req, struct fbnic_fw_ver *fw_ver, char *ver_name) { char running_ver[FBNIC_FW_VER_MAX_SIZE]; int err; fbnic_mk_fw_ver_str(fw_ver->version, running_ver); err = devlink_info_version_running_put(req, ver_name, running_ver); if (err) return err; if (strlen(fw_ver->commit) > 0) { char commit_name[FBNIC_SN_STR_LEN]; snprintf(commit_name, FBNIC_SN_STR_LEN, "%s.commit", ver_name); err = devlink_info_version_running_put(req, commit_name, fw_ver->commit); if (err) return err; } return 0; } static int fbnic_version_stored_put(struct devlink_info_req *req, struct fbnic_fw_ver *fw_ver, char *ver_name) { char stored_ver[FBNIC_FW_VER_MAX_SIZE]; int err; fbnic_mk_fw_ver_str(fw_ver->version, stored_ver); err = devlink_info_version_stored_put(req, ver_name, stored_ver); if (err) return err; if (strlen(fw_ver->commit) > 0) { char commit_name[FBNIC_SN_STR_LEN]; snprintf(commit_name, FBNIC_SN_STR_LEN, "%s.commit", ver_name); err = devlink_info_version_stored_put(req, commit_name, fw_ver->commit); if (err) return err; } return 0; } static int fbnic_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, struct netlink_ext_ack *extack) { struct fbnic_dev *fbd = devlink_priv(devlink); int err; err = fbnic_version_running_put(req, &fbd->fw_cap.running.mgmt, DEVLINK_INFO_VERSION_GENERIC_FW); if (err) return err; err = fbnic_version_running_put(req, &fbd->fw_cap.running.bootloader, DEVLINK_INFO_VERSION_GENERIC_FW_BOOTLOADER); if (err) return err; err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.mgmt, DEVLINK_INFO_VERSION_GENERIC_FW); if (err) return err; err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.bootloader, DEVLINK_INFO_VERSION_GENERIC_FW_BOOTLOADER); if (err) return err; err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.undi, DEVLINK_INFO_VERSION_GENERIC_FW_UNDI); if (err) return err; if (fbd->dsn) { unsigned char serial[FBNIC_SN_STR_LEN]; u8 dsn[8]; put_unaligned_be64(fbd->dsn, dsn); err = snprintf(serial, FBNIC_SN_STR_LEN, "%8phD", dsn); if (err < 0) return err; err = devlink_info_serial_number_put(req, serial); if (err) return err; } return 0; } static const struct devlink_ops fbnic_devlink_ops = { .info_get = fbnic_devlink_info_get, }; void fbnic_devlink_free(struct fbnic_dev *fbd) { struct devlink *devlink = priv_to_devlink(fbd); devlink_free(devlink); } struct fbnic_dev *fbnic_devlink_alloc(struct pci_dev *pdev) { void __iomem * const *iomap_table; struct devlink *devlink; struct fbnic_dev *fbd; devlink = devlink_alloc(&fbnic_devlink_ops, sizeof(struct fbnic_dev), &pdev->dev); if (!devlink) return NULL; fbd = devlink_priv(devlink); pci_set_drvdata(pdev, fbd); fbd->dev = &pdev->dev; iomap_table = pcim_iomap_table(pdev); fbd->uc_addr0 = iomap_table[0]; fbd->uc_addr4 = iomap_table[4]; fbd->dsn = pci_get_dsn(pdev); fbd->mps = pcie_get_mps(pdev); fbd->readrq = pcie_get_readrq(pdev); fbd->mac_addr_boundary = FBNIC_RPC_TCAM_MACDA_DEFAULT_BOUNDARY; return fbd; } void fbnic_devlink_register(struct fbnic_dev *fbd) { struct devlink *devlink = priv_to_devlink(fbd); devlink_register(devlink); } void fbnic_devlink_unregister(struct fbnic_dev *fbd) { struct devlink *devlink = priv_to_devlink(fbd); devlink_unregister(devlink); }