File Index
Files and directories
Sign in
FILE

fbnic_devlink.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/meta/fbnic/fbnic_devlink.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) Meta Platforms, Inc. and affiliates. */
  3
  4#include <linux/unaligned.h>
  5#include <linux/pci.h>
  6#include <linux/pldmfw.h>
  7#include <linux/types.h>
  8#include <net/devlink.h>
  9
 10#include "fbnic.h"
 11#include "fbnic_fw.h"
 12#include "fbnic_tlv.h"
 13
 14#define FBNIC_SN_STR_LEN	24
 15
 16static int fbnic_version_running_put(struct devlink_info_req *req,
 17				     struct fbnic_fw_ver *fw_ver,
 18				     char *ver_name)
 19{
 20	char running_ver[FBNIC_FW_VER_MAX_SIZE];
 21	int err;
 22
 23	fbnic_mk_fw_ver_str(fw_ver->version, running_ver);
 24	err = devlink_info_version_running_put(req, ver_name, running_ver);
 25	if (err)
 26		return err;
 27
 28	if (strlen(fw_ver->commit) > 0) {
 29		char commit_name[FBNIC_SN_STR_LEN];
 30
 31		snprintf(commit_name, FBNIC_SN_STR_LEN, "%s.commit", ver_name);
 32		err = devlink_info_version_running_put(req, commit_name,
 33						       fw_ver->commit);
 34		if (err)
 35			return err;
 36	}
 37
 38	return 0;
 39}
 40
 41static int fbnic_version_stored_put(struct devlink_info_req *req,
 42				    struct fbnic_fw_ver *fw_ver,
 43				    char *ver_name)
 44{
 45	char stored_ver[FBNIC_FW_VER_MAX_SIZE];
 46	int err;
 47
 48	fbnic_mk_fw_ver_str(fw_ver->version, stored_ver);
 49	err = devlink_info_version_stored_put(req, ver_name, stored_ver);
 50	if (err)
 51		return err;
 52
 53	if (strlen(fw_ver->commit) > 0) {
 54		char commit_name[FBNIC_SN_STR_LEN];
 55
 56		snprintf(commit_name, FBNIC_SN_STR_LEN, "%s.commit", ver_name);
 57		err = devlink_info_version_stored_put(req, commit_name,
 58						      fw_ver->commit);
 59		if (err)
 60			return err;
 61	}
 62
 63	return 0;
 64}
 65
 66static int fbnic_devlink_info_get(struct devlink *devlink,
 67				  struct devlink_info_req *req,
 68				  struct netlink_ext_ack *extack)
 69{
 70	struct fbnic_dev *fbd = devlink_priv(devlink);
 71	int err;
 72
 73	err = fbnic_version_running_put(req, &fbd->fw_cap.running.mgmt,
 74					DEVLINK_INFO_VERSION_GENERIC_FW);
 75	if (err)
 76		return err;
 77
 78	err = fbnic_version_running_put(req, &fbd->fw_cap.running.bootloader,
 79					DEVLINK_INFO_VERSION_GENERIC_FW_BOOTLOADER);
 80	if (err)
 81		return err;
 82
 83	err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.mgmt,
 84				       DEVLINK_INFO_VERSION_GENERIC_FW);
 85	if (err)
 86		return err;
 87
 88	err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.bootloader,
 89				       DEVLINK_INFO_VERSION_GENERIC_FW_BOOTLOADER);
 90	if (err)
 91		return err;
 92
 93	err = fbnic_version_stored_put(req, &fbd->fw_cap.stored.undi,
 94				       DEVLINK_INFO_VERSION_GENERIC_FW_UNDI);
 95	if (err)
 96		return err;
 97
 98	if (fbd->dsn) {
 99		unsigned char serial[FBNIC_SN_STR_LEN];
100		u8 dsn[8];
101
102		put_unaligned_be64(fbd->dsn, dsn);
103		err = snprintf(serial, FBNIC_SN_STR_LEN, "%8phD", dsn);
104		if (err < 0)
105			return err;
106
107		err = devlink_info_serial_number_put(req, serial);
108		if (err)
109			return err;
110	}
111
112	return 0;
113}
114
115static bool
116fbnic_pldm_match_record(struct pldmfw *context, struct pldmfw_record *record)
117{
118	struct pldmfw_desc_tlv *desc;
119	u32 anti_rollback_ver = 0;
120	struct devlink *devlink;
121	struct fbnic_dev *fbd;
122	struct pci_dev *pdev;
123
124	/* First, use the standard PCI matching function */
125	if (!pldmfw_op_pci_match_record(context, record))
126		return false;
127
128	pdev = to_pci_dev(context->dev);
129	fbd = pci_get_drvdata(pdev);
130	devlink = priv_to_devlink(fbd);
131
132	/* If PCI match is successful, check for vendor-specific descriptors */
133	list_for_each_entry(desc, &record->descs, entry) {
134		if (desc->type != PLDM_DESC_ID_VENDOR_DEFINED)
135			continue;
136
137		if (desc->size < 21 || desc->data[0] != 1 ||
138		    desc->data[1] != 15)
139			continue;
140
141		if (memcmp(desc->data + 2, "AntiRollbackVer", 15) != 0)
142			continue;
143
144		anti_rollback_ver = get_unaligned_le32(desc->data + 17);
145		break;
146	}
147
148	/* Compare versions and return error if they do not match */
149	if (anti_rollback_ver < fbd->fw_cap.anti_rollback_version) {
150		char buf[128];
151
152		snprintf(buf, sizeof(buf),
153			 "New firmware anti-rollback version (0x%x) is older than device version (0x%x)!",
154			 anti_rollback_ver, fbd->fw_cap.anti_rollback_version);
155		devlink_flash_update_status_notify(devlink, buf,
156						   "Anti-Rollback", 0, 0);
157
158		return false;
159	}
160
161	return true;
162}
163
164static int
165fbnic_flash_start(struct fbnic_dev *fbd, struct pldmfw_component *component)
166{
167	struct fbnic_fw_completion *cmpl;
168	int err;
169
170	cmpl = fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_FW_START_UPGRADE_REQ);
171	if (!cmpl)
172		return -ENOMEM;
173
174	err = fbnic_fw_xmit_fw_start_upgrade(fbd, cmpl,
175					     component->identifier,
176					     component->component_size);
177	if (err)
178		goto cmpl_free;
179
180	/* Wait for firmware to ack firmware upgrade start */
181	if (wait_for_completion_timeout(&cmpl->done, 10 * HZ))
182		err = cmpl->result;
183	else
184		err = -ETIMEDOUT;
185
186	fbnic_mbx_clear_cmpl(fbd, cmpl);
187cmpl_free:
188	fbnic_fw_put_cmpl(cmpl);
189
190	return err;
191}
192
193static int
194fbnic_flash_component(struct pldmfw *context,
195		      struct pldmfw_component *component)
196{
197	const u8 *data = component->component_data;
198	const u32 size = component->component_size;
199	struct fbnic_fw_completion *cmpl;
200	const char *component_name;
201	struct devlink *devlink;
202	struct fbnic_dev *fbd;
203	struct pci_dev *pdev;
204	u32 offset = 0;
205	u32 length = 0;
206	char buf[32];
207	int err;
208
209	pdev = to_pci_dev(context->dev);
210	fbd = pci_get_drvdata(pdev);
211	devlink = priv_to_devlink(fbd);
212
213	switch (component->identifier) {
214	case QSPI_SECTION_CMRT:
215		component_name = "boot1";
216		break;
217	case QSPI_SECTION_CONTROL_FW:
218		component_name = "boot2";
219		break;
220	case QSPI_SECTION_OPTION_ROM:
221		component_name = "option-rom";
222		break;
223	default:
224		snprintf(buf, sizeof(buf), "Unknown component ID %u!",
225			 component->identifier);
226		devlink_flash_update_status_notify(devlink, buf, NULL, 0,
227						   size);
228		return -EINVAL;
229	}
230
231	/* Once firmware receives the request to start upgrading it responds
232	 * with two messages:
233	 * 1. An ACK that it received the message and possible error code
234	 *    indicating that an upgrade is not currently possible.
235	 * 2. A request for the first chunk of data
236	 *
237	 * Setup completions for write before issuing the start message so
238	 * the driver can catch both messages.
239	 */
240	cmpl = fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_FW_WRITE_CHUNK_REQ);
241	if (!cmpl)
242		return -ENOMEM;
243
244	err = fbnic_mbx_set_cmpl(fbd, cmpl);
245	if (err)
246		goto cmpl_free;
247
248	devlink_flash_update_timeout_notify(devlink, "Initializing",
249					    component_name, 15);
250	err = fbnic_flash_start(fbd, component);
251	if (err)
252		goto err_no_msg;
253
254	while (offset < size) {
255		if (!wait_for_completion_timeout(&cmpl->done, 15 * HZ)) {
256			err = -ETIMEDOUT;
257			break;
258		}
259
260		err = cmpl->result;
261		if (err)
262			break;
263
264		/* Verify firmware is requesting the next chunk in the seq. */
265		if (cmpl->u.fw_update.offset != offset + length) {
266			err = -EFAULT;
267			break;
268		}
269
270		offset = cmpl->u.fw_update.offset;
271		length = cmpl->u.fw_update.length;
272
273		if (length > TLV_MAX_DATA || offset + length > size) {
274			err = -EFAULT;
275			break;
276		}
277
278		devlink_flash_update_status_notify(devlink, "Flashing",
279						   component_name,
280						   offset, size);
281
282		/* Mailbox will set length to 0 once it receives the finish
283		 * message.
284		 */
285		if (!length)
286			continue;
287
288		reinit_completion(&cmpl->done);
289		err = fbnic_fw_xmit_fw_write_chunk(fbd, data, offset, length,
290						   0);
291		if (err)
292			break;
293	}
294
295	if (err) {
296		fbnic_fw_xmit_fw_write_chunk(fbd, NULL, 0, 0, err);
297err_no_msg:
298		snprintf(buf, sizeof(buf), "Mailbox encountered error %d!",
299			 err);
300		devlink_flash_update_status_notify(devlink, buf,
301						   component_name, 0, 0);
302	}
303
304	fbnic_mbx_clear_cmpl(fbd, cmpl);
305cmpl_free:
306	fbnic_fw_put_cmpl(cmpl);
307
308	return err;
309}
310
311static const struct pldmfw_ops fbnic_pldmfw_ops = {
312	.match_record = fbnic_pldm_match_record,
313	.flash_component = fbnic_flash_component,
314};
315
316static int
317fbnic_devlink_flash_update(struct devlink *devlink,
318			   struct devlink_flash_update_params *params,
319			   struct netlink_ext_ack *extack)
320{
321	struct fbnic_dev *fbd = devlink_priv(devlink);
322	const struct firmware *fw = params->fw;
323	struct device *dev = fbd->dev;
324	struct pldmfw context;
325	char *err_msg;
326	int err;
327
328	context.ops = &fbnic_pldmfw_ops;
329	context.dev = dev;
330
331	err = pldmfw_flash_image(&context, fw);
332	if (err) {
333		switch (err) {
334		case -EINVAL:
335			err_msg = "Invalid image";
336			break;
337		case -EOPNOTSUPP:
338			err_msg = "Unsupported image";
339			break;
340		case -ENOMEM:
341			err_msg = "Out of memory";
342			break;
343		case -EFAULT:
344			err_msg = "Invalid header";
345			break;
346		case -ENOENT:
347			err_msg = "No matching record";
348			break;
349		case -ENODEV:
350			err_msg = "No matching device";
351			break;
352		case -ETIMEDOUT:
353			err_msg = "Timed out waiting for reply";
354			break;
355		default:
356			err_msg = "Unknown error";
357			break;
358		}
359
360		NL_SET_ERR_MSG_FMT_MOD(extack,
361				       "Failed to flash PLDM Image: %s (error: %d)",
362				       err_msg, err);
363	}
364
365	return err;
366}
367
368static const struct devlink_ops fbnic_devlink_ops = {
369	.info_get	= fbnic_devlink_info_get,
370	.flash_update	= fbnic_devlink_flash_update,
371};
372
373static int fbnic_fw_reporter_dump(struct devlink_health_reporter *reporter,
374				  struct devlink_fmsg *fmsg, void *priv_ctx,
375				  struct netlink_ext_ack *extack)
376{
377	struct fbnic_dev *fbd = devlink_health_reporter_priv(reporter);
378	u32 offset, index, index_count, length, size;
379	struct fbnic_fw_completion *fw_cmpl;
380	u8 *dump_data, **data;
381	int err;
382
383	fw_cmpl = fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_COREDUMP_GET_INFO_RESP);
384	if (!fw_cmpl)
385		return -ENOMEM;
386
387	err = fbnic_fw_xmit_coredump_info_msg(fbd, fw_cmpl, true);
388	if (err) {
389		NL_SET_ERR_MSG_MOD(extack,
390				   "Failed to transmit core dump info msg");
391		goto cmpl_free;
392	}
393	if (!wait_for_completion_timeout(&fw_cmpl->done, 2 * HZ)) {
394		NL_SET_ERR_MSG_MOD(extack,
395				   "Timed out waiting on core dump info");
396		err = -ETIMEDOUT;
397		goto cmpl_cleanup;
398	}
399
400	size = fw_cmpl->u.coredump_info.size;
401	err = fw_cmpl->result;
402
403	fbnic_mbx_clear_cmpl(fbd, fw_cmpl);
404	fbnic_fw_put_cmpl(fw_cmpl);
405
406	/* Handle error returned by firmware */
407	if (err) {
408		NL_SET_ERR_MSG_MOD(extack, "Firmware core dump returned error");
409		return err;
410	}
411	if (!size) {
412		NL_SET_ERR_MSG_MOD(extack,
413				   "Firmware core dump returned size 0");
414		return -EIO;
415	}
416
417	/* Read the dump, we can only transfer TLV_MAX_DATA at a time */
418	index_count = DIV_ROUND_UP(size, TLV_MAX_DATA);
419
420	fw_cmpl = __fbnic_fw_alloc_cmpl(FBNIC_TLV_MSG_ID_COREDUMP_READ_RESP,
421					sizeof(void *) * index_count + size);
422	if (!fw_cmpl)
423		return -ENOMEM;
424
425	/* Populate pointer table w/ pointer offsets */
426	dump_data = (void *)&fw_cmpl->u.coredump.data[index_count];
427	data = fw_cmpl->u.coredump.data;
428	fw_cmpl->u.coredump.size = size;
429	fw_cmpl->u.coredump.stride = TLV_MAX_DATA;
430
431	for (index = 0; index < index_count; index++) {
432		/* First iteration installs completion */
433		struct fbnic_fw_completion *cmpl_arg = index ? NULL : fw_cmpl;
434
435		offset = index * TLV_MAX_DATA;
436		length = min(size - offset, TLV_MAX_DATA);
437
438		data[index] = dump_data + offset;
439		err = fbnic_fw_xmit_coredump_read_msg(fbd, cmpl_arg,
440						      offset, length);
441		if (err) {
442			NL_SET_ERR_MSG_MOD(extack,
443					   "Failed to transmit core dump msg");
444			if (cmpl_arg)
445				goto cmpl_free;
446			else
447				goto cmpl_cleanup;
448		}
449
450		if (wait_for_completion_timeout(&fw_cmpl->done, 2 * HZ)) {
451			reinit_completion(&fw_cmpl->done);
452		} else {
453			NL_SET_ERR_MSG_FMT_MOD(extack,
454					       "Timed out waiting on core dump (%d/%d)",
455					       index + 1, index_count);
456			err = -ETIMEDOUT;
457			goto cmpl_cleanup;
458		}
459
460		/* If we didn't see the reply record as incomplete */
461		if (fw_cmpl->u.coredump.data[index]) {
462			NL_SET_ERR_MSG_FMT_MOD(extack,
463					       "No data for core dump chunk (%d/%d)",
464					       index + 1, index_count);
465			err = -EIO;
466			goto cmpl_cleanup;
467		}
468	}
469
470	devlink_fmsg_binary_pair_nest_start(fmsg, "FW coredump");
471
472	for (offset = 0; offset < size; offset += length) {
473		length = min_t(u32, size - offset, TLV_MAX_DATA);
474
475		devlink_fmsg_binary_put(fmsg, dump_data + offset, length);
476	}
477
478	devlink_fmsg_binary_pair_nest_end(fmsg);
479
480cmpl_cleanup:
481	fbnic_mbx_clear_cmpl(fbd, fw_cmpl);
482cmpl_free:
483	fbnic_fw_put_cmpl(fw_cmpl);
484
485	return err;
486}
487
488static int
489fbnic_fw_reporter_diagnose(struct devlink_health_reporter *reporter,
490			   struct devlink_fmsg *fmsg,
491			   struct netlink_ext_ack *extack)
492{
493	struct fbnic_dev *fbd = devlink_health_reporter_priv(reporter);
494	u32 sec, msec;
495
496	/* Device is most likely down, we're not exchanging heartbeats */
497	if (!fbd->prev_firmware_time)
498		return 0;
499
500	sec = div_u64_rem(fbd->firmware_time, MSEC_PER_SEC, &msec);
501
502	devlink_fmsg_pair_nest_start(fmsg, "last_heartbeat");
503	devlink_fmsg_obj_nest_start(fmsg);
504	devlink_fmsg_pair_nest_start(fmsg, "fw_uptime");
505	devlink_fmsg_obj_nest_start(fmsg);
506	devlink_fmsg_u32_pair_put(fmsg, "sec", sec);
507	devlink_fmsg_u32_pair_put(fmsg, "msec", msec);
508	devlink_fmsg_obj_nest_end(fmsg);
509	devlink_fmsg_pair_nest_end(fmsg);
510	devlink_fmsg_obj_nest_end(fmsg);
511	devlink_fmsg_pair_nest_end(fmsg);
512
513	return 0;
514}
515
516void __printf(2, 3)
517fbnic_devlink_fw_report(struct fbnic_dev *fbd, const char *format, ...)
518{
519	char msg[FBNIC_FW_LOG_MAX_SIZE];
520	va_list args;
521
522	va_start(args, format);
523	vsnprintf(msg, FBNIC_FW_LOG_MAX_SIZE, format, args);
524	va_end(args);
525
526	devlink_health_report(fbd->fw_reporter, msg, fbd);
527	if (fbnic_fw_log_ready(fbd))
528		fbnic_fw_log_write(fbd, 0, fbd->firmware_time, msg);
529}
530
531static const struct devlink_health_reporter_ops fbnic_fw_ops = {
532	.name = "fw",
533	.dump = fbnic_fw_reporter_dump,
534	.diagnose = fbnic_fw_reporter_diagnose,
535};
536
537static u32 fbnic_read_otp_status(struct fbnic_dev *fbd)
538{
539	return fbnic_fw_rd32(fbd, FBNIC_NS_OTP_STATUS);
540}
541
542static int
543fbnic_otp_reporter_dump(struct devlink_health_reporter *reporter,
544			struct devlink_fmsg *fmsg, void *priv_ctx,
545			struct netlink_ext_ack *extack)
546{
547	struct fbnic_dev *fbd = devlink_health_reporter_priv(reporter);
548	u32 otp_status, otp_write_status, m;
549
550	otp_status = fbnic_read_otp_status(fbd);
551	otp_write_status = fbnic_fw_rd32(fbd, FBNIC_NS_OTP_WRITE_STATUS);
552
553	/* Dump OTP status */
554	devlink_fmsg_pair_nest_start(fmsg, "OTP");
555	devlink_fmsg_obj_nest_start(fmsg);
556
557	devlink_fmsg_u32_pair_put(fmsg, "Status", otp_status);
558
559	/* Extract OTP Write Data status */
560	m = FBNIC_NS_OTP_WRITE_DATA_STATUS_MASK;
561	devlink_fmsg_u32_pair_put(fmsg, "Data",
562				  FIELD_GET(m, otp_write_status));
563
564	/* Extract OTP Write ECC status */
565	m = FBNIC_NS_OTP_WRITE_ECC_STATUS_MASK;
566	devlink_fmsg_u32_pair_put(fmsg, "ECC",
567				  FIELD_GET(m, otp_write_status));
568
569	devlink_fmsg_obj_nest_end(fmsg);
570	devlink_fmsg_pair_nest_end(fmsg);
571
572	return 0;
573}
574
575void fbnic_devlink_otp_check(struct fbnic_dev *fbd, const char *msg)
576{
577	/* Check if there is anything to report */
578	if (!fbnic_read_otp_status(fbd))
579		return;
580
581	devlink_health_report(fbd->otp_reporter, msg, fbd);
582	if (fbnic_fw_log_ready(fbd))
583		fbnic_fw_log_write(fbd, 0, fbd->firmware_time, msg);
584}
585
586static const struct devlink_health_reporter_ops fbnic_otp_ops = {
587	.name = "otp",
588	.dump = fbnic_otp_reporter_dump,
589};
590
591int fbnic_devlink_health_create(struct fbnic_dev *fbd)
592{
593	fbd->fw_reporter = devlink_health_reporter_create(priv_to_devlink(fbd),
594							  &fbnic_fw_ops, fbd);
595	if (IS_ERR(fbd->fw_reporter)) {
596		dev_warn(fbd->dev,
597			 "Failed to create FW fault reporter: %pe\n",
598			 fbd->fw_reporter);
599		return PTR_ERR(fbd->fw_reporter);
600	}
601
602	fbd->otp_reporter = devlink_health_reporter_create(priv_to_devlink(fbd),
603							   &fbnic_otp_ops, fbd);
604	if (IS_ERR(fbd->otp_reporter)) {
605		devlink_health_reporter_destroy(fbd->fw_reporter);
606		dev_warn(fbd->dev,
607			 "Failed to create OTP fault reporter: %pe\n",
608			 fbd->otp_reporter);
609		return PTR_ERR(fbd->otp_reporter);
610	}
611
612	return 0;
613}
614
615void fbnic_devlink_health_destroy(struct fbnic_dev *fbd)
616{
617	devlink_health_reporter_destroy(fbd->otp_reporter);
618	devlink_health_reporter_destroy(fbd->fw_reporter);
619}
620
621void fbnic_devlink_free(struct fbnic_dev *fbd)
622{
623	struct devlink *devlink = priv_to_devlink(fbd);
624
625	devlink_free(devlink);
626}
627
628struct fbnic_dev *fbnic_devlink_alloc(struct pci_dev *pdev)
629{
630	void __iomem * const *iomap_table;
631	struct devlink *devlink;
632	struct fbnic_dev *fbd;
633
634	devlink = devlink_alloc(&fbnic_devlink_ops, sizeof(struct fbnic_dev),
635				&pdev->dev);
636	if (!devlink)
637		return NULL;
638
639	fbd = devlink_priv(devlink);
640	pci_set_drvdata(pdev, fbd);
641	fbd->dev = &pdev->dev;
642
643	iomap_table = pcim_iomap_table(pdev);
644	fbd->uc_addr0 = iomap_table[0];
645	fbd->uc_addr4 = iomap_table[4];
646
647	fbd->dsn = pci_get_dsn(pdev);
648	fbd->mps = pcie_get_mps(pdev);
649	fbd->readrq = pcie_get_readrq(pdev);
650
651	fbd->mac_addr_boundary = FBNIC_RPC_TCAM_MACDA_DEFAULT_BOUNDARY;
652
653	return fbd;
654}
655
656void fbnic_devlink_register(struct fbnic_dev *fbd)
657{
658	struct devlink *devlink = priv_to_devlink(fbd);
659
660	devlink_register(devlink);
661}
662
663void fbnic_devlink_unregister(struct fbnic_dev *fbd)
664{
665	struct devlink *devlink = priv_to_devlink(fbd);
666
667	devlink_unregister(devlink);
668}
~/ Read-only file preview.