xref: /openbmc/linux/drivers/net/ethernet/sfc/efx_devlink.c (revision 14743ddd2495c96caa18e382625c034e49a812e2)
1fa34a514SAlejandro Lucero // SPDX-License-Identifier: GPL-2.0-only
2fa34a514SAlejandro Lucero /****************************************************************************
3fa34a514SAlejandro Lucero  * Driver for AMD network controllers and boards
4fa34a514SAlejandro Lucero  * Copyright (C) 2023, Advanced Micro Devices, Inc.
5fa34a514SAlejandro Lucero  *
6fa34a514SAlejandro Lucero  * This program is free software; you can redistribute it and/or modify it
7fa34a514SAlejandro Lucero  * under the terms of the GNU General Public License version 2 as published
8fa34a514SAlejandro Lucero  * by the Free Software Foundation, incorporated herein by reference.
9fa34a514SAlejandro Lucero  */
10fa34a514SAlejandro Lucero 
11fa34a514SAlejandro Lucero #include "net_driver.h"
12fa34a514SAlejandro Lucero #include "efx_devlink.h"
13*14743dddSAlejandro Lucero #include <linux/rtc.h>
14*14743dddSAlejandro Lucero #include "mcdi.h"
15*14743dddSAlejandro Lucero #include "mcdi_functions.h"
16*14743dddSAlejandro Lucero #include "mcdi_pcol.h"
17fa34a514SAlejandro Lucero 
18fa34a514SAlejandro Lucero struct efx_devlink {
19fa34a514SAlejandro Lucero 	struct efx_nic *efx;
20fa34a514SAlejandro Lucero };
21fa34a514SAlejandro Lucero 
22*14743dddSAlejandro Lucero static int efx_devlink_info_nvram_partition(struct efx_nic *efx,
23*14743dddSAlejandro Lucero 					    struct devlink_info_req *req,
24*14743dddSAlejandro Lucero 					    unsigned int partition_type,
25*14743dddSAlejandro Lucero 					    const char *version_name)
26*14743dddSAlejandro Lucero {
27*14743dddSAlejandro Lucero 	char buf[EFX_MAX_VERSION_INFO_LEN];
28*14743dddSAlejandro Lucero 	u16 version[4];
29*14743dddSAlejandro Lucero 	int rc;
30*14743dddSAlejandro Lucero 
31*14743dddSAlejandro Lucero 	rc = efx_mcdi_nvram_metadata(efx, partition_type, NULL, version, NULL,
32*14743dddSAlejandro Lucero 				     0);
33*14743dddSAlejandro Lucero 	if (rc) {
34*14743dddSAlejandro Lucero 		netif_err(efx, drv, efx->net_dev, "mcdi nvram %s: failed\n",
35*14743dddSAlejandro Lucero 			  version_name);
36*14743dddSAlejandro Lucero 		return rc;
37*14743dddSAlejandro Lucero 	}
38*14743dddSAlejandro Lucero 
39*14743dddSAlejandro Lucero 	snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u", version[0],
40*14743dddSAlejandro Lucero 		 version[1], version[2], version[3]);
41*14743dddSAlejandro Lucero 	devlink_info_version_stored_put(req, version_name, buf);
42*14743dddSAlejandro Lucero 
43*14743dddSAlejandro Lucero 	return 0;
44*14743dddSAlejandro Lucero }
45*14743dddSAlejandro Lucero 
46*14743dddSAlejandro Lucero static int efx_devlink_info_stored_versions(struct efx_nic *efx,
47*14743dddSAlejandro Lucero 					    struct devlink_info_req *req)
48*14743dddSAlejandro Lucero {
49*14743dddSAlejandro Lucero 	int rc;
50*14743dddSAlejandro Lucero 
51*14743dddSAlejandro Lucero 	rc = efx_devlink_info_nvram_partition(efx, req,
52*14743dddSAlejandro Lucero 					      NVRAM_PARTITION_TYPE_BUNDLE,
53*14743dddSAlejandro Lucero 					      DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID);
54*14743dddSAlejandro Lucero 	if (rc)
55*14743dddSAlejandro Lucero 		return rc;
56*14743dddSAlejandro Lucero 
57*14743dddSAlejandro Lucero 	rc = efx_devlink_info_nvram_partition(efx, req,
58*14743dddSAlejandro Lucero 					      NVRAM_PARTITION_TYPE_MC_FIRMWARE,
59*14743dddSAlejandro Lucero 					      DEVLINK_INFO_VERSION_GENERIC_FW_MGMT);
60*14743dddSAlejandro Lucero 	if (rc)
61*14743dddSAlejandro Lucero 		return rc;
62*14743dddSAlejandro Lucero 
63*14743dddSAlejandro Lucero 	rc = efx_devlink_info_nvram_partition(efx, req,
64*14743dddSAlejandro Lucero 					      NVRAM_PARTITION_TYPE_SUC_FIRMWARE,
65*14743dddSAlejandro Lucero 					      EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC);
66*14743dddSAlejandro Lucero 	if (rc)
67*14743dddSAlejandro Lucero 		return rc;
68*14743dddSAlejandro Lucero 
69*14743dddSAlejandro Lucero 	rc = efx_devlink_info_nvram_partition(efx, req,
70*14743dddSAlejandro Lucero 					      NVRAM_PARTITION_TYPE_EXPANSION_ROM,
71*14743dddSAlejandro Lucero 					      EFX_DEVLINK_INFO_VERSION_FW_EXPROM);
72*14743dddSAlejandro Lucero 	if (rc)
73*14743dddSAlejandro Lucero 		return rc;
74*14743dddSAlejandro Lucero 
75*14743dddSAlejandro Lucero 	rc = efx_devlink_info_nvram_partition(efx, req,
76*14743dddSAlejandro Lucero 					      NVRAM_PARTITION_TYPE_EXPANSION_UEFI,
77*14743dddSAlejandro Lucero 					      EFX_DEVLINK_INFO_VERSION_FW_UEFI);
78*14743dddSAlejandro Lucero 	return rc;
79*14743dddSAlejandro Lucero }
80*14743dddSAlejandro Lucero 
81*14743dddSAlejandro Lucero #define EFX_VER_FLAG(_f)	\
82*14743dddSAlejandro Lucero 	(MC_CMD_GET_VERSION_V5_OUT_ ## _f ## _PRESENT_LBN)
83*14743dddSAlejandro Lucero 
84*14743dddSAlejandro Lucero static void efx_devlink_info_running_v2(struct efx_nic *efx,
85*14743dddSAlejandro Lucero 					struct devlink_info_req *req,
86*14743dddSAlejandro Lucero 					unsigned int flags, efx_dword_t *outbuf)
87*14743dddSAlejandro Lucero {
88*14743dddSAlejandro Lucero 	char buf[EFX_MAX_VERSION_INFO_LEN];
89*14743dddSAlejandro Lucero 	union {
90*14743dddSAlejandro Lucero 		const __le32 *dwords;
91*14743dddSAlejandro Lucero 		const __le16 *words;
92*14743dddSAlejandro Lucero 		const char *str;
93*14743dddSAlejandro Lucero 	} ver;
94*14743dddSAlejandro Lucero 	struct rtc_time build_date;
95*14743dddSAlejandro Lucero 	unsigned int build_id;
96*14743dddSAlejandro Lucero 	size_t offset;
97*14743dddSAlejandro Lucero 	__maybe_unused u64 tstamp;
98*14743dddSAlejandro Lucero 
99*14743dddSAlejandro Lucero 	if (flags & BIT(EFX_VER_FLAG(BOARD_EXT_INFO))) {
100*14743dddSAlejandro Lucero 		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%s",
101*14743dddSAlejandro Lucero 			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_NAME));
102*14743dddSAlejandro Lucero 		devlink_info_version_fixed_put(req,
103*14743dddSAlejandro Lucero 					       DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
104*14743dddSAlejandro Lucero 					       buf);
105*14743dddSAlejandro Lucero 
106*14743dddSAlejandro Lucero 		/* Favour full board version if present (in V5 or later) */
107*14743dddSAlejandro Lucero 		if (~flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
108*14743dddSAlejandro Lucero 			snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u",
109*14743dddSAlejandro Lucero 				 MCDI_DWORD(outbuf,
110*14743dddSAlejandro Lucero 					    GET_VERSION_V2_OUT_BOARD_REVISION));
111*14743dddSAlejandro Lucero 			devlink_info_version_fixed_put(req,
112*14743dddSAlejandro Lucero 						       DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
113*14743dddSAlejandro Lucero 						       buf);
114*14743dddSAlejandro Lucero 		}
115*14743dddSAlejandro Lucero 
116*14743dddSAlejandro Lucero 		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_SERIAL);
117*14743dddSAlejandro Lucero 		if (ver.str[0])
118*14743dddSAlejandro Lucero 			devlink_info_board_serial_number_put(req, ver.str);
119*14743dddSAlejandro Lucero 	}
120*14743dddSAlejandro Lucero 
121*14743dddSAlejandro Lucero 	if (flags & BIT(EFX_VER_FLAG(FPGA_EXT_INFO))) {
122*14743dddSAlejandro Lucero 		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
123*14743dddSAlejandro Lucero 						GET_VERSION_V2_OUT_FPGA_VERSION);
124*14743dddSAlejandro Lucero 		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u_%c%u",
125*14743dddSAlejandro Lucero 				  le32_to_cpu(ver.dwords[0]),
126*14743dddSAlejandro Lucero 				  'A' + le32_to_cpu(ver.dwords[1]),
127*14743dddSAlejandro Lucero 				  le32_to_cpu(ver.dwords[2]));
128*14743dddSAlejandro Lucero 
129*14743dddSAlejandro Lucero 		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_FPGA_EXTRA);
130*14743dddSAlejandro Lucero 		if (ver.str[0])
131*14743dddSAlejandro Lucero 			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
132*14743dddSAlejandro Lucero 				 " (%s)", ver.str);
133*14743dddSAlejandro Lucero 
134*14743dddSAlejandro Lucero 		devlink_info_version_running_put(req,
135*14743dddSAlejandro Lucero 						 EFX_DEVLINK_INFO_VERSION_FPGA_REV,
136*14743dddSAlejandro Lucero 						 buf);
137*14743dddSAlejandro Lucero 	}
138*14743dddSAlejandro Lucero 
139*14743dddSAlejandro Lucero 	if (flags & BIT(EFX_VER_FLAG(CMC_EXT_INFO))) {
140*14743dddSAlejandro Lucero 		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
141*14743dddSAlejandro Lucero 						GET_VERSION_V2_OUT_CMCFW_VERSION);
142*14743dddSAlejandro Lucero 		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
143*14743dddSAlejandro Lucero 				  le32_to_cpu(ver.dwords[0]),
144*14743dddSAlejandro Lucero 				  le32_to_cpu(ver.dwords[1]),
145*14743dddSAlejandro Lucero 				  le32_to_cpu(ver.dwords[2]),
146*14743dddSAlejandro Lucero 				  le32_to_cpu(ver.dwords[3]));
147*14743dddSAlejandro Lucero 
148*14743dddSAlejandro Lucero #ifdef CONFIG_RTC_LIB
149*14743dddSAlejandro Lucero 		tstamp = MCDI_QWORD(outbuf,
150*14743dddSAlejandro Lucero 				    GET_VERSION_V2_OUT_CMCFW_BUILD_DATE);
151*14743dddSAlejandro Lucero 		if (tstamp) {
152*14743dddSAlejandro Lucero 			rtc_time64_to_tm(tstamp, &build_date);
153*14743dddSAlejandro Lucero 			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
154*14743dddSAlejandro Lucero 				 " (%ptRd)", &build_date);
155*14743dddSAlejandro Lucero 		}
156*14743dddSAlejandro Lucero #endif
157*14743dddSAlejandro Lucero 
158*14743dddSAlejandro Lucero 		devlink_info_version_running_put(req,
159*14743dddSAlejandro Lucero 						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC,
160*14743dddSAlejandro Lucero 						 buf);
161*14743dddSAlejandro Lucero 	}
162*14743dddSAlejandro Lucero 
163*14743dddSAlejandro Lucero 	ver.words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_V2_OUT_VERSION);
164*14743dddSAlejandro Lucero 	offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
165*14743dddSAlejandro Lucero 			  le16_to_cpu(ver.words[0]), le16_to_cpu(ver.words[1]),
166*14743dddSAlejandro Lucero 			  le16_to_cpu(ver.words[2]), le16_to_cpu(ver.words[3]));
167*14743dddSAlejandro Lucero 	if (flags & BIT(EFX_VER_FLAG(MCFW_EXT_INFO))) {
168*14743dddSAlejandro Lucero 		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_ID);
169*14743dddSAlejandro Lucero 		snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
170*14743dddSAlejandro Lucero 			 " (%x) %s", build_id,
171*14743dddSAlejandro Lucero 			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_NAME));
172*14743dddSAlejandro Lucero 	}
173*14743dddSAlejandro Lucero 	devlink_info_version_running_put(req,
174*14743dddSAlejandro Lucero 					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
175*14743dddSAlejandro Lucero 					 buf);
176*14743dddSAlejandro Lucero 
177*14743dddSAlejandro Lucero 	if (flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
178*14743dddSAlejandro Lucero 		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
179*14743dddSAlejandro Lucero 						GET_VERSION_V2_OUT_SUCFW_VERSION);
180*14743dddSAlejandro Lucero #ifdef CONFIG_RTC_LIB
181*14743dddSAlejandro Lucero 		tstamp = MCDI_QWORD(outbuf,
182*14743dddSAlejandro Lucero 				    GET_VERSION_V2_OUT_SUCFW_BUILD_DATE);
183*14743dddSAlejandro Lucero 		rtc_time64_to_tm(tstamp, &build_date);
184*14743dddSAlejandro Lucero #else
185*14743dddSAlejandro Lucero 		memset(&build_date, 0, sizeof(build_date)
186*14743dddSAlejandro Lucero #endif
187*14743dddSAlejandro Lucero 		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_SUCFW_CHIP_ID);
188*14743dddSAlejandro Lucero 
189*14743dddSAlejandro Lucero 		snprintf(buf, EFX_MAX_VERSION_INFO_LEN,
190*14743dddSAlejandro Lucero 			 "%u.%u.%u.%u type %x (%ptRd)",
191*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
192*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[2]), le32_to_cpu(ver.dwords[3]),
193*14743dddSAlejandro Lucero 			 build_id, &build_date);
194*14743dddSAlejandro Lucero 
195*14743dddSAlejandro Lucero 		devlink_info_version_running_put(req,
196*14743dddSAlejandro Lucero 						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
197*14743dddSAlejandro Lucero 						 buf);
198*14743dddSAlejandro Lucero 	}
199*14743dddSAlejandro Lucero }
200*14743dddSAlejandro Lucero 
201*14743dddSAlejandro Lucero static void efx_devlink_info_running_v3(struct efx_nic *efx,
202*14743dddSAlejandro Lucero 					struct devlink_info_req *req,
203*14743dddSAlejandro Lucero 					unsigned int flags, efx_dword_t *outbuf)
204*14743dddSAlejandro Lucero {
205*14743dddSAlejandro Lucero 	char buf[EFX_MAX_VERSION_INFO_LEN];
206*14743dddSAlejandro Lucero 	union {
207*14743dddSAlejandro Lucero 		const __le32 *dwords;
208*14743dddSAlejandro Lucero 		const __le16 *words;
209*14743dddSAlejandro Lucero 		const char *str;
210*14743dddSAlejandro Lucero 	} ver;
211*14743dddSAlejandro Lucero 
212*14743dddSAlejandro Lucero 	if (flags & BIT(EFX_VER_FLAG(DATAPATH_HW_VERSION))) {
213*14743dddSAlejandro Lucero 		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
214*14743dddSAlejandro Lucero 						GET_VERSION_V3_OUT_DATAPATH_HW_VERSION);
215*14743dddSAlejandro Lucero 
216*14743dddSAlejandro Lucero 		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
217*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
218*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[2]));
219*14743dddSAlejandro Lucero 
220*14743dddSAlejandro Lucero 		devlink_info_version_running_put(req,
221*14743dddSAlejandro Lucero 						 EFX_DEVLINK_INFO_VERSION_DATAPATH_HW,
222*14743dddSAlejandro Lucero 						 buf);
223*14743dddSAlejandro Lucero 	}
224*14743dddSAlejandro Lucero 
225*14743dddSAlejandro Lucero 	if (flags & BIT(EFX_VER_FLAG(DATAPATH_FW_VERSION))) {
226*14743dddSAlejandro Lucero 		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
227*14743dddSAlejandro Lucero 						GET_VERSION_V3_OUT_DATAPATH_FW_VERSION);
228*14743dddSAlejandro Lucero 
229*14743dddSAlejandro Lucero 		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
230*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
231*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[2]));
232*14743dddSAlejandro Lucero 
233*14743dddSAlejandro Lucero 		devlink_info_version_running_put(req,
234*14743dddSAlejandro Lucero 						 EFX_DEVLINK_INFO_VERSION_DATAPATH_FW,
235*14743dddSAlejandro Lucero 						 buf);
236*14743dddSAlejandro Lucero 	}
237*14743dddSAlejandro Lucero }
238*14743dddSAlejandro Lucero 
239*14743dddSAlejandro Lucero static void efx_devlink_info_running_v4(struct efx_nic *efx,
240*14743dddSAlejandro Lucero 					struct devlink_info_req *req,
241*14743dddSAlejandro Lucero 					unsigned int flags, efx_dword_t *outbuf)
242*14743dddSAlejandro Lucero {
243*14743dddSAlejandro Lucero 	char buf[EFX_MAX_VERSION_INFO_LEN];
244*14743dddSAlejandro Lucero 	union {
245*14743dddSAlejandro Lucero 		const __le32 *dwords;
246*14743dddSAlejandro Lucero 		const __le16 *words;
247*14743dddSAlejandro Lucero 		const char *str;
248*14743dddSAlejandro Lucero 	} ver;
249*14743dddSAlejandro Lucero 
250*14743dddSAlejandro Lucero 	if (flags & BIT(EFX_VER_FLAG(SOC_BOOT_VERSION))) {
251*14743dddSAlejandro Lucero 		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
252*14743dddSAlejandro Lucero 						GET_VERSION_V4_OUT_SOC_BOOT_VERSION);
253*14743dddSAlejandro Lucero 
254*14743dddSAlejandro Lucero 		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
255*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
256*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[2]),
257*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[3]));
258*14743dddSAlejandro Lucero 
259*14743dddSAlejandro Lucero 		devlink_info_version_running_put(req,
260*14743dddSAlejandro Lucero 						 EFX_DEVLINK_INFO_VERSION_SOC_BOOT,
261*14743dddSAlejandro Lucero 						 buf);
262*14743dddSAlejandro Lucero 	}
263*14743dddSAlejandro Lucero 
264*14743dddSAlejandro Lucero 	if (flags & BIT(EFX_VER_FLAG(SOC_UBOOT_VERSION))) {
265*14743dddSAlejandro Lucero 		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
266*14743dddSAlejandro Lucero 						GET_VERSION_V4_OUT_SOC_UBOOT_VERSION);
267*14743dddSAlejandro Lucero 
268*14743dddSAlejandro Lucero 		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
269*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
270*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[2]),
271*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[3]));
272*14743dddSAlejandro Lucero 
273*14743dddSAlejandro Lucero 		devlink_info_version_running_put(req,
274*14743dddSAlejandro Lucero 						 EFX_DEVLINK_INFO_VERSION_SOC_UBOOT,
275*14743dddSAlejandro Lucero 						 buf);
276*14743dddSAlejandro Lucero 	}
277*14743dddSAlejandro Lucero 
278*14743dddSAlejandro Lucero 	if (flags & BIT(EFX_VER_FLAG(SOC_MAIN_ROOTFS_VERSION))) {
279*14743dddSAlejandro Lucero 		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
280*14743dddSAlejandro Lucero 					GET_VERSION_V4_OUT_SOC_MAIN_ROOTFS_VERSION);
281*14743dddSAlejandro Lucero 
282*14743dddSAlejandro Lucero 		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
283*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
284*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[2]),
285*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[3]));
286*14743dddSAlejandro Lucero 
287*14743dddSAlejandro Lucero 		devlink_info_version_running_put(req,
288*14743dddSAlejandro Lucero 						 EFX_DEVLINK_INFO_VERSION_SOC_MAIN,
289*14743dddSAlejandro Lucero 						 buf);
290*14743dddSAlejandro Lucero 	}
291*14743dddSAlejandro Lucero 
292*14743dddSAlejandro Lucero 	if (flags & BIT(EFX_VER_FLAG(SOC_RECOVERY_BUILDROOT_VERSION))) {
293*14743dddSAlejandro Lucero 		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
294*14743dddSAlejandro Lucero 						GET_VERSION_V4_OUT_SOC_RECOVERY_BUILDROOT_VERSION);
295*14743dddSAlejandro Lucero 
296*14743dddSAlejandro Lucero 		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
297*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
298*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[2]),
299*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[3]));
300*14743dddSAlejandro Lucero 
301*14743dddSAlejandro Lucero 		devlink_info_version_running_put(req,
302*14743dddSAlejandro Lucero 						 EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY,
303*14743dddSAlejandro Lucero 						 buf);
304*14743dddSAlejandro Lucero 	}
305*14743dddSAlejandro Lucero 
306*14743dddSAlejandro Lucero 	if (flags & BIT(EFX_VER_FLAG(SUCFW_VERSION)) &&
307*14743dddSAlejandro Lucero 	    ~flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
308*14743dddSAlejandro Lucero 		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
309*14743dddSAlejandro Lucero 						GET_VERSION_V4_OUT_SUCFW_VERSION);
310*14743dddSAlejandro Lucero 
311*14743dddSAlejandro Lucero 		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
312*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
313*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[2]),
314*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[3]));
315*14743dddSAlejandro Lucero 
316*14743dddSAlejandro Lucero 		devlink_info_version_running_put(req,
317*14743dddSAlejandro Lucero 						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
318*14743dddSAlejandro Lucero 						 buf);
319*14743dddSAlejandro Lucero 	}
320*14743dddSAlejandro Lucero }
321*14743dddSAlejandro Lucero 
322*14743dddSAlejandro Lucero static void efx_devlink_info_running_v5(struct efx_nic *efx,
323*14743dddSAlejandro Lucero 					struct devlink_info_req *req,
324*14743dddSAlejandro Lucero 					unsigned int flags, efx_dword_t *outbuf)
325*14743dddSAlejandro Lucero {
326*14743dddSAlejandro Lucero 	char buf[EFX_MAX_VERSION_INFO_LEN];
327*14743dddSAlejandro Lucero 	union {
328*14743dddSAlejandro Lucero 		const __le32 *dwords;
329*14743dddSAlejandro Lucero 		const __le16 *words;
330*14743dddSAlejandro Lucero 		const char *str;
331*14743dddSAlejandro Lucero 	} ver;
332*14743dddSAlejandro Lucero 
333*14743dddSAlejandro Lucero 	if (flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
334*14743dddSAlejandro Lucero 		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
335*14743dddSAlejandro Lucero 						GET_VERSION_V5_OUT_BOARD_VERSION);
336*14743dddSAlejandro Lucero 
337*14743dddSAlejandro Lucero 		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
338*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
339*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[2]),
340*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[3]));
341*14743dddSAlejandro Lucero 
342*14743dddSAlejandro Lucero 		devlink_info_version_running_put(req,
343*14743dddSAlejandro Lucero 						 DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
344*14743dddSAlejandro Lucero 						 buf);
345*14743dddSAlejandro Lucero 	}
346*14743dddSAlejandro Lucero 
347*14743dddSAlejandro Lucero 	if (flags & BIT(EFX_VER_FLAG(BUNDLE_VERSION))) {
348*14743dddSAlejandro Lucero 		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
349*14743dddSAlejandro Lucero 						GET_VERSION_V5_OUT_BUNDLE_VERSION);
350*14743dddSAlejandro Lucero 
351*14743dddSAlejandro Lucero 		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
352*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
353*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[2]),
354*14743dddSAlejandro Lucero 			 le32_to_cpu(ver.dwords[3]));
355*14743dddSAlejandro Lucero 
356*14743dddSAlejandro Lucero 		devlink_info_version_running_put(req,
357*14743dddSAlejandro Lucero 						 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID,
358*14743dddSAlejandro Lucero 						 buf);
359*14743dddSAlejandro Lucero 	}
360*14743dddSAlejandro Lucero }
361*14743dddSAlejandro Lucero 
362*14743dddSAlejandro Lucero static int efx_devlink_info_running_versions(struct efx_nic *efx,
363*14743dddSAlejandro Lucero 					     struct devlink_info_req *req)
364*14743dddSAlejandro Lucero {
365*14743dddSAlejandro Lucero 	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_V5_OUT_LEN);
366*14743dddSAlejandro Lucero 	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_VERSION_EXT_IN_LEN);
367*14743dddSAlejandro Lucero 	char buf[EFX_MAX_VERSION_INFO_LEN];
368*14743dddSAlejandro Lucero 	union {
369*14743dddSAlejandro Lucero 		const __le32 *dwords;
370*14743dddSAlejandro Lucero 		const __le16 *words;
371*14743dddSAlejandro Lucero 		const char *str;
372*14743dddSAlejandro Lucero 	} ver;
373*14743dddSAlejandro Lucero 	size_t outlength;
374*14743dddSAlejandro Lucero 	unsigned int flags;
375*14743dddSAlejandro Lucero 	int rc;
376*14743dddSAlejandro Lucero 
377*14743dddSAlejandro Lucero 	rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, inbuf, sizeof(inbuf),
378*14743dddSAlejandro Lucero 			  outbuf, sizeof(outbuf), &outlength);
379*14743dddSAlejandro Lucero 	if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN) {
380*14743dddSAlejandro Lucero 		netif_err(efx, drv, efx->net_dev,
381*14743dddSAlejandro Lucero 			  "mcdi MC_CMD_GET_VERSION failed\n");
382*14743dddSAlejandro Lucero 		return rc;
383*14743dddSAlejandro Lucero 	}
384*14743dddSAlejandro Lucero 
385*14743dddSAlejandro Lucero 	/* Handle previous output */
386*14743dddSAlejandro Lucero 	if (outlength < MC_CMD_GET_VERSION_V2_OUT_LEN) {
387*14743dddSAlejandro Lucero 		ver.words = (__le16 *)MCDI_PTR(outbuf,
388*14743dddSAlejandro Lucero 					       GET_VERSION_EXT_OUT_VERSION);
389*14743dddSAlejandro Lucero 		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
390*14743dddSAlejandro Lucero 			 le16_to_cpu(ver.words[0]),
391*14743dddSAlejandro Lucero 			 le16_to_cpu(ver.words[1]),
392*14743dddSAlejandro Lucero 			 le16_to_cpu(ver.words[2]),
393*14743dddSAlejandro Lucero 			 le16_to_cpu(ver.words[3]));
394*14743dddSAlejandro Lucero 
395*14743dddSAlejandro Lucero 		devlink_info_version_running_put(req,
396*14743dddSAlejandro Lucero 						 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
397*14743dddSAlejandro Lucero 						 buf);
398*14743dddSAlejandro Lucero 		return 0;
399*14743dddSAlejandro Lucero 	}
400*14743dddSAlejandro Lucero 
401*14743dddSAlejandro Lucero 	/* Handle V2 additions */
402*14743dddSAlejandro Lucero 	flags = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_FLAGS);
403*14743dddSAlejandro Lucero 	efx_devlink_info_running_v2(efx, req, flags, outbuf);
404*14743dddSAlejandro Lucero 
405*14743dddSAlejandro Lucero 	if (outlength < MC_CMD_GET_VERSION_V3_OUT_LEN)
406*14743dddSAlejandro Lucero 		return 0;
407*14743dddSAlejandro Lucero 
408*14743dddSAlejandro Lucero 	/* Handle V3 additions */
409*14743dddSAlejandro Lucero 	efx_devlink_info_running_v3(efx, req, flags, outbuf);
410*14743dddSAlejandro Lucero 
411*14743dddSAlejandro Lucero 	if (outlength < MC_CMD_GET_VERSION_V4_OUT_LEN)
412*14743dddSAlejandro Lucero 		return 0;
413*14743dddSAlejandro Lucero 
414*14743dddSAlejandro Lucero 	/* Handle V4 additions */
415*14743dddSAlejandro Lucero 	efx_devlink_info_running_v4(efx, req, flags, outbuf);
416*14743dddSAlejandro Lucero 
417*14743dddSAlejandro Lucero 	if (outlength < MC_CMD_GET_VERSION_V5_OUT_LEN)
418*14743dddSAlejandro Lucero 		return 0;
419*14743dddSAlejandro Lucero 
420*14743dddSAlejandro Lucero 	/* Handle V5 additions */
421*14743dddSAlejandro Lucero 	efx_devlink_info_running_v5(efx, req, flags, outbuf);
422*14743dddSAlejandro Lucero 
423*14743dddSAlejandro Lucero 	return 0;
424*14743dddSAlejandro Lucero }
425*14743dddSAlejandro Lucero 
426*14743dddSAlejandro Lucero #define EFX_MAX_SERIALNUM_LEN	(ETH_ALEN * 2 + 1)
427*14743dddSAlejandro Lucero 
428*14743dddSAlejandro Lucero static int efx_devlink_info_board_cfg(struct efx_nic *efx,
429*14743dddSAlejandro Lucero 				      struct devlink_info_req *req)
430*14743dddSAlejandro Lucero {
431*14743dddSAlejandro Lucero 	char sn[EFX_MAX_SERIALNUM_LEN];
432*14743dddSAlejandro Lucero 	u8 mac_address[ETH_ALEN];
433*14743dddSAlejandro Lucero 	int rc;
434*14743dddSAlejandro Lucero 
435*14743dddSAlejandro Lucero 	rc = efx_mcdi_get_board_cfg(efx, (u8 *)mac_address, NULL, NULL);
436*14743dddSAlejandro Lucero 	if (!rc) {
437*14743dddSAlejandro Lucero 		snprintf(sn, EFX_MAX_SERIALNUM_LEN, "%pm", mac_address);
438*14743dddSAlejandro Lucero 		devlink_info_serial_number_put(req, sn);
439*14743dddSAlejandro Lucero 	}
440*14743dddSAlejandro Lucero 	return rc;
441*14743dddSAlejandro Lucero }
442*14743dddSAlejandro Lucero 
443*14743dddSAlejandro Lucero static int efx_devlink_info_get(struct devlink *devlink,
444*14743dddSAlejandro Lucero 				struct devlink_info_req *req,
445*14743dddSAlejandro Lucero 				struct netlink_ext_ack *extack)
446*14743dddSAlejandro Lucero {
447*14743dddSAlejandro Lucero 	struct efx_devlink *devlink_private = devlink_priv(devlink);
448*14743dddSAlejandro Lucero 	struct efx_nic *efx = devlink_private->efx;
449*14743dddSAlejandro Lucero 	int rc;
450*14743dddSAlejandro Lucero 
451*14743dddSAlejandro Lucero 	/* Several different MCDI commands are used. We report first error
452*14743dddSAlejandro Lucero 	 * through extack returning at that point. Specific error
453*14743dddSAlejandro Lucero 	 * information via system messages.
454*14743dddSAlejandro Lucero 	 */
455*14743dddSAlejandro Lucero 	rc = efx_devlink_info_board_cfg(efx, req);
456*14743dddSAlejandro Lucero 	if (rc) {
457*14743dddSAlejandro Lucero 		NL_SET_ERR_MSG_MOD(extack, "Getting board info failed");
458*14743dddSAlejandro Lucero 		return rc;
459*14743dddSAlejandro Lucero 	}
460*14743dddSAlejandro Lucero 	rc = efx_devlink_info_stored_versions(efx, req);
461*14743dddSAlejandro Lucero 	if (rc) {
462*14743dddSAlejandro Lucero 		NL_SET_ERR_MSG_MOD(extack, "Getting stored versions failed");
463*14743dddSAlejandro Lucero 		return rc;
464*14743dddSAlejandro Lucero 	}
465*14743dddSAlejandro Lucero 	rc = efx_devlink_info_running_versions(efx, req);
466*14743dddSAlejandro Lucero 	if (rc) {
467*14743dddSAlejandro Lucero 		NL_SET_ERR_MSG_MOD(extack, "Getting running versions failed");
468*14743dddSAlejandro Lucero 		return rc;
469*14743dddSAlejandro Lucero 	}
470*14743dddSAlejandro Lucero 
471*14743dddSAlejandro Lucero 	return 0;
472*14743dddSAlejandro Lucero }
473*14743dddSAlejandro Lucero 
474fa34a514SAlejandro Lucero static const struct devlink_ops sfc_devlink_ops = {
475*14743dddSAlejandro Lucero 	.info_get			= efx_devlink_info_get,
476fa34a514SAlejandro Lucero };
477fa34a514SAlejandro Lucero 
478fa34a514SAlejandro Lucero void efx_fini_devlink_lock(struct efx_nic *efx)
479fa34a514SAlejandro Lucero {
480fa34a514SAlejandro Lucero 	if (efx->devlink)
481fa34a514SAlejandro Lucero 		devl_lock(efx->devlink);
482fa34a514SAlejandro Lucero }
483fa34a514SAlejandro Lucero 
484fa34a514SAlejandro Lucero void efx_fini_devlink_and_unlock(struct efx_nic *efx)
485fa34a514SAlejandro Lucero {
486fa34a514SAlejandro Lucero 	if (efx->devlink) {
487fa34a514SAlejandro Lucero 		devl_unregister(efx->devlink);
488fa34a514SAlejandro Lucero 		devl_unlock(efx->devlink);
489fa34a514SAlejandro Lucero 		devlink_free(efx->devlink);
490fa34a514SAlejandro Lucero 		efx->devlink = NULL;
491fa34a514SAlejandro Lucero 	}
492fa34a514SAlejandro Lucero }
493fa34a514SAlejandro Lucero 
494fa34a514SAlejandro Lucero int efx_probe_devlink_and_lock(struct efx_nic *efx)
495fa34a514SAlejandro Lucero {
496fa34a514SAlejandro Lucero 	struct efx_devlink *devlink_private;
497fa34a514SAlejandro Lucero 
498fa34a514SAlejandro Lucero 	if (efx->type->is_vf)
499fa34a514SAlejandro Lucero 		return 0;
500fa34a514SAlejandro Lucero 
501fa34a514SAlejandro Lucero 	efx->devlink = devlink_alloc(&sfc_devlink_ops,
502fa34a514SAlejandro Lucero 				     sizeof(struct efx_devlink),
503fa34a514SAlejandro Lucero 				     &efx->pci_dev->dev);
504fa34a514SAlejandro Lucero 	if (!efx->devlink)
505fa34a514SAlejandro Lucero 		return -ENOMEM;
506fa34a514SAlejandro Lucero 
507fa34a514SAlejandro Lucero 	devl_lock(efx->devlink);
508fa34a514SAlejandro Lucero 	devlink_private = devlink_priv(efx->devlink);
509fa34a514SAlejandro Lucero 	devlink_private->efx = efx;
510fa34a514SAlejandro Lucero 
511fa34a514SAlejandro Lucero 	devl_register(efx->devlink);
512fa34a514SAlejandro Lucero 
513fa34a514SAlejandro Lucero 	return 0;
514fa34a514SAlejandro Lucero }
515fa34a514SAlejandro Lucero 
516fa34a514SAlejandro Lucero void efx_probe_devlink_unlock(struct efx_nic *efx)
517fa34a514SAlejandro Lucero {
518fa34a514SAlejandro Lucero 	if (!efx->devlink)
519fa34a514SAlejandro Lucero 		return;
520fa34a514SAlejandro Lucero 
521fa34a514SAlejandro Lucero 	devl_unlock(efx->devlink);
522fa34a514SAlejandro Lucero }
523