File Index
Files and directories
Sign in
FILE

fbnic_fw_log.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/meta/fbnic/fbnic_fw_log.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) Meta Platforms, Inc. and affiliates. */
  3
  4#include <linux/spinlock.h>
  5#include <linux/vmalloc.h>
  6
  7#include "fbnic.h"
  8#include "fbnic_fw.h"
  9#include "fbnic_fw_log.h"
 10
 11void fbnic_fw_log_enable(struct fbnic_dev *fbd, bool send_hist)
 12{
 13	int err;
 14
 15	if (!fbnic_fw_log_ready(fbd))
 16		return;
 17
 18	if (fbd->fw_cap.running.mgmt.version < MIN_FW_VER_CODE_HIST)
 19		send_hist = false;
 20
 21	err = fbnic_fw_xmit_send_logs(fbd, true, send_hist);
 22	if (err && err != -EOPNOTSUPP)
 23		dev_warn(fbd->dev, "Unable to enable firmware logs: %d\n", err);
 24}
 25
 26void fbnic_fw_log_disable(struct fbnic_dev *fbd)
 27{
 28	int err;
 29
 30	err = fbnic_fw_xmit_send_logs(fbd, false, false);
 31	if (err && err != -EOPNOTSUPP)
 32		dev_warn(fbd->dev, "Unable to disable firmware logs: %d\n",
 33			 err);
 34}
 35
 36int fbnic_fw_log_init(struct fbnic_dev *fbd)
 37{
 38	struct fbnic_fw_log *log = &fbd->fw_log;
 39	void *data;
 40
 41	if (WARN_ON_ONCE(fbnic_fw_log_ready(fbd)))
 42		return -EEXIST;
 43
 44	data = vmalloc(FBNIC_FW_LOG_SIZE);
 45	if (!data)
 46		return -ENOMEM;
 47
 48	spin_lock_init(&fbd->fw_log.lock);
 49	INIT_LIST_HEAD(&log->entries);
 50	log->size = FBNIC_FW_LOG_SIZE;
 51	log->data_start = data;
 52	log->data_end = data + FBNIC_FW_LOG_SIZE;
 53
 54	return 0;
 55}
 56
 57void fbnic_fw_log_free(struct fbnic_dev *fbd)
 58{
 59	struct fbnic_fw_log *log = &fbd->fw_log;
 60
 61	if (!fbnic_fw_log_ready(fbd))
 62		return;
 63
 64	INIT_LIST_HEAD(&log->entries);
 65	log->size = 0;
 66	vfree(log->data_start);
 67	log->data_start = NULL;
 68	log->data_end = NULL;
 69}
 70
 71int fbnic_fw_log_write(struct fbnic_dev *fbd, u64 index, u32 timestamp,
 72		       const char *msg)
 73{
 74	struct fbnic_fw_log_entry *entry, *head, *tail, *next;
 75	struct fbnic_fw_log *log = &fbd->fw_log;
 76	size_t msg_len = strlen(msg) + 1;
 77	unsigned long flags;
 78	void *entry_end;
 79
 80	if (!fbnic_fw_log_ready(fbd)) {
 81		dev_err(fbd->dev, "Firmware sent log entry without being requested!\n");
 82		return -ENOSPC;
 83	}
 84
 85	spin_lock_irqsave(&log->lock, flags);
 86
 87	if (list_empty(&log->entries)) {
 88		entry = log->data_start;
 89	} else {
 90		head = list_first_entry(&log->entries, typeof(*head), list);
 91		entry_end = head->msg + head->len + 1;
 92		entry = PTR_ALIGN(entry_end, 8);
 93	}
 94
 95	entry_end = entry->msg + msg_len + 1;
 96
 97	/* We've reached the end of the buffer, wrap around */
 98	if (entry_end > log->data_end) {
 99		entry = log->data_start;
100		entry_end = entry->msg + msg_len + 1;
101	}
102
103	/* Make room for entry by removing from tail. */
104	list_for_each_entry_safe_reverse(tail, next, &log->entries, list) {
105		if (entry <= tail && entry_end > (void *)tail)
106			list_del(&tail->list);
107		else
108			break;
109	}
110
111	entry->index = index;
112	entry->timestamp = timestamp;
113	entry->len = msg_len;
114	strscpy(entry->msg, msg, entry->len);
115	list_add(&entry->list, &log->entries);
116
117	spin_unlock_irqrestore(&log->lock, flags);
118
119	return 0;
120}
~/ Read-only file preview.