Commit c33626d8 authored by Vikas Gupta's avatar Vikas Gupta Committed by Jakub Kicinski

bnxt_en: add support for storing crash dump into host memory

Newer firmware supports automatic DMA of crash dump to host memory
when it crashes.  If the feature is supported, allocate the required
memory using the existing context memory infrastructure.  Communicate
the page table containing the DMA addresses to the firmware.
Reviewed-by: default avatarSomnath Kotur <somnath.kotur@broadcom.com>
Reviewed-by: default avatarPavan Chebbi <pavan.chebbi@broadcom.com>
Reviewed-by: default avatarAndy Gospodarek <andrew.gospodarek@broadcom.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Signed-off-by: default avatarVikas Gupta <vikas.gupta@broadcom.com>
Signed-off-by: default avatarMichael Chan <michael.chan@broadcom.com>
Link: https://patch.msgid.link/20240828183235.128948-2-michael.chan@broadcom.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 791f9b68
......@@ -69,6 +69,7 @@
#include "bnxt_tc.h"
#include "bnxt_devlink.h"
#include "bnxt_debugfs.h"
#include "bnxt_coredump.h"
#include "bnxt_hwmon.h"
#define BNXT_TX_TIMEOUT (5 * HZ)
......@@ -8946,6 +8947,80 @@ static int bnxt_alloc_ctx_mem(struct bnxt *bp)
return 0;
}
static int bnxt_hwrm_crash_dump_mem_cfg(struct bnxt *bp)
{
struct hwrm_dbg_crashdump_medium_cfg_input *req;
u16 page_attr;
int rc;
if (!(bp->fw_dbg_cap & DBG_QCAPS_RESP_FLAGS_CRASHDUMP_HOST_DDR))
return 0;
rc = hwrm_req_init(bp, req, HWRM_DBG_CRASHDUMP_MEDIUM_CFG);
if (rc)
return rc;
if (BNXT_PAGE_SIZE == 0x2000)
page_attr = DBG_CRASHDUMP_MEDIUM_CFG_REQ_PG_SIZE_PG_8K;
else if (BNXT_PAGE_SIZE == 0x10000)
page_attr = DBG_CRASHDUMP_MEDIUM_CFG_REQ_PG_SIZE_PG_64K;
else
page_attr = DBG_CRASHDUMP_MEDIUM_CFG_REQ_PG_SIZE_PG_4K;
req->pg_size_lvl = cpu_to_le16(page_attr |
bp->fw_crash_mem->ring_mem.depth);
req->pbl = cpu_to_le64(bp->fw_crash_mem->ring_mem.pg_tbl_map);
req->size = cpu_to_le32(bp->fw_crash_len);
req->output_dest_flags = cpu_to_le16(BNXT_DBG_CR_DUMP_MDM_CFG_DDR);
return hwrm_req_send(bp, req);
}
static void bnxt_free_crash_dump_mem(struct bnxt *bp)
{
if (bp->fw_crash_mem) {
bnxt_free_ctx_pg_tbls(bp, bp->fw_crash_mem);
kfree(bp->fw_crash_mem);
bp->fw_crash_mem = NULL;
}
}
static int bnxt_alloc_crash_dump_mem(struct bnxt *bp)
{
u32 mem_size = 0;
int rc;
if (!(bp->fw_dbg_cap & DBG_QCAPS_RESP_FLAGS_CRASHDUMP_HOST_DDR))
return 0;
rc = bnxt_hwrm_get_dump_len(bp, BNXT_DUMP_CRASH, &mem_size);
if (rc)
return rc;
mem_size = round_up(mem_size, 4);
/* keep and use the existing pages */
if (bp->fw_crash_mem &&
mem_size <= bp->fw_crash_mem->nr_pages * BNXT_PAGE_SIZE)
goto alloc_done;
if (bp->fw_crash_mem)
bnxt_free_ctx_pg_tbls(bp, bp->fw_crash_mem);
else
bp->fw_crash_mem = kzalloc(sizeof(*bp->fw_crash_mem),
GFP_KERNEL);
if (!bp->fw_crash_mem)
return -ENOMEM;
rc = bnxt_alloc_ctx_pg_tbls(bp, bp->fw_crash_mem, mem_size, 1, NULL);
if (rc) {
bnxt_free_crash_dump_mem(bp);
return rc;
}
alloc_done:
bp->fw_crash_len = mem_size;
return 0;
}
int bnxt_hwrm_func_resc_qcaps(struct bnxt *bp, bool all)
{
struct hwrm_func_resource_qcaps_output *resp;
......@@ -13986,6 +14061,19 @@ static int bnxt_fw_init_one_p2(struct bnxt *bp)
if (rc)
return -ENODEV;
rc = bnxt_alloc_crash_dump_mem(bp);
if (rc)
netdev_warn(bp->dev, "crash dump mem alloc failure rc: %d\n",
rc);
if (!rc) {
rc = bnxt_hwrm_crash_dump_mem_cfg(bp);
if (rc) {
bnxt_free_crash_dump_mem(bp);
netdev_warn(bp->dev,
"hwrm crash dump mem failure rc: %d\n", rc);
}
}
if (bnxt_fw_pre_resv_vnics(bp))
bp->fw_cap |= BNXT_FW_CAP_PRE_RESV_VNICS;
......@@ -15294,6 +15382,7 @@ static void bnxt_remove_one(struct pci_dev *pdev)
bp->fw_health = NULL;
bnxt_cleanup_pci(bp);
bnxt_free_ctx_mem(bp);
bnxt_free_crash_dump_mem(bp);
kfree(bp->rss_indir_tbl);
bp->rss_indir_tbl = NULL;
bnxt_free_port_stats(bp);
......@@ -15933,6 +16022,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
bp->fw_health = NULL;
bnxt_cleanup_pci(bp);
bnxt_free_ctx_mem(bp);
bnxt_free_crash_dump_mem(bp);
kfree(bp->rss_indir_tbl);
bp->rss_indir_tbl = NULL;
......@@ -16024,6 +16114,8 @@ static int bnxt_resume(struct device *device)
rc = -ENODEV;
goto resume_exit;
}
if (bp->fw_crash_mem)
bnxt_hwrm_crash_dump_mem_cfg(bp);
bnxt_get_wol_settings(bp);
if (netif_running(dev)) {
......
......@@ -2649,6 +2649,9 @@ struct bnxt {
#endif
u32 thermal_threshold_type;
enum board_idx board_idx;
struct bnxt_ctx_pg_info *fw_crash_mem;
u32 fw_crash_len;
};
#define BNXT_NUM_RX_RING_STATS 8
......
......@@ -385,7 +385,7 @@ int bnxt_get_coredump(struct bnxt *bp, u16 dump_type, void *buf, u32 *dump_len)
}
}
static int bnxt_hwrm_get_dump_len(struct bnxt *bp, u16 dump_type, u32 *dump_len)
int bnxt_hwrm_get_dump_len(struct bnxt *bp, u16 dump_type, u32 *dump_len)
{
struct hwrm_dbg_qcfg_output *resp;
struct hwrm_dbg_qcfg_input *req;
......@@ -395,7 +395,8 @@ static int bnxt_hwrm_get_dump_len(struct bnxt *bp, u16 dump_type, u32 *dump_len)
return -EOPNOTSUPP;
if (dump_type == BNXT_DUMP_CRASH &&
!(bp->fw_dbg_cap & DBG_QCAPS_RESP_FLAGS_CRASHDUMP_SOC_DDR))
!(bp->fw_dbg_cap & DBG_QCAPS_RESP_FLAGS_CRASHDUMP_SOC_DDR ||
(bp->fw_dbg_cap & DBG_QCAPS_RESP_FLAGS_CRASHDUMP_HOST_DDR)))
return -EOPNOTSUPP;
rc = hwrm_req_init(bp, req, HWRM_DBG_QCFG);
......@@ -403,8 +404,12 @@ static int bnxt_hwrm_get_dump_len(struct bnxt *bp, u16 dump_type, u32 *dump_len)
return rc;
req->fid = cpu_to_le16(0xffff);
if (dump_type == BNXT_DUMP_CRASH)
req->flags = cpu_to_le16(DBG_QCFG_REQ_FLAGS_CRASHDUMP_SIZE_FOR_DEST_DEST_SOC_DDR);
if (dump_type == BNXT_DUMP_CRASH) {
if (bp->fw_dbg_cap & DBG_QCAPS_RESP_FLAGS_CRASHDUMP_SOC_DDR)
req->flags = cpu_to_le16(BNXT_DBG_FL_CR_DUMP_SIZE_SOC);
else
req->flags = cpu_to_le16(BNXT_DBG_FL_CR_DUMP_SIZE_HOST);
}
resp = hwrm_req_hold(bp, req);
rc = hwrm_req_send(bp, req);
......@@ -412,7 +417,10 @@ static int bnxt_hwrm_get_dump_len(struct bnxt *bp, u16 dump_type, u32 *dump_len)
goto get_dump_len_exit;
if (dump_type == BNXT_DUMP_CRASH) {
*dump_len = le32_to_cpu(resp->crashdump_size);
if (bp->fw_dbg_cap & DBG_QCAPS_RESP_FLAGS_CRASHDUMP_SOC_DDR)
*dump_len = BNXT_CRASH_DUMP_LEN;
else
*dump_len = le32_to_cpu(resp->crashdump_size);
} else {
/* Driver adds coredump header and "HWRM_VER_GET response"
* segment additionally to coredump.
......
......@@ -111,7 +111,15 @@ struct hwrm_dbg_cmn_output {
#define HWRM_DBG_CMN_FLAGS_MORE 1
};
#define BNXT_DBG_FL_CR_DUMP_SIZE_SOC \
DBG_QCFG_REQ_FLAGS_CRASHDUMP_SIZE_FOR_DEST_DEST_SOC_DDR
#define BNXT_DBG_FL_CR_DUMP_SIZE_HOST \
DBG_QCFG_REQ_FLAGS_CRASHDUMP_SIZE_FOR_DEST_DEST_HOST_DDR
#define BNXT_DBG_CR_DUMP_MDM_CFG_DDR \
DBG_CRASHDUMP_MEDIUM_CFG_REQ_TYPE_DDR
int bnxt_get_coredump(struct bnxt *bp, u16 dump_type, void *buf, u32 *dump_len);
int bnxt_hwrm_get_dump_len(struct bnxt *bp, u16 dump_type, u32 *dump_len);
u32 bnxt_get_coredump_length(struct bnxt *bp, u16 dump_type);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment