File Index
Files and directories
Sign in
FILE

bnge_devlink.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/broadcom/bnge/bnge_devlink.c C
  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
 13static 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
 36static 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
 57read_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
 67exit:
 68	kfree(vpd_data);
 69}
 70
 71#define HWRM_FW_VER_STR_LEN	16
 72
 73static 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
262static const struct devlink_ops bnge_devlink_ops = {
263	.info_get = bnge_devlink_info_get,
264};
265
266void bnge_devlink_free(struct bnge_dev *bd)
267{
268	struct devlink *devlink = priv_to_devlink(bd);
269
270	devlink_free(devlink);
271}
272
273struct 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
296void bnge_devlink_register(struct bnge_dev *bd)
297{
298	struct devlink *devlink = priv_to_devlink(bd);
299	devlink_register(devlink);
300}
301
302void bnge_devlink_unregister(struct bnge_dev *bd)
303{
304	struct devlink *devlink = priv_to_devlink(bd);
305	devlink_unregister(devlink);
306}
~/ Read-only file preview.