summaryrefslogtreecommitdiff
path: root/gxp-debug-dump.c
diff options
context:
space:
mode:
Diffstat (limited to 'gxp-debug-dump.c')
-rw-r--r--gxp-debug-dump.c137
1 files changed, 98 insertions, 39 deletions
diff --git a/gxp-debug-dump.c b/gxp-debug-dump.c
index 94ae78b..4df7add 100644
--- a/gxp-debug-dump.c
+++ b/gxp-debug-dump.c
@@ -14,17 +14,16 @@
#include <linux/string.h>
#include <linux/workqueue.h>
-#if IS_ENABLED(CONFIG_GXP_TEST) || IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
-#include <linux/platform_data/sscoredump.h>
-#endif
-
#include <gcip/gcip-pm.h>
+#include <gcip/gcip-alloc-helper.h>
#include "gxp-client.h"
#include "gxp-debug-dump.h"
#include "gxp-dma.h"
#include "gxp-doorbell.h"
#include "gxp-firmware.h"
+#include "gxp-firmware-data.h"
+#include "gxp-firmware-loader.h"
#include "gxp-host-device-structs.h"
#include "gxp-internal.h"
#include "gxp-lpm.h"
@@ -32,6 +31,10 @@
#include "gxp-pm.h"
#include "gxp-vd.h"
+#if HAS_COREDUMP
+#include <linux/platform_data/sscoredump.h>
+#endif
+
#define SSCD_MSG_LENGTH 64
#define SYNC_BARRIER_BLOCK 0x00100000
@@ -39,6 +42,13 @@
#define DEBUG_DUMP_MEMORY_SIZE 0x400000 /* size in bytes */
+/*
+ * CORE_FIRMWARE_RW_STRIDE & CORE_FIRMWARE_RW_ADDR must match with their
+ * values defind in core firmware image config.
+ */
+#define CORE_FIRMWARE_RW_STRIDE 0x200000 /* 2 MB */
+#define CORE_FIRMWARE_RW_ADDR(x) (0xFA400000 + CORE_FIRMWARE_RW_STRIDE * x)
+
/* Enum indicating the debug dump request reason. */
enum gxp_debug_dump_init_type { DEBUG_DUMP_FW_INIT, DEBUG_DUMP_KERNEL_INIT };
@@ -301,7 +311,7 @@ static int gxp_get_common_dump(struct gxp_dev *gxp)
return ret;
}
-#if IS_ENABLED(CONFIG_GXP_TEST) || IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
+#if HAS_COREDUMP
static void gxp_send_to_sscd(struct gxp_dev *gxp, void *segs, int seg_cnt,
const char *info)
{
@@ -454,7 +464,62 @@ static int gxp_user_buffers_vmap(struct gxp_dev *gxp,
out:
return cnt;
}
-#endif
+
+/**
+ * gxp_map_fw_rw_section() - Maps the fw rw section address and size to be
+ * sent to sscd module for taking the dump.
+ * @gxp: The GXP device.
+ * @vd: vd of the crashed client.
+ * @core_id: physical core_id of crashed core.
+ * @seg_idx: Pointer to a index that is keeping track of
+ * gxp->debug_dump_mgr->segs[] array.
+ *
+ * This function parses the ns_regions of the given vd to find
+ * fw_rw_section details.
+ *
+ * Return:
+ * * 0 - Successfully mapped fw_rw_section data.
+ * * -EOPNOTSUPP - Operation not supported for invalid image config.
+ * * -ENXIO - No IOVA found for the fw_rw_section.
+ */
+static int gxp_map_fw_rw_section(struct gxp_dev *gxp,
+ struct gxp_virtual_device *vd,
+ uint32_t core_id, int *seg_idx)
+{
+ size_t idx;
+ struct sg_table *sgt;
+ struct gxp_debug_dump_manager *mgr = gxp->debug_dump_mgr;
+ dma_addr_t fw_rw_section_daddr = CORE_FIRMWARE_RW_ADDR(core_id);
+ const size_t n_reg = ARRAY_SIZE(vd->ns_regions);
+
+ if (!gxp_fw_data_use_per_vd_config(vd)) {
+ dev_err(gxp->dev, "Unsupported Image config version = %d.",
+ gxp->fw_loader_mgr->core_img_cfg.config_version);
+ return -EOPNOTSUPP;
+ }
+
+ for (idx = 0; idx < n_reg; idx++) {
+ sgt = vd->ns_regions[idx].sgt;
+ if (!sgt)
+ break;
+
+ if (fw_rw_section_daddr != vd->ns_regions[idx].daddr)
+ continue;
+
+ mgr->segs[core_id][*seg_idx].addr =
+ gcip_noncontiguous_sgt_to_mem(sgt);
+ mgr->segs[core_id][*seg_idx].size = gcip_ns_config_to_size(
+ gxp->fw_loader_mgr->core_img_cfg.ns_iommu_mappings[idx]);
+ *seg_idx += 1;
+ return 0;
+ }
+ dev_err(gxp->dev,
+ "fw_rw_section mapping for core %u at iova 0x%llx does not exist",
+ core_id, fw_rw_section_daddr);
+ return -ENXIO;
+}
+
+#endif /* HAS_COREDUMP */
void gxp_debug_dump_invalidate_segments(struct gxp_dev *gxp, uint32_t core_id)
{
@@ -505,7 +570,7 @@ static int gxp_handle_debug_dump(struct gxp_dev *gxp,
&core_dump->core_dump_header[core_id];
struct gxp_core_header *core_header = &core_dump_header->core_header;
int ret = 0;
-#if IS_ENABLED(CONFIG_GXP_TEST) || IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
+#if HAS_COREDUMP
struct gxp_common_dump *common_dump = mgr->common_dump;
int i;
int seg_idx = 0;
@@ -513,7 +578,7 @@ static int gxp_handle_debug_dump(struct gxp_dev *gxp,
char sscd_msg[SSCD_MSG_LENGTH];
void *user_buf_vaddrs[GXP_NUM_BUFFER_MAPPINGS];
int user_buf_cnt;
-#endif
+#endif /* HAS_COREDUMP */
/* Core */
if (!core_header->dump_available) {
@@ -522,7 +587,7 @@ static int gxp_handle_debug_dump(struct gxp_dev *gxp,
goto out;
}
-#if IS_ENABLED(CONFIG_GXP_TEST) || IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP)
+#if HAS_COREDUMP
/* Common */
data_addr = &common_dump->common_dump_data.common_regs;
for (i = 0; i < GXP_NUM_COMMON_SEGMENTS; i++) {
@@ -571,14 +636,16 @@ static int gxp_handle_debug_dump(struct gxp_dev *gxp,
ret = -EFAULT;
goto out_efault;
}
- /*
- * TODO(b/265105909): Implement the logic for collecting fw rw section
- * separately for mcu mode.
- */
+ /* fw ro section */
mgr->segs[core_id][seg_idx].addr = gxp->fwbufs[core_id].vaddr;
- mgr->segs[core_id][seg_idx].size = gxp->fwbufs[core_id].size;
+ mgr->segs[core_id][seg_idx].size = vd->fw_ro_size;
seg_idx++;
+ /* fw rw section */
+ ret = gxp_map_fw_rw_section(gxp, vd, core_id, &seg_idx);
+ if (ret)
+ goto out;
+
/* User Buffers */
user_buf_cnt =
gxp_user_buffers_vmap(gxp, vd, core_header, user_buf_vaddrs);
@@ -605,7 +672,7 @@ out_efault:
gxp_user_buffers_vunmap(gxp, vd, core_header);
}
-#endif
+#endif /* HAS_COREDUMP */
out:
gxp_debug_dump_invalidate_segments(gxp, core_id);
@@ -615,7 +682,7 @@ out:
static int gxp_init_segments(struct gxp_dev *gxp)
{
-#if !(IS_ENABLED(CONFIG_GXP_TEST) || IS_ENABLED(CONFIG_SUBSYSTEM_COREDUMP))
+#if !HAS_COREDUMP
return 0;
#else
struct gxp_debug_dump_manager *mgr = gxp->debug_dump_mgr;
@@ -625,7 +692,7 @@ static int gxp_init_segments(struct gxp_dev *gxp)
return -ENOMEM;
return 0;
-#endif
+#endif /* HAS_COREDUMP */
}
/*
@@ -663,23 +730,12 @@ out:
static void gxp_generate_debug_dump(struct gxp_dev *gxp, uint core_id,
struct gxp_virtual_device *vd)
{
- u32 boot_mode;
- bool gxp_generate_coredump_called = false;
-
+ bool gxp_generate_coredump_called = true;
mutex_lock(&gxp->debug_dump_mgr->debug_dump_lock);
- /*
- * TODO(b/265105909): Checks below to be verified after implementation for
- * firmware loading for mcu mode are completed.
- */
- boot_mode = gxp_firmware_get_boot_mode(gxp, vd, core_id);
-
- if (gxp_is_fw_running(gxp, core_id) &&
- (boot_mode == GXP_BOOT_MODE_STATUS_COLD_BOOT_COMPLETED ||
- boot_mode == GXP_BOOT_MODE_STATUS_RESUME_COMPLETED)) {
- gxp_generate_coredump_called = true;
- if (gxp_generate_coredump(gxp, vd, core_id))
- dev_err(gxp->dev, "Failed to generate coredump\n");
+ if (gxp_generate_coredump(gxp, vd, core_id)) {
+ gxp_generate_coredump_called = false;
+ dev_err(gxp->dev, "Failed to generate the coredump.\n");
}
/* Invalidate segments to prepare for the next debug dump trigger */
@@ -706,8 +762,14 @@ static void gxp_debug_dump_process_dump_direct_mode(struct work_struct *work)
struct gxp_virtual_device *vd = NULL;
down_read(&gxp->vd_semaphore);
- if (gxp->core_to_vd[core_id])
+ if (gxp->core_to_vd[core_id]) {
vd = gxp_vd_get(gxp->core_to_vd[core_id]);
+ } else {
+ dev_err(gxp->dev, "debug dump failed for null vd on core %d.",
+ core_id);
+ up_read(&gxp->vd_semaphore);
+ return;
+ }
up_read(&gxp->vd_semaphore);
/*
@@ -715,15 +777,12 @@ static void gxp_debug_dump_process_dump_direct_mode(struct work_struct *work)
* of @vd while generating a debug dump. This will help not to block other virtual devices
* proceeding their jobs.
*/
- if (vd)
- mutex_lock(&vd->debug_dump_lock);
+ mutex_lock(&vd->debug_dump_lock);
gxp_generate_debug_dump(gxp, core_id, vd);
- if (vd) {
- mutex_unlock(&vd->debug_dump_lock);
- gxp_vd_put(vd);
- }
+ mutex_unlock(&vd->debug_dump_lock);
+ gxp_vd_put(vd);
}
int gxp_debug_dump_process_dump_mcu_mode(struct gxp_dev *gxp, uint core_list,