1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) Meta Platforms, Inc. and affiliates. */ 3 4 #include <linux/unaligned.h> 5 #include <linux/pci.h> 6 #include <linux/types.h> 7 #include <net/devlink.h> 8 9 #include "fbnic.h" 10 11 #define FBNIC_SN_STR_LEN 24 12 13 static int fbnic_version_running_put(struct devlink_info_req *req, 14 struct fbnic_fw_ver *fw_ver, 15 char *ver_name) 16 { 17 char running_ver[FBNIC_FW_VER_MAX_SIZE]; 18 int err; 19 20 fbnic_mk_fw_ver_str(fw_ver->version, running_ver); 21 err = devlink_info_version_running_put(req, ver_name, running_ver); 22 if (err) 23 return err; 24 25 if (strlen(fw_ver->commit) > 0) { 26 char commit_name[FBNIC_SN_STR_LEN]; 27 28 snprintf(commit_name, FBNIC_SN_STR_LEN, "%s.commit", ver_name); 29 err = devlink_info_version_running_put(req, commit_name, 30 fw_ver->commit); 31 if (err) 32 return err; 33 } 34 35 return 0; 36 } 37 38 static int fbnic_version_stored_put(struct devlink_info_req *req, 39 struct fbnic_fw_ver *fw_ver, 40 char *ver_name) 41 { 42 char stored_ver[FBNIC_FW_VER_MAX_SIZE]; 43 int err; 44 45 fbnic_mk_fw_ver_str(fw_ver->version, stored_ver); 46 err = devlink_info_version_stored_put(req, ver_name, stored_ver); 47 if (err) 48 return err; 49 50 if (strlen(fw_ver->commit) > 0) { 51 char commit_name[FBNIC_SN_STR_LEN]; 52 53 snprintf(commit_name, FBNIC_SN_STR_LEN, "%s.commit", ver_name); 54 err = devlink_info_version_stored_put(req, commit_name, 55 fw_ver->commit); 56 if (err) 57 return err; 58 } 59 60 return 0; 61 } 62 63 static int fbnic_devlink_info_get(struct devlink *devlink, 64 struct devlink_info_req *req, 65 struct netlink_ext_ack *extack) 66 { 67 struct fbnic_dev *fbd = devlink_priv(devlink); 68 int err; 69 70 err = fbnic_version_running_put(req, &fbd->fw_cap.running.mgmt, 71 DEVLINK_INFO_VERSION_GENERIC_FW); 72 if (err) 73 return err; 74 75 err = fbnic_version_running_put(req, &fbd->fw_cap.running.bootloader, 76 DEVLINK_INFO_VERSION_GENERIC_FW_BOOTLOADER); 77 if (err) 78 return err; 79 80 err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.mgmt, 81 DEVLINK_INFO_VERSION_GENERIC_FW); 82 if (err) 83 return err; 84 85 err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.bootloader, 86 DEVLINK_INFO_VERSION_GENERIC_FW_BOOTLOADER); 87 if (err) 88 return err; 89 90 err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.undi, 91 DEVLINK_INFO_VERSION_GENERIC_FW_UNDI); 92 if (err) 93 return err; 94 95 if (fbd->dsn) { 96 unsigned char serial[FBNIC_SN_STR_LEN]; 97 u8 dsn[8]; 98 99 put_unaligned_be64(fbd->dsn, dsn); 100 err = snprintf(serial, FBNIC_SN_STR_LEN, "%8phD", dsn); 101 if (err < 0) 102 return err; 103 104 err = devlink_info_serial_number_put(req, serial); 105 if (err) 106 return err; 107 } 108 109 return 0; 110 } 111 112 static const struct devlink_ops fbnic_devlink_ops = { 113 .info_get = fbnic_devlink_info_get, 114 }; 115 116 void fbnic_devlink_free(struct fbnic_dev *fbd) 117 { 118 struct devlink *devlink = priv_to_devlink(fbd); 119 120 devlink_free(devlink); 121 } 122 123 struct fbnic_dev *fbnic_devlink_alloc(struct pci_dev *pdev) 124 { 125 void __iomem * const *iomap_table; 126 struct devlink *devlink; 127 struct fbnic_dev *fbd; 128 129 devlink = devlink_alloc(&fbnic_devlink_ops, sizeof(struct fbnic_dev), 130 &pdev->dev); 131 if (!devlink) 132 return NULL; 133 134 fbd = devlink_priv(devlink); 135 pci_set_drvdata(pdev, fbd); 136 fbd->dev = &pdev->dev; 137 138 iomap_table = pcim_iomap_table(pdev); 139 fbd->uc_addr0 = iomap_table[0]; 140 fbd->uc_addr4 = iomap_table[4]; 141 142 fbd->dsn = pci_get_dsn(pdev); 143 fbd->mps = pcie_get_mps(pdev); 144 fbd->readrq = pcie_get_readrq(pdev); 145 146 fbd->mac_addr_boundary = FBNIC_RPC_TCAM_MACDA_DEFAULT_BOUNDARY; 147 148 return fbd; 149 } 150 151 void fbnic_devlink_register(struct fbnic_dev *fbd) 152 { 153 struct devlink *devlink = priv_to_devlink(fbd); 154 155 devlink_register(devlink); 156 } 157 158 void fbnic_devlink_unregister(struct fbnic_dev *fbd) 159 { 160 struct devlink *devlink = priv_to_devlink(fbd); 161 162 devlink_unregister(devlink); 163 } 164