FILE
fbnic_fw_log.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/meta/fbnic/fbnic_fw_log.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.