1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (c) 2025 Broadcom. 3 4 #include <linux/unaligned.h> 5 #include <linux/pci.h> 6 #include <linux/types.h> 7 #include <net/devlink.h> 8 9 #include "bnge.h" 10 #include "bnge_devlink.h" 11 #include "bnge_hwrm_lib.h" 12 13 static int bnge_dl_info_put(struct bnge_dev *bd, struct devlink_info_req *req, 14 enum bnge_dl_version_type type, const char *key, 15 char *buf) 16 { 17 if (!strlen(buf)) 18 return 0; 19 20 if (!strcmp(key, DEVLINK_INFO_VERSION_GENERIC_FW_NCSI) || 21 !strcmp(key, DEVLINK_INFO_VERSION_GENERIC_FW_ROCE)) 22 return 0; 23 24 switch (type) { 25 case BNGE_VERSION_FIXED: 26 return devlink_info_version_fixed_put(req, key, buf); 27 case BNGE_VERSION_RUNNING: 28 return devlink_info_version_running_put(req, key, buf); 29 case BNGE_VERSION_STORED: 30 return devlink_info_version_stored_put(req, key, buf); 31 } 32 33 return 0; 34 } 35 36 static void bnge_vpd_read_info(struct bnge_dev *bd) 37 { 38 struct pci_dev *pdev = bd->pdev; 39 unsigned int vpd_size, kw_len; 40 int pos, size; 41 u8 *vpd_data; 42 43 vpd_data = pci_vpd_alloc(pdev, &vpd_size); 44 if (IS_ERR(vpd_data)) { 45 pci_warn(pdev, "Unable to read VPD\n"); 46 return; 47 } 48 49 pos = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size, 50 PCI_VPD_RO_KEYWORD_PARTNO, &kw_len); 51 if (pos < 0) 52 goto read_sn; 53 54 size = min_t(int, kw_len, BNGE_VPD_FLD_LEN - 1); 55 memcpy(bd->board_partno, &vpd_data[pos], size); 56 57 read_sn: 58 pos = pci_vpd_find_ro_info_keyword(vpd_data, vpd_size, 59 PCI_VPD_RO_KEYWORD_SERIALNO, 60 &kw_len); 61 if (pos < 0) 62 goto exit; 63 64 size = min_t(int, kw_len, BNGE_VPD_FLD_LEN - 1); 65 memcpy(bd->board_serialno, &vpd_data[pos], size); 66 67 exit: 68 kfree(vpd_data); 69 } 70 71 #define HWRM_FW_VER_STR_LEN 16 72 73 static int bnge_devlink_info_get(struct devlink *devlink, 74 struct devlink_info_req *req, 75 struct netlink_ext_ack *extack) 76 { 77 struct hwrm_nvm_get_dev_info_output nvm_dev_info; 78 struct bnge_dev *bd = devlink_priv(devlink); 79 struct hwrm_ver_get_output *ver_resp; 80 char mgmt_ver[FW_VER_STR_LEN]; 81 char roce_ver[FW_VER_STR_LEN]; 82 char ncsi_ver[FW_VER_STR_LEN]; 83 char buf[32]; 84 85 int rc; 86 87 if (bd->dsn) { 88 char buf[32]; 89 u8 dsn[8]; 90 int rc; 91 92 put_unaligned_le64(bd->dsn, dsn); 93 sprintf(buf, "%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X", 94 dsn[7], dsn[6], dsn[5], dsn[4], 95 dsn[3], dsn[2], dsn[1], dsn[0]); 96 rc = devlink_info_serial_number_put(req, buf); 97 if (rc) { 98 NL_SET_ERR_MSG_MOD(extack, "Failed to set dsn"); 99 return rc; 100 } 101 } 102 103 if (strlen(bd->board_serialno)) { 104 rc = devlink_info_board_serial_number_put(req, 105 bd->board_serialno); 106 if (rc) { 107 NL_SET_ERR_MSG_MOD(extack, 108 "Failed to set board serial number"); 109 return rc; 110 } 111 } 112 113 rc = bnge_dl_info_put(bd, req, BNGE_VERSION_FIXED, 114 DEVLINK_INFO_VERSION_GENERIC_BOARD_ID, 115 bd->board_partno); 116 if (rc) { 117 NL_SET_ERR_MSG_MOD(extack, "Failed to set board part number"); 118 return rc; 119 } 120 121 /* More information from HWRM ver get command */ 122 sprintf(buf, "%X", bd->chip_num); 123 rc = bnge_dl_info_put(bd, req, BNGE_VERSION_FIXED, 124 DEVLINK_INFO_VERSION_GENERIC_ASIC_ID, buf); 125 if (rc) { 126 NL_SET_ERR_MSG_MOD(extack, "Failed to set asic id"); 127 return rc; 128 } 129 130 ver_resp = &bd->ver_resp; 131 sprintf(buf, "%c%d", 'A' + ver_resp->chip_rev, ver_resp->chip_metal); 132 rc = bnge_dl_info_put(bd, req, BNGE_VERSION_FIXED, 133 DEVLINK_INFO_VERSION_GENERIC_ASIC_REV, buf); 134 if (rc) { 135 NL_SET_ERR_MSG_MOD(extack, "Failed to set asic info"); 136 return rc; 137 } 138 139 rc = bnge_dl_info_put(bd, req, BNGE_VERSION_RUNNING, 140 DEVLINK_INFO_VERSION_GENERIC_FW_PSID, 141 bd->nvm_cfg_ver); 142 if (rc) { 143 NL_SET_ERR_MSG_MOD(extack, "Failed to set firmware version"); 144 return rc; 145 } 146 147 buf[0] = 0; 148 strncat(buf, ver_resp->active_pkg_name, HWRM_FW_VER_STR_LEN); 149 rc = bnge_dl_info_put(bd, req, BNGE_VERSION_RUNNING, 150 DEVLINK_INFO_VERSION_GENERIC_FW, buf); 151 if (rc) { 152 NL_SET_ERR_MSG_MOD(extack, 153 "Failed to set firmware generic version"); 154 return rc; 155 } 156 157 if (ver_resp->flags & VER_GET_RESP_FLAGS_EXT_VER_AVAIL) { 158 snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 159 ver_resp->hwrm_fw_major, ver_resp->hwrm_fw_minor, 160 ver_resp->hwrm_fw_build, ver_resp->hwrm_fw_patch); 161 162 snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 163 ver_resp->mgmt_fw_major, ver_resp->mgmt_fw_minor, 164 ver_resp->mgmt_fw_build, ver_resp->mgmt_fw_patch); 165 166 snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 167 ver_resp->roce_fw_major, ver_resp->roce_fw_minor, 168 ver_resp->roce_fw_build, ver_resp->roce_fw_patch); 169 } else { 170 snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 171 ver_resp->hwrm_fw_maj_8b, ver_resp->hwrm_fw_min_8b, 172 ver_resp->hwrm_fw_bld_8b, ver_resp->hwrm_fw_rsvd_8b); 173 174 snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 175 ver_resp->mgmt_fw_maj_8b, ver_resp->mgmt_fw_min_8b, 176 ver_resp->mgmt_fw_bld_8b, ver_resp->mgmt_fw_rsvd_8b); 177 178 snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 179 ver_resp->roce_fw_maj_8b, ver_resp->roce_fw_min_8b, 180 ver_resp->roce_fw_bld_8b, ver_resp->roce_fw_rsvd_8b); 181 } 182 rc = bnge_dl_info_put(bd, req, BNGE_VERSION_RUNNING, 183 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, mgmt_ver); 184 if (rc) { 185 NL_SET_ERR_MSG_MOD(extack, 186 "Failed to set firmware mgmt version"); 187 return rc; 188 } 189 190 rc = bnge_dl_info_put(bd, req, BNGE_VERSION_RUNNING, 191 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT_API, 192 bd->hwrm_ver_supp); 193 if (rc) { 194 NL_SET_ERR_MSG_MOD(extack, 195 "Failed to set firmware mgmt api version"); 196 return rc; 197 } 198 199 rc = bnge_dl_info_put(bd, req, BNGE_VERSION_RUNNING, 200 DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, ncsi_ver); 201 if (rc) { 202 NL_SET_ERR_MSG_MOD(extack, 203 "Failed to set ncsi firmware version"); 204 return rc; 205 } 206 207 rc = bnge_dl_info_put(bd, req, BNGE_VERSION_RUNNING, 208 DEVLINK_INFO_VERSION_GENERIC_FW_ROCE, roce_ver); 209 if (rc) { 210 NL_SET_ERR_MSG_MOD(extack, "Failed to set roce firmware version"); 211 return rc; 212 } 213 214 rc = bnge_hwrm_nvm_dev_info(bd, &nvm_dev_info); 215 if (!(nvm_dev_info.flags & NVM_GET_DEV_INFO_RESP_FLAGS_FW_VER_VALID)) 216 return 0; 217 218 buf[0] = 0; 219 strncat(buf, nvm_dev_info.pkg_name, HWRM_FW_VER_STR_LEN); 220 rc = bnge_dl_info_put(bd, req, BNGE_VERSION_STORED, 221 DEVLINK_INFO_VERSION_GENERIC_FW, buf); 222 if (rc) { 223 NL_SET_ERR_MSG_MOD(extack, 224 "Failed to set roce firmware version"); 225 return rc; 226 } 227 228 snprintf(mgmt_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 229 nvm_dev_info.hwrm_fw_major, nvm_dev_info.hwrm_fw_minor, 230 nvm_dev_info.hwrm_fw_build, nvm_dev_info.hwrm_fw_patch); 231 rc = bnge_dl_info_put(bd, req, BNGE_VERSION_STORED, 232 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT, mgmt_ver); 233 if (rc) { 234 NL_SET_ERR_MSG_MOD(extack, 235 "Failed to set stored firmware version"); 236 return rc; 237 } 238 239 snprintf(ncsi_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 240 nvm_dev_info.mgmt_fw_major, nvm_dev_info.mgmt_fw_minor, 241 nvm_dev_info.mgmt_fw_build, nvm_dev_info.mgmt_fw_patch); 242 rc = bnge_dl_info_put(bd, req, BNGE_VERSION_STORED, 243 DEVLINK_INFO_VERSION_GENERIC_FW_NCSI, ncsi_ver); 244 if (rc) { 245 NL_SET_ERR_MSG_MOD(extack, 246 "Failed to set stored ncsi firmware version"); 247 return rc; 248 } 249 250 snprintf(roce_ver, FW_VER_STR_LEN, "%d.%d.%d.%d", 251 nvm_dev_info.roce_fw_major, nvm_dev_info.roce_fw_minor, 252 nvm_dev_info.roce_fw_build, nvm_dev_info.roce_fw_patch); 253 rc = bnge_dl_info_put(bd, req, BNGE_VERSION_STORED, 254 DEVLINK_INFO_VERSION_GENERIC_FW_ROCE, roce_ver); 255 if (rc) 256 NL_SET_ERR_MSG_MOD(extack, 257 "Failed to set stored roce firmware version"); 258 259 return rc; 260 } 261 262 static const struct devlink_ops bnge_devlink_ops = { 263 .info_get = bnge_devlink_info_get, 264 }; 265 266 void bnge_devlink_free(struct bnge_dev *bd) 267 { 268 struct devlink *devlink = priv_to_devlink(bd); 269 270 devlink_free(devlink); 271 } 272 273 struct bnge_dev *bnge_devlink_alloc(struct pci_dev *pdev) 274 { 275 struct devlink *devlink; 276 struct bnge_dev *bd; 277 278 devlink = devlink_alloc(&bnge_devlink_ops, sizeof(*bd), &pdev->dev); 279 if (!devlink) 280 return NULL; 281 282 bd = devlink_priv(devlink); 283 pci_set_drvdata(pdev, bd); 284 bd->dev = &pdev->dev; 285 bd->pdev = pdev; 286 287 bd->dsn = pci_get_dsn(pdev); 288 if (!bd->dsn) 289 pci_warn(pdev, "Failed to get DSN\n"); 290 291 bnge_vpd_read_info(bd); 292 293 return bd; 294 } 295 296 void bnge_devlink_register(struct bnge_dev *bd) 297 { 298 struct devlink *devlink = priv_to_devlink(bd); 299 devlink_register(devlink); 300 } 301 302 void bnge_devlink_unregister(struct bnge_dev *bd) 303 { 304 struct devlink *devlink = priv_to_devlink(bd); 305 devlink_unregister(devlink); 306 } 307