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
bnge_dl_info_put(struct bnge_dev * bd,struct devlink_info_req * req,enum bnge_dl_version_type type,const char * key,char * buf)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
bnge_vpd_read_info(struct bnge_dev * bd)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
bnge_devlink_info_get(struct devlink * devlink,struct devlink_info_req * req,struct netlink_ext_ack * extack)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
bnge_devlink_free(struct bnge_dev * bd)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
bnge_devlink_alloc(struct pci_dev * pdev)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
bnge_devlink_register(struct bnge_dev * bd)296 void bnge_devlink_register(struct bnge_dev *bd)
297 {
298 struct devlink *devlink = priv_to_devlink(bd);
299 devlink_register(devlink);
300 }
301
bnge_devlink_unregister(struct bnge_dev * bd)302 void bnge_devlink_unregister(struct bnge_dev *bd)
303 {
304 struct devlink *devlink = priv_to_devlink(bd);
305 devlink_unregister(devlink);
306 }
307