File Index
Files and directories
Sign in
FILE

efx_devlink.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/sfc/efx_devlink.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/****************************************************************************
  3 * Driver for AMD network controllers and boards
  4 * Copyright (C) 2023, Advanced Micro Devices, Inc.
  5 *
  6 * This program is free software; you can redistribute it and/or modify it
  7 * under the terms of the GNU General Public License version 2 as published
  8 * by the Free Software Foundation, incorporated herein by reference.
  9 */
 10
 11#include "net_driver.h"
 12#include "ef100_nic.h"
 13#include "efx_devlink.h"
 14#include <linux/rtc.h>
 15#include "mcdi.h"
 16#include "mcdi_functions.h"
 17#include "mcdi_pcol.h"
 18#ifdef CONFIG_SFC_SRIOV
 19#include "mae.h"
 20#include "ef100_rep.h"
 21#endif
 22#include "efx_reflash.h"
 23
 24struct efx_devlink {
 25	struct efx_nic *efx;
 26};
 27
 28#ifdef CONFIG_SFC_SRIOV
 29
 30static int efx_devlink_port_addr_get(struct devlink_port *port, u8 *hw_addr,
 31				     int *hw_addr_len,
 32				     struct netlink_ext_ack *extack)
 33{
 34	struct efx_devlink *devlink = devlink_priv(port->devlink);
 35	struct mae_mport_desc *mport_desc;
 36	efx_qword_t pciefn;
 37	u32 client_id;
 38	int rc = 0;
 39
 40	mport_desc = container_of(port, struct mae_mport_desc, dl_port);
 41
 42	if (!ef100_mport_on_local_intf(devlink->efx, mport_desc)) {
 43		rc = -EINVAL;
 44		NL_SET_ERR_MSG_FMT(extack,
 45				   "Port not on local interface (mport: %u)",
 46				   mport_desc->mport_id);
 47		goto out;
 48	}
 49
 50	if (ef100_mport_is_vf(mport_desc))
 51		EFX_POPULATE_QWORD_3(pciefn,
 52				     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
 53				     PCIE_FUNCTION_VF, mport_desc->vf_idx,
 54				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
 55	else
 56		EFX_POPULATE_QWORD_3(pciefn,
 57				     PCIE_FUNCTION_PF, mport_desc->pf_idx,
 58				     PCIE_FUNCTION_VF, PCIE_FUNCTION_VF_NULL,
 59				     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
 60
 61	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
 62	if (rc) {
 63		NL_SET_ERR_MSG_FMT(extack,
 64				   "No internal client_ID for port (mport: %u)",
 65				   mport_desc->mport_id);
 66		goto out;
 67	}
 68
 69	rc = ef100_get_mac_address(devlink->efx, hw_addr, client_id, true);
 70	if (rc != 0)
 71		NL_SET_ERR_MSG_FMT(extack,
 72				   "No available MAC for port (mport: %u)",
 73				   mport_desc->mport_id);
 74out:
 75	*hw_addr_len = ETH_ALEN;
 76	return rc;
 77}
 78
 79static int efx_devlink_port_addr_set(struct devlink_port *port,
 80				     const u8 *hw_addr, int hw_addr_len,
 81				     struct netlink_ext_ack *extack)
 82{
 83	MCDI_DECLARE_BUF(inbuf, MC_CMD_SET_CLIENT_MAC_ADDRESSES_IN_LEN(1));
 84	struct efx_devlink *devlink = devlink_priv(port->devlink);
 85	struct mae_mport_desc *mport_desc;
 86	efx_qword_t pciefn;
 87	u32 client_id;
 88	int rc;
 89
 90	mport_desc = container_of(port, struct mae_mport_desc, dl_port);
 91
 92	if (!ef100_mport_is_vf(mport_desc)) {
 93		NL_SET_ERR_MSG_FMT(extack,
 94				   "port mac change not allowed (mport: %u)",
 95				   mport_desc->mport_id);
 96		return -EPERM;
 97	}
 98
 99	EFX_POPULATE_QWORD_3(pciefn,
100			     PCIE_FUNCTION_PF, PCIE_FUNCTION_PF_NULL,
101			     PCIE_FUNCTION_VF, mport_desc->vf_idx,
102			     PCIE_FUNCTION_INTF, PCIE_INTERFACE_CALLER);
103
104	rc = efx_ef100_lookup_client_id(devlink->efx, pciefn, &client_id);
105	if (rc) {
106		NL_SET_ERR_MSG_FMT(extack,
107				   "No internal client_ID for port (mport: %u)",
108				   mport_desc->mport_id);
109		return rc;
110	}
111
112	MCDI_SET_DWORD(inbuf, SET_CLIENT_MAC_ADDRESSES_IN_CLIENT_HANDLE,
113		       client_id);
114
115	ether_addr_copy(MCDI_PTR(inbuf, SET_CLIENT_MAC_ADDRESSES_IN_MAC_ADDRS),
116			hw_addr);
117
118	rc = efx_mcdi_rpc(devlink->efx, MC_CMD_SET_CLIENT_MAC_ADDRESSES, inbuf,
119			  sizeof(inbuf), NULL, 0, NULL);
120	if (rc)
121		NL_SET_ERR_MSG_FMT(extack,
122				   "sfc MC_CMD_SET_CLIENT_MAC_ADDRESSES mcdi error (mport: %u)",
123				   mport_desc->mport_id);
124
125	return rc;
126}
127
128static const struct devlink_port_ops sfc_devlink_port_ops = {
129	.port_fn_hw_addr_get = efx_devlink_port_addr_get,
130	.port_fn_hw_addr_set = efx_devlink_port_addr_set,
131};
132
133static void efx_devlink_del_port(struct devlink_port *dl_port)
134{
135	if (!dl_port)
136		return;
137	devl_port_unregister(dl_port);
138}
139
140static int efx_devlink_add_port(struct efx_nic *efx,
141				struct mae_mport_desc *mport)
142{
143	bool external = false;
144
145	if (!ef100_mport_on_local_intf(efx, mport))
146		external = true;
147
148	switch (mport->mport_type) {
149	case MAE_MPORT_DESC_MPORT_TYPE_VNIC:
150		if (mport->vf_idx != MAE_MPORT_DESC_VF_IDX_NULL)
151			devlink_port_attrs_pci_vf_set(&mport->dl_port, 0, mport->pf_idx,
152						      mport->vf_idx,
153						      external);
154		else
155			devlink_port_attrs_pci_pf_set(&mport->dl_port, 0, mport->pf_idx,
156						      external);
157		break;
158	default:
159		/* MAE_MPORT_DESC_MPORT_ALIAS and UNDEFINED */
160		return 0;
161	}
162
163	mport->dl_port.index = mport->mport_id;
164
165	return devl_port_register_with_ops(efx->devlink, &mport->dl_port,
166					   mport->mport_id,
167					   &sfc_devlink_port_ops);
168}
169
170#endif
171
172static int efx_devlink_info_nvram_partition(struct efx_nic *efx,
173					    struct devlink_info_req *req,
174					    unsigned int partition_type,
175					    const char *version_name)
176{
177	char buf[EFX_MAX_VERSION_INFO_LEN];
178	u16 version[4];
179	int rc;
180
181	rc = efx_mcdi_nvram_metadata(efx, partition_type, NULL, version, NULL,
182				     0);
183
184	/* If the partition does not exist, that is not an error. */
185	if (rc == -ENOENT)
186		return 0;
187
188	if (rc) {
189		netif_err(efx, drv, efx->net_dev, "mcdi nvram %s: failed (rc=%d)\n",
190			  version_name, rc);
191		return rc;
192	}
193
194	snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u", version[0],
195		 version[1], version[2], version[3]);
196	devlink_info_version_stored_put(req, version_name, buf);
197
198	return 0;
199}
200
201static int efx_devlink_info_stored_versions(struct efx_nic *efx,
202					    struct devlink_info_req *req)
203{
204	int err;
205
206	/* We do not care here about the specific error but just if an error
207	 * happened. The specific error will be reported inside the call
208	 * through system messages, and if any error happened in any call
209	 * below, we report it through extack.
210	 */
211	err = efx_devlink_info_nvram_partition(efx, req,
212					       NVRAM_PARTITION_TYPE_BUNDLE,
213					       DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID);
214
215	err |= efx_devlink_info_nvram_partition(efx, req,
216						NVRAM_PARTITION_TYPE_MC_FIRMWARE,
217						DEVLINK_INFO_VERSION_GENERIC_FW_MGMT);
218
219	err |= efx_devlink_info_nvram_partition(efx, req,
220						NVRAM_PARTITION_TYPE_SUC_FIRMWARE,
221						EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC);
222
223	err |= efx_devlink_info_nvram_partition(efx, req,
224						NVRAM_PARTITION_TYPE_EXPANSION_ROM,
225						EFX_DEVLINK_INFO_VERSION_FW_EXPROM);
226
227	err |= efx_devlink_info_nvram_partition(efx, req,
228						NVRAM_PARTITION_TYPE_EXPANSION_UEFI,
229						EFX_DEVLINK_INFO_VERSION_FW_UEFI);
230	return err;
231}
232
233#define EFX_VER_FLAG(_f)	\
234	(MC_CMD_GET_VERSION_V5_OUT_ ## _f ## _PRESENT_LBN)
235
236static void efx_devlink_info_running_v2(struct efx_nic *efx,
237					struct devlink_info_req *req,
238					unsigned int flags, efx_dword_t *outbuf)
239{
240	char buf[EFX_MAX_VERSION_INFO_LEN];
241	union {
242		const __le32 *dwords;
243		const __le16 *words;
244		const char *str;
245	} ver;
246	struct rtc_time build_date;
247	unsigned int build_id;
248	size_t offset;
249	__maybe_unused u64 tstamp;
250
251	if (flags & BIT(EFX_VER_FLAG(BOARD_EXT_INFO))) {
252		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%s",
253			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_NAME));
254		devlink_info_version_fixed_put(req,
255					       DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
256					       buf);
257
258		/* Favour full board version if present (in V5 or later) */
259		if (~flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
260			snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u",
261				 MCDI_DWORD(outbuf,
262					    GET_VERSION_V2_OUT_BOARD_REVISION));
263			devlink_info_version_fixed_put(req,
264						       DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
265						       buf);
266		}
267
268		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_BOARD_SERIAL);
269		if (ver.str[0])
270			devlink_info_board_serial_number_put(req, ver.str);
271	}
272
273	if (flags & BIT(EFX_VER_FLAG(FPGA_EXT_INFO))) {
274		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
275						GET_VERSION_V2_OUT_FPGA_VERSION);
276		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u_%c%u",
277				  le32_to_cpu(ver.dwords[0]),
278				  'A' + le32_to_cpu(ver.dwords[1]),
279				  le32_to_cpu(ver.dwords[2]));
280
281		ver.str = MCDI_PTR(outbuf, GET_VERSION_V2_OUT_FPGA_EXTRA);
282		if (ver.str[0])
283			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
284				 " (%s)", ver.str);
285
286		devlink_info_version_running_put(req,
287						 EFX_DEVLINK_INFO_VERSION_FPGA_REV,
288						 buf);
289	}
290
291	if (flags & BIT(EFX_VER_FLAG(CMC_EXT_INFO))) {
292		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
293						GET_VERSION_V2_OUT_CMCFW_VERSION);
294		offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
295				  le32_to_cpu(ver.dwords[0]),
296				  le32_to_cpu(ver.dwords[1]),
297				  le32_to_cpu(ver.dwords[2]),
298				  le32_to_cpu(ver.dwords[3]));
299
300#ifdef CONFIG_RTC_LIB
301		tstamp = MCDI_QWORD(outbuf,
302				    GET_VERSION_V2_OUT_CMCFW_BUILD_DATE);
303		if (tstamp) {
304			rtc_time64_to_tm(tstamp, &build_date);
305			snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
306				 " (%ptRd)", &build_date);
307		}
308#endif
309
310		devlink_info_version_running_put(req,
311						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_CMC,
312						 buf);
313	}
314
315	ver.words = (__le16 *)MCDI_PTR(outbuf, GET_VERSION_V2_OUT_VERSION);
316	offset = snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
317			  le16_to_cpu(ver.words[0]), le16_to_cpu(ver.words[1]),
318			  le16_to_cpu(ver.words[2]), le16_to_cpu(ver.words[3]));
319	if (flags & BIT(EFX_VER_FLAG(MCFW_EXT_INFO))) {
320		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_ID);
321		snprintf(&buf[offset], EFX_MAX_VERSION_INFO_LEN - offset,
322			 " (%x) %s", build_id,
323			 MCDI_PTR(outbuf, GET_VERSION_V2_OUT_MCFW_BUILD_NAME));
324	}
325	devlink_info_version_running_put(req,
326					 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
327					 buf);
328
329	if (flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
330		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
331						GET_VERSION_V2_OUT_SUCFW_VERSION);
332#ifdef CONFIG_RTC_LIB
333		tstamp = MCDI_QWORD(outbuf,
334				    GET_VERSION_V2_OUT_SUCFW_BUILD_DATE);
335		rtc_time64_to_tm(tstamp, &build_date);
336#else
337		memset(&build_date, 0, sizeof(build_date));
338#endif
339		build_id = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_SUCFW_CHIP_ID);
340
341		snprintf(buf, EFX_MAX_VERSION_INFO_LEN,
342			 "%u.%u.%u.%u type %x (%ptRd)",
343			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
344			 le32_to_cpu(ver.dwords[2]), le32_to_cpu(ver.dwords[3]),
345			 build_id, &build_date);
346
347		devlink_info_version_running_put(req,
348						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
349						 buf);
350	}
351}
352
353static void efx_devlink_info_running_v3(struct efx_nic *efx,
354					struct devlink_info_req *req,
355					unsigned int flags, efx_dword_t *outbuf)
356{
357	char buf[EFX_MAX_VERSION_INFO_LEN];
358	union {
359		const __le32 *dwords;
360		const __le16 *words;
361		const char *str;
362	} ver;
363
364	if (flags & BIT(EFX_VER_FLAG(DATAPATH_HW_VERSION))) {
365		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
366						GET_VERSION_V3_OUT_DATAPATH_HW_VERSION);
367
368		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
369			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
370			 le32_to_cpu(ver.dwords[2]));
371
372		devlink_info_version_running_put(req,
373						 EFX_DEVLINK_INFO_VERSION_DATAPATH_HW,
374						 buf);
375	}
376
377	if (flags & BIT(EFX_VER_FLAG(DATAPATH_FW_VERSION))) {
378		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
379						GET_VERSION_V3_OUT_DATAPATH_FW_VERSION);
380
381		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u",
382			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
383			 le32_to_cpu(ver.dwords[2]));
384
385		devlink_info_version_running_put(req,
386						 EFX_DEVLINK_INFO_VERSION_DATAPATH_FW,
387						 buf);
388	}
389}
390
391static void efx_devlink_info_running_v4(struct efx_nic *efx,
392					struct devlink_info_req *req,
393					unsigned int flags, efx_dword_t *outbuf)
394{
395	char buf[EFX_MAX_VERSION_INFO_LEN];
396	union {
397		const __le32 *dwords;
398		const __le16 *words;
399		const char *str;
400	} ver;
401
402	if (flags & BIT(EFX_VER_FLAG(SOC_BOOT_VERSION))) {
403		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
404						GET_VERSION_V4_OUT_SOC_BOOT_VERSION);
405
406		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
407			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
408			 le32_to_cpu(ver.dwords[2]),
409			 le32_to_cpu(ver.dwords[3]));
410
411		devlink_info_version_running_put(req,
412						 EFX_DEVLINK_INFO_VERSION_SOC_BOOT,
413						 buf);
414	}
415
416	if (flags & BIT(EFX_VER_FLAG(SOC_UBOOT_VERSION))) {
417		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
418						GET_VERSION_V4_OUT_SOC_UBOOT_VERSION);
419
420		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
421			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
422			 le32_to_cpu(ver.dwords[2]),
423			 le32_to_cpu(ver.dwords[3]));
424
425		devlink_info_version_running_put(req,
426						 EFX_DEVLINK_INFO_VERSION_SOC_UBOOT,
427						 buf);
428	}
429
430	if (flags & BIT(EFX_VER_FLAG(SOC_MAIN_ROOTFS_VERSION))) {
431		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
432					GET_VERSION_V4_OUT_SOC_MAIN_ROOTFS_VERSION);
433
434		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
435			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
436			 le32_to_cpu(ver.dwords[2]),
437			 le32_to_cpu(ver.dwords[3]));
438
439		devlink_info_version_running_put(req,
440						 EFX_DEVLINK_INFO_VERSION_SOC_MAIN,
441						 buf);
442	}
443
444	if (flags & BIT(EFX_VER_FLAG(SOC_RECOVERY_BUILDROOT_VERSION))) {
445		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
446						GET_VERSION_V4_OUT_SOC_RECOVERY_BUILDROOT_VERSION);
447
448		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
449			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
450			 le32_to_cpu(ver.dwords[2]),
451			 le32_to_cpu(ver.dwords[3]));
452
453		devlink_info_version_running_put(req,
454						 EFX_DEVLINK_INFO_VERSION_SOC_RECOVERY,
455						 buf);
456	}
457
458	if (flags & BIT(EFX_VER_FLAG(SUCFW_VERSION)) &&
459	    ~flags & BIT(EFX_VER_FLAG(SUCFW_EXT_INFO))) {
460		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
461						GET_VERSION_V4_OUT_SUCFW_VERSION);
462
463		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
464			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
465			 le32_to_cpu(ver.dwords[2]),
466			 le32_to_cpu(ver.dwords[3]));
467
468		devlink_info_version_running_put(req,
469						 EFX_DEVLINK_INFO_VERSION_FW_MGMT_SUC,
470						 buf);
471	}
472}
473
474static void efx_devlink_info_running_v5(struct efx_nic *efx,
475					struct devlink_info_req *req,
476					unsigned int flags, efx_dword_t *outbuf)
477{
478	char buf[EFX_MAX_VERSION_INFO_LEN];
479	union {
480		const __le32 *dwords;
481		const __le16 *words;
482		const char *str;
483	} ver;
484
485	if (flags & BIT(EFX_VER_FLAG(BOARD_VERSION))) {
486		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
487						GET_VERSION_V5_OUT_BOARD_VERSION);
488
489		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
490			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
491			 le32_to_cpu(ver.dwords[2]),
492			 le32_to_cpu(ver.dwords[3]));
493
494		devlink_info_version_running_put(req,
495						 DEVLINK_INFO_VERSION_GENERIC_BOARD_REV,
496						 buf);
497	}
498
499	if (flags & BIT(EFX_VER_FLAG(BUNDLE_VERSION))) {
500		ver.dwords = (__le32 *)MCDI_PTR(outbuf,
501						GET_VERSION_V5_OUT_BUNDLE_VERSION);
502
503		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
504			 le32_to_cpu(ver.dwords[0]), le32_to_cpu(ver.dwords[1]),
505			 le32_to_cpu(ver.dwords[2]),
506			 le32_to_cpu(ver.dwords[3]));
507
508		devlink_info_version_running_put(req,
509						 DEVLINK_INFO_VERSION_GENERIC_FW_BUNDLE_ID,
510						 buf);
511	}
512}
513
514static int efx_devlink_info_running_versions(struct efx_nic *efx,
515					     struct devlink_info_req *req)
516{
517	MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_VERSION_V5_OUT_LEN);
518	MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_VERSION_EXT_IN_LEN);
519	char buf[EFX_MAX_VERSION_INFO_LEN];
520	union {
521		const __le32 *dwords;
522		const __le16 *words;
523		const char *str;
524	} ver;
525	size_t outlength;
526	unsigned int flags;
527	int rc;
528
529	rc = efx_mcdi_rpc(efx, MC_CMD_GET_VERSION, inbuf, sizeof(inbuf),
530			  outbuf, sizeof(outbuf), &outlength);
531	if (rc || outlength < MC_CMD_GET_VERSION_OUT_LEN) {
532		netif_err(efx, drv, efx->net_dev,
533			  "mcdi MC_CMD_GET_VERSION failed\n");
534		return rc;
535	}
536
537	/* Handle previous output */
538	if (outlength < MC_CMD_GET_VERSION_V2_OUT_LEN) {
539		ver.words = (__le16 *)MCDI_PTR(outbuf,
540					       GET_VERSION_EXT_OUT_VERSION);
541		snprintf(buf, EFX_MAX_VERSION_INFO_LEN, "%u.%u.%u.%u",
542			 le16_to_cpu(ver.words[0]),
543			 le16_to_cpu(ver.words[1]),
544			 le16_to_cpu(ver.words[2]),
545			 le16_to_cpu(ver.words[3]));
546
547		devlink_info_version_running_put(req,
548						 DEVLINK_INFO_VERSION_GENERIC_FW_MGMT,
549						 buf);
550		return 0;
551	}
552
553	/* Handle V2 additions */
554	flags = MCDI_DWORD(outbuf, GET_VERSION_V2_OUT_FLAGS);
555	efx_devlink_info_running_v2(efx, req, flags, outbuf);
556
557	if (outlength < MC_CMD_GET_VERSION_V3_OUT_LEN)
558		return 0;
559
560	/* Handle V3 additions */
561	efx_devlink_info_running_v3(efx, req, flags, outbuf);
562
563	if (outlength < MC_CMD_GET_VERSION_V4_OUT_LEN)
564		return 0;
565
566	/* Handle V4 additions */
567	efx_devlink_info_running_v4(efx, req, flags, outbuf);
568
569	if (outlength < MC_CMD_GET_VERSION_V5_OUT_LEN)
570		return 0;
571
572	/* Handle V5 additions */
573	efx_devlink_info_running_v5(efx, req, flags, outbuf);
574
575	return 0;
576}
577
578#define EFX_MAX_SERIALNUM_LEN	(ETH_ALEN * 2 + 1)
579
580static int efx_devlink_info_board_cfg(struct efx_nic *efx,
581				      struct devlink_info_req *req)
582{
583	char sn[EFX_MAX_SERIALNUM_LEN];
584	u8 mac_address[ETH_ALEN];
585	int rc;
586
587	rc = efx_mcdi_get_board_cfg(efx, (u8 *)mac_address, NULL, NULL);
588	if (!rc) {
589		snprintf(sn, EFX_MAX_SERIALNUM_LEN, "%pm", mac_address);
590		devlink_info_serial_number_put(req, sn);
591	}
592	return rc;
593}
594
595static int efx_devlink_info_get(struct devlink *devlink,
596				struct devlink_info_req *req,
597				struct netlink_ext_ack *extack)
598{
599	struct efx_devlink *devlink_private = devlink_priv(devlink);
600	struct efx_nic *efx = devlink_private->efx;
601	int err;
602
603	/* Several different MCDI commands are used. We report if errors
604	 * happened through extack. Specific error information via system
605	 * messages inside the calls.
606	 */
607	err = efx_devlink_info_board_cfg(efx, req);
608
609	err |= efx_devlink_info_stored_versions(efx, req);
610
611	err |= efx_devlink_info_running_versions(efx, req);
612
613	if (err)
614		NL_SET_ERR_MSG_MOD(extack, "Errors when getting device info. Check system messages");
615
616	return 0;
617}
618
619static int efx_devlink_flash_update(struct devlink *devlink,
620				    struct devlink_flash_update_params *params,
621				    struct netlink_ext_ack *extack)
622{
623	struct efx_devlink *devlink_private = devlink_priv(devlink);
624	struct efx_nic *efx = devlink_private->efx;
625
626	return efx_reflash_flash_firmware(efx, params->fw, extack);
627}
628
629static const struct devlink_ops sfc_devlink_ops = {
630	.supported_flash_update_params	= 0,
631	.flash_update			= efx_devlink_flash_update,
632	.info_get			= efx_devlink_info_get,
633};
634
635#ifdef CONFIG_SFC_SRIOV
636static struct devlink_port *ef100_set_devlink_port(struct efx_nic *efx, u32 idx)
637{
638	struct mae_mport_desc *mport;
639	u32 id;
640	int rc;
641
642	if (!efx->mae)
643		return NULL;
644
645	if (efx_mae_lookup_mport(efx, idx, &id)) {
646		/* This should not happen. */
647		if (idx == MAE_MPORT_DESC_VF_IDX_NULL)
648			pci_warn_once(efx->pci_dev, "No mport ID found for PF.\n");
649		else
650			pci_warn_once(efx->pci_dev, "No mport ID found for VF %u.\n",
651				      idx);
652		return NULL;
653	}
654
655	mport = efx_mae_get_mport(efx, id);
656	if (!mport) {
657		/* This should not happen. */
658		if (idx == MAE_MPORT_DESC_VF_IDX_NULL)
659			pci_warn_once(efx->pci_dev, "No mport found for PF.\n");
660		else
661			pci_warn_once(efx->pci_dev, "No mport found for VF %u.\n",
662				      idx);
663		return NULL;
664	}
665
666	rc = efx_devlink_add_port(efx, mport);
667	if (rc) {
668		if (idx == MAE_MPORT_DESC_VF_IDX_NULL)
669			pci_warn(efx->pci_dev,
670				 "devlink port creation for PF failed.\n");
671		else
672			pci_warn(efx->pci_dev,
673				 "devlink_port creation for VF %u failed.\n",
674				 idx);
675		return NULL;
676	}
677
678	return &mport->dl_port;
679}
680
681void ef100_rep_set_devlink_port(struct efx_rep *efv)
682{
683	efv->dl_port = ef100_set_devlink_port(efv->parent, efv->idx);
684}
685
686void ef100_pf_set_devlink_port(struct efx_nic *efx)
687{
688	efx->dl_port = ef100_set_devlink_port(efx, MAE_MPORT_DESC_VF_IDX_NULL);
689}
690
691void ef100_rep_unset_devlink_port(struct efx_rep *efv)
692{
693	efx_devlink_del_port(efv->dl_port);
694}
695
696void ef100_pf_unset_devlink_port(struct efx_nic *efx)
697{
698	efx_devlink_del_port(efx->dl_port);
699}
700#endif
701
702void efx_fini_devlink_lock(struct efx_nic *efx)
703{
704	if (efx->devlink)
705		devl_lock(efx->devlink);
706}
707
708void efx_fini_devlink_and_unlock(struct efx_nic *efx)
709{
710	if (efx->devlink) {
711		devl_unregister(efx->devlink);
712		devl_unlock(efx->devlink);
713		devlink_free(efx->devlink);
714		efx->devlink = NULL;
715	}
716}
717
718int efx_probe_devlink_and_lock(struct efx_nic *efx)
719{
720	struct efx_devlink *devlink_private;
721
722	if (efx->type->is_vf)
723		return 0;
724
725	efx->devlink = devlink_alloc(&sfc_devlink_ops,
726				     sizeof(struct efx_devlink),
727				     &efx->pci_dev->dev);
728	if (!efx->devlink)
729		return -ENOMEM;
730
731	devl_lock(efx->devlink);
732	devlink_private = devlink_priv(efx->devlink);
733	devlink_private->efx = efx;
734
735	devl_register(efx->devlink);
736
737	return 0;
738}
739
740void efx_probe_devlink_unlock(struct efx_nic *efx)
741{
742	if (!efx->devlink)
743		return;
744
745	devl_unlock(efx->devlink);
746}
~/ Read-only file preview.