xref: /linux/drivers/net/ethernet/broadcom/bnge/bnge_devlink.c (revision 8be4d31cb8aaeea27bde4b7ddb26e28a89062ebf)
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