From: Edwin Peer edwin.peer@broadcom.com
[ Upstream commit b032228e58ea2477955058ad4d70a636ce1dec51 ]
Change bnxt_get_coredump() and bnxt_get_coredump_length() to non-static functions.
Signed-off-by: Edwin Peer edwin.peer@broadcom.com Signed-off-by: Michael Chan michael.chan@broadcom.com Signed-off-by: David S. Miller davem@davemloft.net Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/net/ethernet/broadcom/bnxt/Makefile | 2 +- .../ethernet/broadcom/bnxt/bnxt_coredump.c | 372 ++++++++++++++++++ .../ethernet/broadcom/bnxt/bnxt_coredump.h | 51 +++ .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 356 ----------------- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.h | 43 -- 5 files changed, 424 insertions(+), 400 deletions(-) create mode 100644 drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c
diff --git a/drivers/net/ethernet/broadcom/bnxt/Makefile b/drivers/net/ethernet/broadcom/bnxt/Makefile index c6ef7ec2c1151..2bc2b707d6eee 100644 --- a/drivers/net/ethernet/broadcom/bnxt/Makefile +++ b/drivers/net/ethernet/broadcom/bnxt/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_BNXT) += bnxt_en.o
-bnxt_en-y := bnxt.o bnxt_hwrm.o bnxt_sriov.o bnxt_ethtool.o bnxt_dcb.o bnxt_ulp.o bnxt_xdp.o bnxt_ptp.o bnxt_vfr.o bnxt_devlink.o bnxt_dim.o +bnxt_en-y := bnxt.o bnxt_hwrm.o bnxt_sriov.o bnxt_ethtool.o bnxt_dcb.o bnxt_ulp.o bnxt_xdp.o bnxt_ptp.o bnxt_vfr.o bnxt_devlink.o bnxt_dim.o bnxt_coredump.o bnxt_en-$(CONFIG_BNXT_FLOWER_OFFLOAD) += bnxt_tc.o bnxt_en-$(CONFIG_DEBUG_FS) += bnxt_debugfs.o diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c new file mode 100644 index 0000000000000..3e23fce3771e6 --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.c @@ -0,0 +1,372 @@ +/* Broadcom NetXtreme-C/E network driver. + * + * Copyright (c) 2021 Broadcom Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/pci.h> +#include "bnxt_hsi.h" +#include "bnxt.h" +#include "bnxt_hwrm.h" +#include "bnxt_coredump.h" + +static int bnxt_hwrm_dbg_dma_data(struct bnxt *bp, void *msg, + struct bnxt_hwrm_dbg_dma_info *info) +{ + struct hwrm_dbg_cmn_input *cmn_req = msg; + __le16 *seq_ptr = msg + info->seq_off; + struct hwrm_dbg_cmn_output *cmn_resp; + u16 seq = 0, len, segs_off; + dma_addr_t dma_handle; + void *dma_buf, *resp; + int rc, off = 0; + + dma_buf = hwrm_req_dma_slice(bp, msg, info->dma_len, &dma_handle); + if (!dma_buf) { + hwrm_req_drop(bp, msg); + return -ENOMEM; + } + + hwrm_req_timeout(bp, msg, HWRM_COREDUMP_TIMEOUT); + cmn_resp = hwrm_req_hold(bp, msg); + resp = cmn_resp; + + segs_off = offsetof(struct hwrm_dbg_coredump_list_output, + total_segments); + cmn_req->host_dest_addr = cpu_to_le64(dma_handle); + cmn_req->host_buf_len = cpu_to_le32(info->dma_len); + while (1) { + *seq_ptr = cpu_to_le16(seq); + rc = hwrm_req_send(bp, msg); + if (rc) + break; + + len = le16_to_cpu(*((__le16 *)(resp + info->data_len_off))); + if (!seq && + cmn_req->req_type == cpu_to_le16(HWRM_DBG_COREDUMP_LIST)) { + info->segs = le16_to_cpu(*((__le16 *)(resp + + segs_off))); + if (!info->segs) { + rc = -EIO; + break; + } + + info->dest_buf_size = info->segs * + sizeof(struct coredump_segment_record); + info->dest_buf = kmalloc(info->dest_buf_size, + GFP_KERNEL); + if (!info->dest_buf) { + rc = -ENOMEM; + break; + } + } + + if (info->dest_buf) { + if ((info->seg_start + off + len) <= + BNXT_COREDUMP_BUF_LEN(info->buf_len)) { + memcpy(info->dest_buf + off, dma_buf, len); + } else { + rc = -ENOBUFS; + break; + } + } + + if (cmn_req->req_type == + cpu_to_le16(HWRM_DBG_COREDUMP_RETRIEVE)) + info->dest_buf_size += len; + + if (!(cmn_resp->flags & HWRM_DBG_CMN_FLAGS_MORE)) + break; + + seq++; + off += len; + } + hwrm_req_drop(bp, msg); + return rc; +} + +static int bnxt_hwrm_dbg_coredump_list(struct bnxt *bp, + struct bnxt_coredump *coredump) +{ + struct bnxt_hwrm_dbg_dma_info info = {NULL}; + struct hwrm_dbg_coredump_list_input *req; + int rc; + + rc = hwrm_req_init(bp, req, HWRM_DBG_COREDUMP_LIST); + if (rc) + return rc; + + info.dma_len = COREDUMP_LIST_BUF_LEN; + info.seq_off = offsetof(struct hwrm_dbg_coredump_list_input, seq_no); + info.data_len_off = offsetof(struct hwrm_dbg_coredump_list_output, + data_len); + + rc = bnxt_hwrm_dbg_dma_data(bp, req, &info); + if (!rc) { + coredump->data = info.dest_buf; + coredump->data_size = info.dest_buf_size; + coredump->total_segs = info.segs; + } + return rc; +} + +static int bnxt_hwrm_dbg_coredump_initiate(struct bnxt *bp, u16 component_id, + u16 segment_id) +{ + struct hwrm_dbg_coredump_initiate_input *req; + int rc; + + rc = hwrm_req_init(bp, req, HWRM_DBG_COREDUMP_INITIATE); + if (rc) + return rc; + + hwrm_req_timeout(bp, req, HWRM_COREDUMP_TIMEOUT); + req->component_id = cpu_to_le16(component_id); + req->segment_id = cpu_to_le16(segment_id); + + return hwrm_req_send(bp, req); +} + +static int bnxt_hwrm_dbg_coredump_retrieve(struct bnxt *bp, u16 component_id, + u16 segment_id, u32 *seg_len, + void *buf, u32 buf_len, u32 offset) +{ + struct hwrm_dbg_coredump_retrieve_input *req; + struct bnxt_hwrm_dbg_dma_info info = {NULL}; + int rc; + + rc = hwrm_req_init(bp, req, HWRM_DBG_COREDUMP_RETRIEVE); + if (rc) + return rc; + + req->component_id = cpu_to_le16(component_id); + req->segment_id = cpu_to_le16(segment_id); + + info.dma_len = COREDUMP_RETRIEVE_BUF_LEN; + info.seq_off = offsetof(struct hwrm_dbg_coredump_retrieve_input, + seq_no); + info.data_len_off = offsetof(struct hwrm_dbg_coredump_retrieve_output, + data_len); + if (buf) { + info.dest_buf = buf + offset; + info.buf_len = buf_len; + info.seg_start = offset; + } + + rc = bnxt_hwrm_dbg_dma_data(bp, req, &info); + if (!rc) + *seg_len = info.dest_buf_size; + + return rc; +} + +static void +bnxt_fill_coredump_seg_hdr(struct bnxt *bp, + struct bnxt_coredump_segment_hdr *seg_hdr, + struct coredump_segment_record *seg_rec, u32 seg_len, + int status, u32 duration, u32 instance) +{ + memset(seg_hdr, 0, sizeof(*seg_hdr)); + memcpy(seg_hdr->signature, "sEgM", 4); + if (seg_rec) { + seg_hdr->component_id = (__force __le32)seg_rec->component_id; + seg_hdr->segment_id = (__force __le32)seg_rec->segment_id; + seg_hdr->low_version = seg_rec->version_low; + seg_hdr->high_version = seg_rec->version_hi; + } else { + /* For hwrm_ver_get response Component id = 2 + * and Segment id = 0 + */ + seg_hdr->component_id = cpu_to_le32(2); + seg_hdr->segment_id = 0; + } + seg_hdr->function_id = cpu_to_le16(bp->pdev->devfn); + seg_hdr->length = cpu_to_le32(seg_len); + seg_hdr->status = cpu_to_le32(status); + seg_hdr->duration = cpu_to_le32(duration); + seg_hdr->data_offset = cpu_to_le32(sizeof(*seg_hdr)); + seg_hdr->instance = cpu_to_le32(instance); +} + +static void +bnxt_fill_coredump_record(struct bnxt *bp, struct bnxt_coredump_record *record, + time64_t start, s16 start_utc, u16 total_segs, + int status) +{ + time64_t end = ktime_get_real_seconds(); + u32 os_ver_major = 0, os_ver_minor = 0; + struct tm tm; + + time64_to_tm(start, 0, &tm); + memset(record, 0, sizeof(*record)); + memcpy(record->signature, "cOrE", 4); + record->flags = 0; + record->low_version = 0; + record->high_version = 1; + record->asic_state = 0; + strscpy(record->system_name, utsname()->nodename, + sizeof(record->system_name)); + record->year = cpu_to_le16(tm.tm_year + 1900); + record->month = cpu_to_le16(tm.tm_mon + 1); + record->day = cpu_to_le16(tm.tm_mday); + record->hour = cpu_to_le16(tm.tm_hour); + record->minute = cpu_to_le16(tm.tm_min); + record->second = cpu_to_le16(tm.tm_sec); + record->utc_bias = cpu_to_le16(start_utc); + strcpy(record->commandline, "ethtool -w"); + record->total_segments = cpu_to_le32(total_segs); + + if (sscanf(utsname()->release, "%u.%u", &os_ver_major, &os_ver_minor) != 2) + netdev_warn(bp->dev, "Unknown OS release in coredump\n"); + record->os_ver_major = cpu_to_le32(os_ver_major); + record->os_ver_minor = cpu_to_le32(os_ver_minor); + + strscpy(record->os_name, utsname()->sysname, sizeof(record->os_name)); + time64_to_tm(end, 0, &tm); + record->end_year = cpu_to_le16(tm.tm_year + 1900); + record->end_month = cpu_to_le16(tm.tm_mon + 1); + record->end_day = cpu_to_le16(tm.tm_mday); + record->end_hour = cpu_to_le16(tm.tm_hour); + record->end_minute = cpu_to_le16(tm.tm_min); + record->end_second = cpu_to_le16(tm.tm_sec); + record->end_utc_bias = cpu_to_le16(sys_tz.tz_minuteswest * 60); + record->asic_id1 = cpu_to_le32(bp->chip_num << 16 | + bp->ver_resp.chip_rev << 8 | + bp->ver_resp.chip_metal); + record->asic_id2 = 0; + record->coredump_status = cpu_to_le32(status); + record->ioctl_low_version = 0; + record->ioctl_high_version = 0; +} + +static int __bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len) +{ + u32 ver_get_resp_len = sizeof(struct hwrm_ver_get_output); + u32 offset = 0, seg_hdr_len, seg_record_len, buf_len = 0; + struct coredump_segment_record *seg_record = NULL; + struct bnxt_coredump_segment_hdr seg_hdr; + struct bnxt_coredump coredump = {NULL}; + time64_t start_time; + u16 start_utc; + int rc = 0, i; + + if (buf) + buf_len = *dump_len; + + start_time = ktime_get_real_seconds(); + start_utc = sys_tz.tz_minuteswest * 60; + seg_hdr_len = sizeof(seg_hdr); + + /* First segment should be hwrm_ver_get response */ + *dump_len = seg_hdr_len + ver_get_resp_len; + if (buf) { + bnxt_fill_coredump_seg_hdr(bp, &seg_hdr, NULL, ver_get_resp_len, + 0, 0, 0); + memcpy(buf + offset, &seg_hdr, seg_hdr_len); + offset += seg_hdr_len; + memcpy(buf + offset, &bp->ver_resp, ver_get_resp_len); + offset += ver_get_resp_len; + } + + rc = bnxt_hwrm_dbg_coredump_list(bp, &coredump); + if (rc) { + netdev_err(bp->dev, "Failed to get coredump segment list\n"); + goto err; + } + + *dump_len += seg_hdr_len * coredump.total_segs; + + seg_record = (struct coredump_segment_record *)coredump.data; + seg_record_len = sizeof(*seg_record); + + for (i = 0; i < coredump.total_segs; i++) { + u16 comp_id = le16_to_cpu(seg_record->component_id); + u16 seg_id = le16_to_cpu(seg_record->segment_id); + u32 duration = 0, seg_len = 0; + unsigned long start, end; + + if (buf && ((offset + seg_hdr_len) > + BNXT_COREDUMP_BUF_LEN(buf_len))) { + rc = -ENOBUFS; + goto err; + } + + start = jiffies; + + rc = bnxt_hwrm_dbg_coredump_initiate(bp, comp_id, seg_id); + if (rc) { + netdev_err(bp->dev, + "Failed to initiate coredump for seg = %d\n", + seg_record->segment_id); + goto next_seg; + } + + /* Write segment data into the buffer */ + rc = bnxt_hwrm_dbg_coredump_retrieve(bp, comp_id, seg_id, + &seg_len, buf, buf_len, + offset + seg_hdr_len); + if (rc && rc == -ENOBUFS) + goto err; + else if (rc) + netdev_err(bp->dev, + "Failed to retrieve coredump for seg = %d\n", + seg_record->segment_id); + +next_seg: + end = jiffies; + duration = jiffies_to_msecs(end - start); + bnxt_fill_coredump_seg_hdr(bp, &seg_hdr, seg_record, seg_len, + rc, duration, 0); + + if (buf) { + /* Write segment header into the buffer */ + memcpy(buf + offset, &seg_hdr, seg_hdr_len); + offset += seg_hdr_len + seg_len; + } + + *dump_len += seg_len; + seg_record = + (struct coredump_segment_record *)((u8 *)seg_record + + seg_record_len); + } + +err: + if (buf) + bnxt_fill_coredump_record(bp, buf + offset, start_time, + start_utc, coredump.total_segs + 1, + rc); + kfree(coredump.data); + *dump_len += sizeof(struct bnxt_coredump_record); + if (rc == -ENOBUFS) + netdev_err(bp->dev, "Firmware returned large coredump buffer\n"); + return rc; +} + +int bnxt_get_coredump(struct bnxt *bp, u16 dump_type, void *buf, u32 *dump_len) +{ + if (dump_type == BNXT_DUMP_CRASH) { +#ifdef CONFIG_TEE_BNXT_FW + return tee_bnxt_copy_coredump(buf, 0, *dump_len); +#else + return -EOPNOTSUPP; +#endif + } else { + return __bnxt_get_coredump(bp, buf, dump_len); + } +} + +u32 bnxt_get_coredump_length(struct bnxt *bp, u16 dump_type) +{ + u32 len = 0; + + if (dump_type == BNXT_DUMP_CRASH) + len = BNXT_CRASH_DUMP_LEN; + else + __bnxt_get_coredump(bp, NULL, &len); + return len; +} diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.h index 09c22f8fe3991..b1a1b2fffb194 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_coredump.h @@ -10,6 +10,10 @@ #ifndef BNXT_COREDUMP_H #define BNXT_COREDUMP_H
+#include <linux/utsname.h> +#include <linux/time.h> +#include <linux/rtc.h> + struct bnxt_coredump_segment_hdr { __u8 signature[4]; __le32 component_id; @@ -63,4 +67,51 @@ struct bnxt_coredump_record { __u8 ioctl_high_version; __le16 rsvd3[313]; }; + +#define BNXT_CRASH_DUMP_LEN (8 << 20) + +#define COREDUMP_LIST_BUF_LEN 2048 +#define COREDUMP_RETRIEVE_BUF_LEN 4096 + +struct bnxt_coredump { + void *data; + int data_size; + u16 total_segs; +}; + +#define BNXT_COREDUMP_BUF_LEN(len) ((len) - sizeof(struct bnxt_coredump_record)) + +struct bnxt_hwrm_dbg_dma_info { + void *dest_buf; + int dest_buf_size; + u16 dma_len; + u16 seq_off; + u16 data_len_off; + u16 segs; + u32 seg_start; + u32 buf_len; +}; + +struct hwrm_dbg_cmn_input { + __le16 req_type; + __le16 cmpl_ring; + __le16 seq_id; + __le16 target_id; + __le64 resp_addr; + __le64 host_dest_addr; + __le32 host_buf_len; +}; + +struct hwrm_dbg_cmn_output { + __le16 error_code; + __le16 req_type; + __le16 seq_id; + __le16 resp_len; + u8 flags; + #define HWRM_DBG_CMN_FLAGS_MORE 1 +}; + +int bnxt_get_coredump(struct bnxt *bp, u16 dump_type, void *buf, u32 *dump_len); +u32 bnxt_get_coredump_length(struct bnxt *bp, u16 dump_type); + #endif diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 161c354ed4864..c5974b16670a8 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -3609,362 +3609,6 @@ static int bnxt_reset(struct net_device *dev, u32 *flags) return 0; }
-static int bnxt_hwrm_dbg_dma_data(struct bnxt *bp, void *msg, - struct bnxt_hwrm_dbg_dma_info *info) -{ - struct hwrm_dbg_cmn_input *cmn_req = msg; - __le16 *seq_ptr = msg + info->seq_off; - struct hwrm_dbg_cmn_output *cmn_resp; - u16 seq = 0, len, segs_off; - dma_addr_t dma_handle; - void *dma_buf, *resp; - int rc, off = 0; - - dma_buf = hwrm_req_dma_slice(bp, msg, info->dma_len, &dma_handle); - if (!dma_buf) { - hwrm_req_drop(bp, msg); - return -ENOMEM; - } - - hwrm_req_timeout(bp, msg, HWRM_COREDUMP_TIMEOUT); - cmn_resp = hwrm_req_hold(bp, msg); - resp = cmn_resp; - - segs_off = offsetof(struct hwrm_dbg_coredump_list_output, - total_segments); - cmn_req->host_dest_addr = cpu_to_le64(dma_handle); - cmn_req->host_buf_len = cpu_to_le32(info->dma_len); - while (1) { - *seq_ptr = cpu_to_le16(seq); - rc = hwrm_req_send(bp, msg); - if (rc) - break; - - len = le16_to_cpu(*((__le16 *)(resp + info->data_len_off))); - if (!seq && - cmn_req->req_type == cpu_to_le16(HWRM_DBG_COREDUMP_LIST)) { - info->segs = le16_to_cpu(*((__le16 *)(resp + - segs_off))); - if (!info->segs) { - rc = -EIO; - break; - } - - info->dest_buf_size = info->segs * - sizeof(struct coredump_segment_record); - info->dest_buf = kmalloc(info->dest_buf_size, - GFP_KERNEL); - if (!info->dest_buf) { - rc = -ENOMEM; - break; - } - } - - if (info->dest_buf) { - if ((info->seg_start + off + len) <= - BNXT_COREDUMP_BUF_LEN(info->buf_len)) { - memcpy(info->dest_buf + off, dma_buf, len); - } else { - rc = -ENOBUFS; - break; - } - } - - if (cmn_req->req_type == - cpu_to_le16(HWRM_DBG_COREDUMP_RETRIEVE)) - info->dest_buf_size += len; - - if (!(cmn_resp->flags & HWRM_DBG_CMN_FLAGS_MORE)) - break; - - seq++; - off += len; - } - hwrm_req_drop(bp, msg); - return rc; -} - -static int bnxt_hwrm_dbg_coredump_list(struct bnxt *bp, - struct bnxt_coredump *coredump) -{ - struct bnxt_hwrm_dbg_dma_info info = {NULL}; - struct hwrm_dbg_coredump_list_input *req; - int rc; - - rc = hwrm_req_init(bp, req, HWRM_DBG_COREDUMP_LIST); - if (rc) - return rc; - - info.dma_len = COREDUMP_LIST_BUF_LEN; - info.seq_off = offsetof(struct hwrm_dbg_coredump_list_input, seq_no); - info.data_len_off = offsetof(struct hwrm_dbg_coredump_list_output, - data_len); - - rc = bnxt_hwrm_dbg_dma_data(bp, req, &info); - if (!rc) { - coredump->data = info.dest_buf; - coredump->data_size = info.dest_buf_size; - coredump->total_segs = info.segs; - } - return rc; -} - -static int bnxt_hwrm_dbg_coredump_initiate(struct bnxt *bp, u16 component_id, - u16 segment_id) -{ - struct hwrm_dbg_coredump_initiate_input *req; - int rc; - - rc = hwrm_req_init(bp, req, HWRM_DBG_COREDUMP_INITIATE); - if (rc) - return rc; - - hwrm_req_timeout(bp, req, HWRM_COREDUMP_TIMEOUT); - req->component_id = cpu_to_le16(component_id); - req->segment_id = cpu_to_le16(segment_id); - - return hwrm_req_send(bp, req); -} - -static int bnxt_hwrm_dbg_coredump_retrieve(struct bnxt *bp, u16 component_id, - u16 segment_id, u32 *seg_len, - void *buf, u32 buf_len, u32 offset) -{ - struct hwrm_dbg_coredump_retrieve_input *req; - struct bnxt_hwrm_dbg_dma_info info = {NULL}; - int rc; - - rc = hwrm_req_init(bp, req, HWRM_DBG_COREDUMP_RETRIEVE); - if (rc) - return rc; - - req->component_id = cpu_to_le16(component_id); - req->segment_id = cpu_to_le16(segment_id); - - info.dma_len = COREDUMP_RETRIEVE_BUF_LEN; - info.seq_off = offsetof(struct hwrm_dbg_coredump_retrieve_input, - seq_no); - info.data_len_off = offsetof(struct hwrm_dbg_coredump_retrieve_output, - data_len); - if (buf) { - info.dest_buf = buf + offset; - info.buf_len = buf_len; - info.seg_start = offset; - } - - rc = bnxt_hwrm_dbg_dma_data(bp, req, &info); - if (!rc) - *seg_len = info.dest_buf_size; - - return rc; -} - -static void -bnxt_fill_coredump_seg_hdr(struct bnxt *bp, - struct bnxt_coredump_segment_hdr *seg_hdr, - struct coredump_segment_record *seg_rec, u32 seg_len, - int status, u32 duration, u32 instance) -{ - memset(seg_hdr, 0, sizeof(*seg_hdr)); - memcpy(seg_hdr->signature, "sEgM", 4); - if (seg_rec) { - seg_hdr->component_id = (__force __le32)seg_rec->component_id; - seg_hdr->segment_id = (__force __le32)seg_rec->segment_id; - seg_hdr->low_version = seg_rec->version_low; - seg_hdr->high_version = seg_rec->version_hi; - } else { - /* For hwrm_ver_get response Component id = 2 - * and Segment id = 0 - */ - seg_hdr->component_id = cpu_to_le32(2); - seg_hdr->segment_id = 0; - } - seg_hdr->function_id = cpu_to_le16(bp->pdev->devfn); - seg_hdr->length = cpu_to_le32(seg_len); - seg_hdr->status = cpu_to_le32(status); - seg_hdr->duration = cpu_to_le32(duration); - seg_hdr->data_offset = cpu_to_le32(sizeof(*seg_hdr)); - seg_hdr->instance = cpu_to_le32(instance); -} - -static void -bnxt_fill_coredump_record(struct bnxt *bp, struct bnxt_coredump_record *record, - time64_t start, s16 start_utc, u16 total_segs, - int status) -{ - time64_t end = ktime_get_real_seconds(); - u32 os_ver_major = 0, os_ver_minor = 0; - struct tm tm; - - time64_to_tm(start, 0, &tm); - memset(record, 0, sizeof(*record)); - memcpy(record->signature, "cOrE", 4); - record->flags = 0; - record->low_version = 0; - record->high_version = 1; - record->asic_state = 0; - strscpy(record->system_name, utsname()->nodename, - sizeof(record->system_name)); - record->year = cpu_to_le16(tm.tm_year + 1900); - record->month = cpu_to_le16(tm.tm_mon + 1); - record->day = cpu_to_le16(tm.tm_mday); - record->hour = cpu_to_le16(tm.tm_hour); - record->minute = cpu_to_le16(tm.tm_min); - record->second = cpu_to_le16(tm.tm_sec); - record->utc_bias = cpu_to_le16(start_utc); - strcpy(record->commandline, "ethtool -w"); - record->total_segments = cpu_to_le32(total_segs); - - if (sscanf(utsname()->release, "%u.%u", &os_ver_major, &os_ver_minor) != 2) - netdev_warn(bp->dev, "Unknown OS release in coredump\n"); - record->os_ver_major = cpu_to_le32(os_ver_major); - record->os_ver_minor = cpu_to_le32(os_ver_minor); - - strscpy(record->os_name, utsname()->sysname, sizeof(record->os_name)); - time64_to_tm(end, 0, &tm); - record->end_year = cpu_to_le16(tm.tm_year + 1900); - record->end_month = cpu_to_le16(tm.tm_mon + 1); - record->end_day = cpu_to_le16(tm.tm_mday); - record->end_hour = cpu_to_le16(tm.tm_hour); - record->end_minute = cpu_to_le16(tm.tm_min); - record->end_second = cpu_to_le16(tm.tm_sec); - record->end_utc_bias = cpu_to_le16(sys_tz.tz_minuteswest * 60); - record->asic_id1 = cpu_to_le32(bp->chip_num << 16 | - bp->ver_resp.chip_rev << 8 | - bp->ver_resp.chip_metal); - record->asic_id2 = 0; - record->coredump_status = cpu_to_le32(status); - record->ioctl_low_version = 0; - record->ioctl_high_version = 0; -} - -static int __bnxt_get_coredump(struct bnxt *bp, void *buf, u32 *dump_len) -{ - u32 ver_get_resp_len = sizeof(struct hwrm_ver_get_output); - u32 offset = 0, seg_hdr_len, seg_record_len, buf_len = 0; - struct coredump_segment_record *seg_record = NULL; - struct bnxt_coredump_segment_hdr seg_hdr; - struct bnxt_coredump coredump = {NULL}; - time64_t start_time; - u16 start_utc; - int rc = 0, i; - - if (buf) - buf_len = *dump_len; - - start_time = ktime_get_real_seconds(); - start_utc = sys_tz.tz_minuteswest * 60; - seg_hdr_len = sizeof(seg_hdr); - - /* First segment should be hwrm_ver_get response */ - *dump_len = seg_hdr_len + ver_get_resp_len; - if (buf) { - bnxt_fill_coredump_seg_hdr(bp, &seg_hdr, NULL, ver_get_resp_len, - 0, 0, 0); - memcpy(buf + offset, &seg_hdr, seg_hdr_len); - offset += seg_hdr_len; - memcpy(buf + offset, &bp->ver_resp, ver_get_resp_len); - offset += ver_get_resp_len; - } - - rc = bnxt_hwrm_dbg_coredump_list(bp, &coredump); - if (rc) { - netdev_err(bp->dev, "Failed to get coredump segment list\n"); - goto err; - } - - *dump_len += seg_hdr_len * coredump.total_segs; - - seg_record = (struct coredump_segment_record *)coredump.data; - seg_record_len = sizeof(*seg_record); - - for (i = 0; i < coredump.total_segs; i++) { - u16 comp_id = le16_to_cpu(seg_record->component_id); - u16 seg_id = le16_to_cpu(seg_record->segment_id); - u32 duration = 0, seg_len = 0; - unsigned long start, end; - - if (buf && ((offset + seg_hdr_len) > - BNXT_COREDUMP_BUF_LEN(buf_len))) { - rc = -ENOBUFS; - goto err; - } - - start = jiffies; - - rc = bnxt_hwrm_dbg_coredump_initiate(bp, comp_id, seg_id); - if (rc) { - netdev_err(bp->dev, - "Failed to initiate coredump for seg = %d\n", - seg_record->segment_id); - goto next_seg; - } - - /* Write segment data into the buffer */ - rc = bnxt_hwrm_dbg_coredump_retrieve(bp, comp_id, seg_id, - &seg_len, buf, buf_len, - offset + seg_hdr_len); - if (rc && rc == -ENOBUFS) - goto err; - else if (rc) - netdev_err(bp->dev, - "Failed to retrieve coredump for seg = %d\n", - seg_record->segment_id); - -next_seg: - end = jiffies; - duration = jiffies_to_msecs(end - start); - bnxt_fill_coredump_seg_hdr(bp, &seg_hdr, seg_record, seg_len, - rc, duration, 0); - - if (buf) { - /* Write segment header into the buffer */ - memcpy(buf + offset, &seg_hdr, seg_hdr_len); - offset += seg_hdr_len + seg_len; - } - - *dump_len += seg_len; - seg_record = - (struct coredump_segment_record *)((u8 *)seg_record + - seg_record_len); - } - -err: - if (buf) - bnxt_fill_coredump_record(bp, buf + offset, start_time, - start_utc, coredump.total_segs + 1, - rc); - kfree(coredump.data); - *dump_len += sizeof(struct bnxt_coredump_record); - if (rc == -ENOBUFS) - netdev_err(bp->dev, "Firmware returned large coredump buffer\n"); - return rc; -} - -static int bnxt_get_coredump(struct bnxt *bp, u16 dump_type, void *buf, u32 *dump_len) -{ - if (dump_type == BNXT_DUMP_CRASH) { -#ifdef CONFIG_TEE_BNXT_FW - return tee_bnxt_copy_coredump(buf, 0, *dump_len); -#else - return -EOPNOTSUPP; -#endif - } else { - return __bnxt_get_coredump(bp, buf, dump_len); - } -} - -static u32 bnxt_get_coredump_length(struct bnxt *bp, u16 dump_type) -{ - u32 len = 0; - - if (dump_type == BNXT_DUMP_CRASH) - len = BNXT_CRASH_DUMP_LEN; - else - __bnxt_get_coredump(bp, NULL, &len); - return len; -} - static int bnxt_set_dump(struct net_device *dev, struct ethtool_dump *dump) { struct bnxt *bp = netdev_priv(dev); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h index 0a57cb6a4a4bf..11a719f98defd 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.h @@ -22,49 +22,6 @@ struct bnxt_led_cfg { u8 rsvd; };
-#define COREDUMP_LIST_BUF_LEN 2048 -#define COREDUMP_RETRIEVE_BUF_LEN 4096 - -struct bnxt_coredump { - void *data; - int data_size; - u16 total_segs; -}; - -#define BNXT_COREDUMP_BUF_LEN(len) ((len) - sizeof(struct bnxt_coredump_record)) - -struct bnxt_hwrm_dbg_dma_info { - void *dest_buf; - int dest_buf_size; - u16 dma_len; - u16 seq_off; - u16 data_len_off; - u16 segs; - u32 seg_start; - u32 buf_len; -}; - -struct hwrm_dbg_cmn_input { - __le16 req_type; - __le16 cmpl_ring; - __le16 seq_id; - __le16 target_id; - __le64 resp_addr; - __le64 host_dest_addr; - __le32 host_buf_len; -}; - -struct hwrm_dbg_cmn_output { - __le16 error_code; - __le16 req_type; - __le16 seq_id; - __le16 resp_len; - u8 flags; - #define HWRM_DBG_CMN_FLAGS_MORE 1 -}; - -#define BNXT_CRASH_DUMP_LEN (8 << 20) - #define BNXT_LED_DFLT_ENA \ (PORT_LED_CFG_REQ_ENABLES_LED0_ID | \ PORT_LED_CFG_REQ_ENABLES_LED0_STATE | \