mirror of
https://github.com/torvalds/linux.git
synced 2026-05-29 17:43:52 +02:00
eth: fbnic: Add mailbox support for firmware logs
By default firmware will not send logs to the host. This must be explicitly
enabled by the driver. The mailbox has the concept of a flag which is a u32
used as a boolean. Lack of flag defaults to a value of false. When enabling
logging historical logs may be optionally requested. These are log messages
generated by the NIC before the driver was loaded. The driver also sends a
log version to support changing the logging format in the future.
[SEND_LOGS_REQ] = {
[SEND_LOGS] /* flag to request log reporting */
[SEND_LOGS_HISTORY] /* flag to request historical logs */
[SEND_LOGS_VERSION] /* u32 indicating the log format version */
}
Logs may be sent to the user either one at a time, or when historical logs
are requested in bulk. Firmware may not send more than 14 messages in bulk
to prevent flooding the mailbox.
[LOG_MSG] = {
[LOG_INDEX] /* entry 0 - u64 index of log */
[LOG_MSEC] /* entry 0 - u32 timestamp of log */
[LOG_MSG] /* entry 0 - char log message up to 256 */
[LOG_LENGTH] /* u32 of remaining log items in arrays */
[LOG_INDEX_ARRAY] = {
[LOG_INDEX] /* entry 1 - u64 index of log */
[LOG_INDEX] /* entry 2 - u64 index of log */
...
}
[LOG_MSEC_ARRAY] = {
[LOG_MSEC] /* entry 1 - u32 timestamp of log */
[LOG_MSEC] /* entry 2 - u32 timestamp of log */
...
}
[LOG_MSG_ARRAY] = {
[LOG_MSG] /* entry 1 - char log message up to 256 */
[LOG_MSG] /* entry 2 - char log message up to 256 */
...
}
}
Signed-off-by: Lee Trager <lee@trager.us>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Link: https://patch.msgid.link/20250702192207.697368-5-lee@trager.us
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
c2b93d6bec
commit
2e972f32ae
|
|
@ -21,6 +21,20 @@
|
|||
/* Defines the minimum firmware version required by the driver */
|
||||
#define MIN_FW_VER_CODE FW_VER_CODE(0, 10, 6, 0)
|
||||
|
||||
/* Defines the minimum firmware version required for firmware logs */
|
||||
#define MIN_FW_VER_CODE_LOG FW_VER_CODE(0, 12, 9, 0)
|
||||
|
||||
/* Driver can request that firmware sends all cached logs in bulk. This
|
||||
* feature was enabled on older firmware however firmware has a bug
|
||||
* which attempted to send 30 messages per mbx message which caused an
|
||||
* overflow flooding the mailbox. This results in a kernel warning
|
||||
* related to corrupt mailbox messages.
|
||||
*
|
||||
* If firmware is new enough only request sending historical logs when
|
||||
* the log buffer is empty to prevent duplicate logs.
|
||||
*/
|
||||
#define MIN_FW_VER_CODE_HIST FW_VER_CODE(25, 5, 7, 0)
|
||||
|
||||
#define PCI_DEVICE_ID_META_FBNIC_ASIC 0x0013
|
||||
|
||||
#define FBNIC_CLOCK_FREQ (600 * (1000 * 1000))
|
||||
|
|
|
|||
|
|
@ -1034,6 +1034,169 @@ static int fbnic_fw_parse_tsene_read_resp(void *opaque,
|
|||
return err;
|
||||
}
|
||||
|
||||
static const struct fbnic_tlv_index fbnic_fw_log_req_index[] = {
|
||||
FBNIC_TLV_ATTR_U32(FBNIC_FW_LOG_MSEC),
|
||||
FBNIC_TLV_ATTR_U64(FBNIC_FW_LOG_INDEX),
|
||||
FBNIC_TLV_ATTR_STRING(FBNIC_FW_LOG_MSG, FBNIC_FW_LOG_MAX_SIZE),
|
||||
FBNIC_TLV_ATTR_U32(FBNIC_FW_LOG_LENGTH),
|
||||
FBNIC_TLV_ATTR_ARRAY(FBNIC_FW_LOG_MSEC_ARRAY),
|
||||
FBNIC_TLV_ATTR_ARRAY(FBNIC_FW_LOG_INDEX_ARRAY),
|
||||
FBNIC_TLV_ATTR_ARRAY(FBNIC_FW_LOG_MSG_ARRAY),
|
||||
FBNIC_TLV_ATTR_LAST
|
||||
};
|
||||
|
||||
static int fbnic_fw_process_log_array(struct fbnic_tlv_msg **results,
|
||||
u16 length, u16 arr_type_idx,
|
||||
u16 attr_type_idx,
|
||||
struct fbnic_tlv_msg **tlv_array_out)
|
||||
{
|
||||
struct fbnic_tlv_msg *attr;
|
||||
int attr_len;
|
||||
int err;
|
||||
|
||||
if (!results[attr_type_idx])
|
||||
return -EINVAL;
|
||||
|
||||
tlv_array_out[0] = results[attr_type_idx];
|
||||
|
||||
if (!length)
|
||||
return 0;
|
||||
|
||||
if (!results[arr_type_idx])
|
||||
return -EINVAL;
|
||||
|
||||
attr = results[arr_type_idx];
|
||||
attr_len = le16_to_cpu(attr->hdr.len) / sizeof(u32) - 1;
|
||||
err = fbnic_tlv_attr_parse_array(&attr[1], attr_len, &tlv_array_out[1],
|
||||
fbnic_fw_log_req_index,
|
||||
attr_type_idx,
|
||||
length);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fbnic_fw_parse_logs(struct fbnic_dev *fbd,
|
||||
struct fbnic_tlv_msg **msec_tlv,
|
||||
struct fbnic_tlv_msg **index_tlv,
|
||||
struct fbnic_tlv_msg **log_tlv,
|
||||
int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
char log[FBNIC_FW_LOG_MAX_SIZE];
|
||||
ssize_t len;
|
||||
u64 index;
|
||||
u32 msec;
|
||||
int err;
|
||||
|
||||
if (!msec_tlv[i] || !index_tlv[i] || !log_tlv[i]) {
|
||||
dev_warn(fbd->dev, "Received log message with missing attributes!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
index = fbnic_tlv_attr_get_signed(index_tlv[i], 0);
|
||||
msec = fbnic_tlv_attr_get_signed(msec_tlv[i], 0);
|
||||
len = fbnic_tlv_attr_get_string(log_tlv[i], log,
|
||||
FBNIC_FW_LOG_MAX_SIZE);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
err = fbnic_fw_log_write(fbd, index, msec, log);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fbnic_fw_parse_log_req(void *opaque,
|
||||
struct fbnic_tlv_msg **results)
|
||||
{
|
||||
struct fbnic_tlv_msg *index_tlv[FBNIC_FW_MAX_LOG_HISTORY];
|
||||
struct fbnic_tlv_msg *msec_tlv[FBNIC_FW_MAX_LOG_HISTORY];
|
||||
struct fbnic_tlv_msg *log_tlv[FBNIC_FW_MAX_LOG_HISTORY];
|
||||
struct fbnic_dev *fbd = opaque;
|
||||
u16 length;
|
||||
int err;
|
||||
|
||||
length = fta_get_uint(results, FBNIC_FW_LOG_LENGTH);
|
||||
if (length >= FBNIC_FW_MAX_LOG_HISTORY)
|
||||
return -E2BIG;
|
||||
|
||||
err = fbnic_fw_process_log_array(results, length,
|
||||
FBNIC_FW_LOG_MSEC_ARRAY,
|
||||
FBNIC_FW_LOG_MSEC, msec_tlv);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fbnic_fw_process_log_array(results, length,
|
||||
FBNIC_FW_LOG_INDEX_ARRAY,
|
||||
FBNIC_FW_LOG_INDEX, index_tlv);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fbnic_fw_process_log_array(results, length,
|
||||
FBNIC_FW_LOG_MSG_ARRAY,
|
||||
FBNIC_FW_LOG_MSG, log_tlv);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = fbnic_fw_parse_logs(fbd, msec_tlv, index_tlv, log_tlv,
|
||||
length + 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fbnic_fw_xmit_send_logs(struct fbnic_dev *fbd, bool enable,
|
||||
bool send_log_history)
|
||||
{
|
||||
struct fbnic_tlv_msg *msg;
|
||||
int err;
|
||||
|
||||
if (fbd->fw_cap.running.mgmt.version < MIN_FW_VER_CODE_LOG) {
|
||||
dev_warn(fbd->dev, "Firmware version is too old to support firmware logs!\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
msg = fbnic_tlv_msg_alloc(FBNIC_TLV_MSG_ID_LOG_SEND_LOGS_REQ);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
if (enable) {
|
||||
err = fbnic_tlv_attr_put_flag(msg, FBNIC_SEND_LOGS);
|
||||
if (err)
|
||||
goto free_message;
|
||||
|
||||
/* Report request for version 1 of logs */
|
||||
err = fbnic_tlv_attr_put_int(msg, FBNIC_SEND_LOGS_VERSION,
|
||||
FBNIC_FW_LOG_VERSION);
|
||||
if (err)
|
||||
goto free_message;
|
||||
|
||||
if (send_log_history) {
|
||||
err = fbnic_tlv_attr_put_flag(msg,
|
||||
FBNIC_SEND_LOGS_HISTORY);
|
||||
if (err)
|
||||
goto free_message;
|
||||
}
|
||||
}
|
||||
|
||||
err = fbnic_mbx_map_tlv_msg(fbd, msg);
|
||||
if (err)
|
||||
goto free_message;
|
||||
|
||||
return 0;
|
||||
|
||||
free_message:
|
||||
free_page((unsigned long)msg);
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct fbnic_tlv_parser fbnic_fw_tlv_parser[] = {
|
||||
FBNIC_TLV_PARSER(FW_CAP_RESP, fbnic_fw_cap_resp_index,
|
||||
fbnic_fw_parse_cap_resp),
|
||||
|
|
@ -1053,6 +1216,9 @@ static const struct fbnic_tlv_parser fbnic_fw_tlv_parser[] = {
|
|||
FBNIC_TLV_PARSER(TSENE_READ_RESP,
|
||||
fbnic_tsene_read_resp_index,
|
||||
fbnic_fw_parse_tsene_read_resp),
|
||||
FBNIC_TLV_PARSER(LOG_MSG_REQ,
|
||||
fbnic_fw_log_req_index,
|
||||
fbnic_fw_parse_log_req),
|
||||
FBNIC_TLV_MSG_ERROR
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,20 @@ struct fbnic_fw_mbx {
|
|||
#define FBNIC_FW_VER_MAX_SIZE 32
|
||||
// Formatted version is in the format XX.YY.ZZ_RRR_COMMIT
|
||||
#define FBNIC_FW_CAP_RESP_COMMIT_MAX_SIZE (FBNIC_FW_VER_MAX_SIZE - 13)
|
||||
#define FBNIC_FW_LOG_VERSION 1
|
||||
#define FBNIC_FW_LOG_MAX_SIZE 256
|
||||
/*
|
||||
* The max amount of logs which can fit in a single mailbox message. Firmware
|
||||
* assumes each mailbox message is 4096B. The amount of messages supported is
|
||||
* calculated as 4096 minus headers for message, arrays, and length minus the
|
||||
* size of length divided by headers for each array plus the maximum LOG size,
|
||||
* and the size of MSEC and INDEX. Put another way:
|
||||
*
|
||||
* MAX_LOG_HISTORY = ((4096 - TLV_HDR_SZ * 5 - LENGTH_SZ)
|
||||
* / (FBNIC_FW_LOG_MAX_SIZE + TLV_HDR_SZ * 3 + MSEC_SZ
|
||||
* + INDEX_SZ))
|
||||
*/
|
||||
#define FBNIC_FW_MAX_LOG_HISTORY 14
|
||||
|
||||
struct fbnic_fw_ver {
|
||||
u32 version;
|
||||
|
|
@ -82,6 +95,8 @@ int fbnic_fw_xmit_fw_write_chunk(struct fbnic_dev *fbd,
|
|||
int cancel_error);
|
||||
int fbnic_fw_xmit_tsene_read_msg(struct fbnic_dev *fbd,
|
||||
struct fbnic_fw_completion *cmpl_data);
|
||||
int fbnic_fw_xmit_send_logs(struct fbnic_dev *fbd, bool enable,
|
||||
bool send_log_history);
|
||||
struct fbnic_fw_completion *fbnic_fw_alloc_cmpl(u32 msg_type);
|
||||
void fbnic_fw_put_cmpl(struct fbnic_fw_completion *cmpl_data);
|
||||
|
||||
|
|
@ -125,6 +140,9 @@ enum {
|
|||
FBNIC_TLV_MSG_ID_FW_FINISH_UPGRADE_RESP = 0x29,
|
||||
FBNIC_TLV_MSG_ID_TSENE_READ_REQ = 0x3C,
|
||||
FBNIC_TLV_MSG_ID_TSENE_READ_RESP = 0x3D,
|
||||
FBNIC_TLV_MSG_ID_LOG_SEND_LOGS_REQ = 0x43,
|
||||
FBNIC_TLV_MSG_ID_LOG_MSG_REQ = 0x44,
|
||||
FBNIC_TLV_MSG_ID_LOG_MSG_RESP = 0x45,
|
||||
};
|
||||
|
||||
#define FBNIC_FW_CAP_RESP_VERSION_MAJOR CSR_GENMASK(31, 24)
|
||||
|
|
@ -199,4 +217,22 @@ enum {
|
|||
FBNIC_FW_FINISH_UPGRADE_MSG_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
FBNIC_SEND_LOGS = 0x0,
|
||||
FBNIC_SEND_LOGS_VERSION = 0x1,
|
||||
FBNIC_SEND_LOGS_HISTORY = 0x2,
|
||||
FBNIC_SEND_LOGS_MSG_MAX
|
||||
};
|
||||
|
||||
enum {
|
||||
FBNIC_FW_LOG_MSEC = 0x0,
|
||||
FBNIC_FW_LOG_INDEX = 0x1,
|
||||
FBNIC_FW_LOG_MSG = 0x2,
|
||||
FBNIC_FW_LOG_LENGTH = 0x3,
|
||||
FBNIC_FW_LOG_MSEC_ARRAY = 0x4,
|
||||
FBNIC_FW_LOG_INDEX_ARRAY = 0x5,
|
||||
FBNIC_FW_LOG_MSG_ARRAY = 0x6,
|
||||
FBNIC_FW_LOG_MSG_MAX
|
||||
};
|
||||
|
||||
#endif /* _FBNIC_FW_H_ */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user