diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 550ba56437..1b4d2579f2 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -5746,3 +5746,26 @@ bool sde_encoder_needs_dsc_disable(struct drm_encoder *drm_enc) conn_state = to_sde_connector_state(conn->state); return TOPOLOGY_DSC_MODE(conn_state->old_topology_name); } + +void sde_encoder_add_data_to_minidump_va(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc; + struct sde_encoder_phys *phys_enc; + u32 i; + + sde_enc = to_sde_encoder_virt(drm_enc); + for( i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++) + { + phys_enc = sde_enc->phys_encs[i]; + if(phys_enc && phys_enc->ops.add_to_minidump) + phys_enc->ops.add_to_minidump(phys_enc); + + phys_enc = sde_enc->phys_cmd_encs[i]; + if(phys_enc && phys_enc->ops.add_to_minidump) + phys_enc->ops.add_to_minidump(phys_enc); + + phys_enc = sde_enc->phys_vid_encs[i]; + if(phys_enc && phys_enc->ops.add_to_minidump) + phys_enc->ops.add_to_minidump(phys_enc); + } +} diff --git a/msm/sde/sde_encoder.h b/msm/sde/sde_encoder.h index 874a472ff3..b253377c04 100644 --- a/msm/sde/sde_encoder.h +++ b/msm/sde/sde_encoder.h @@ -658,4 +658,6 @@ static inline bool sde_encoder_is_widebus_enabled(struct drm_encoder *drm_enc) sde_enc = to_sde_encoder_virt(drm_enc); return sde_enc->mode_info.wide_bus_en; } + +void sde_encoder_add_data_to_minidump_va(struct drm_encoder *drm_enc); #endif /* __SDE_ENCODER_H__ */ diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index d3166f44d8..94e813e53a 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/msm/sde/sde_encoder_phys.h @@ -133,6 +133,7 @@ struct sde_encoder_virt_ops { * @setup_vsync_source: Configure vsync source selection for cmd mode. * @get_underrun_line_count: Obtain and log current internal vertical line * count and underrun line count + * @add_to_minidump: Add this phys_enc data to minidumps */ struct sde_encoder_phys_ops { @@ -185,6 +186,7 @@ struct sde_encoder_phys_ops { void (*setup_vsync_source)(struct sde_encoder_phys *phys, u32 vsync_source, struct msm_display_info *disp_info); u32 (*get_underrun_line_count)(struct sde_encoder_phys *phys); + void (*add_to_minidump)(struct sde_encoder_phys *phys); }; /** diff --git a/msm/sde/sde_encoder_phys_cmd.c b/msm/sde/sde_encoder_phys_cmd.c index 96788d4ff6..d48957508c 100644 --- a/msm/sde/sde_encoder_phys_cmd.c +++ b/msm/sde/sde_encoder_phys_cmd.c @@ -1881,6 +1881,14 @@ static void sde_encoder_phys_cmd_setup_vsync_source(struct sde_encoder_phys *phy vsync_source); } +void sde_encoder_phys_cmd_add_enc_to_minidump(struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_cmd *cmd_enc; + cmd_enc = to_sde_encoder_phys_cmd(phys_enc); + + sde_mini_dump_add_va_region("sde_enc_phys_cmd", sizeof(*cmd_enc), cmd_enc); +} + static void sde_encoder_phys_cmd_init_ops(struct sde_encoder_phys_ops *ops) { ops->prepare_commit = sde_encoder_phys_cmd_prepare_commit; @@ -1912,6 +1920,7 @@ static void sde_encoder_phys_cmd_init_ops(struct sde_encoder_phys_ops *ops) ops->setup_vsync_source = sde_encoder_phys_cmd_setup_vsync_source; ops->setup_misr = sde_encoder_helper_setup_misr; ops->collect_misr = sde_encoder_helper_collect_misr; + ops->add_to_minidump = sde_encoder_phys_cmd_add_enc_to_minidump; } static inline bool sde_encoder_phys_cmd_intf_te_supported( diff --git a/msm/sde/sde_encoder_phys_vid.c b/msm/sde/sde_encoder_phys_vid.c index 4374de6707..c854703965 100644 --- a/msm/sde/sde_encoder_phys_vid.c +++ b/msm/sde/sde_encoder_phys_vid.c @@ -1291,6 +1291,14 @@ static int sde_encoder_phys_vid_wait_for_active( return -EINVAL; } +void sde_encoder_phys_vid_add_enc_to_minidump(struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_vid *vid_enc; + vid_enc = to_sde_encoder_phys_vid(phys_enc); + + sde_mini_dump_add_va_region("sde_enc_phys_vid", sizeof(*vid_enc), vid_enc); +} + static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops) { ops->is_master = sde_encoder_phys_vid_is_master; @@ -1319,6 +1327,7 @@ static void sde_encoder_phys_vid_init_ops(struct sde_encoder_phys_ops *ops) ops->prepare_commit = sde_encoder_phys_vid_prepare_for_commit; ops->get_underrun_line_count = sde_encoder_phys_vid_get_underrun_line_count; + ops->add_to_minidump = sde_encoder_phys_vid_add_enc_to_minidump; } struct sde_encoder_phys *sde_encoder_phys_vid_init( diff --git a/msm/sde/sde_encoder_phys_wb.c b/msm/sde/sde_encoder_phys_wb.c index e4bb396311..9ac21bab89 100644 --- a/msm/sde/sde_encoder_phys_wb.c +++ b/msm/sde/sde_encoder_phys_wb.c @@ -1988,6 +1988,14 @@ static void sde_encoder_phys_wb_destroy(struct sde_encoder_phys *phys_enc) kfree(wb_enc); } +void sde_encoder_phys_wb_add_enc_to_minidump(struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_wb *wb_enc; + wb_enc = to_sde_encoder_phys_wb(phys_enc); + + sde_mini_dump_add_va_region("sde_enc_phys_wb", sizeof(*wb_enc), wb_enc); +} + /** * sde_encoder_phys_wb_init_ops - initialize writeback operations * @ops: Pointer to encoder operation table @@ -2010,6 +2018,7 @@ static void sde_encoder_phys_wb_init_ops(struct sde_encoder_phys_ops *ops) ops->trigger_start = sde_encoder_helper_trigger_start; ops->hw_reset = sde_encoder_helper_hw_reset; ops->irq_control = sde_encoder_phys_wb_irq_ctrl; + ops->add_to_minidump = sde_encoder_phys_wb_add_enc_to_minidump; } /** diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 366135eb57..b4fc41e4a3 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -5107,3 +5107,37 @@ int sde_kms_handle_recovery(struct drm_encoder *encoder) SDE_EVT32(DRMID(encoder), MSM_ENC_ACTIVE_REGION); return sde_encoder_wait_for_event(encoder, MSM_ENC_ACTIVE_REGION); } + +void sde_kms_add_data_to_minidump_va(struct sde_kms *sde_kms) +{ + struct msm_drm_private *priv; + struct sde_crtc *sde_crtc; + struct sde_crtc_state *cstate; + struct sde_connector *sde_conn; + struct sde_connector_state *conn_state; + u32 i; + + priv = sde_kms->dev->dev_private; + + sde_mini_dump_add_va_region("sde_kms", sizeof(*sde_kms), sde_kms); + + for (i = 0; i < priv->num_crtcs; i++) { + sde_crtc = to_sde_crtc(priv->crtcs[i]); + cstate = to_sde_crtc_state(priv->crtcs[i]->state); + sde_mini_dump_add_va_region("sde_crtc", sizeof(*sde_crtc), sde_crtc); + sde_mini_dump_add_va_region("crtc_state", sizeof(*cstate), cstate); + } + + for (i = 0; i < priv->num_planes; i++) + sde_plane_add_data_to_minidump_va(priv->planes[i]); + + for (i = 0; i < priv->num_encoders; i++) + sde_encoder_add_data_to_minidump_va(priv->encoders[i]); + + for (i = 0; i < priv->num_connectors; i++) { + sde_conn = to_sde_connector(priv->connectors[i]); + conn_state = to_sde_connector_state(priv->connectors[i]->state); + sde_mini_dump_add_va_region("sde_conn", sizeof(*sde_conn), sde_conn); + sde_mini_dump_add_va_region("conn_state", sizeof(*conn_state), conn_state); + } +} diff --git a/msm/sde/sde_kms.h b/msm/sde/sde_kms.h index fe78d4c727..6181357298 100644 --- a/msm/sde/sde_kms.h +++ b/msm/sde/sde_kms.h @@ -765,4 +765,6 @@ int sde_kms_vm_trusted_prepare_commit(struct sde_kms *sde_kms, */ int sde_kms_vm_primary_prepare_commit(struct sde_kms *sde_kms, struct drm_atomic_state *state); + +void sde_kms_add_data_to_minidump_va(struct sde_kms *sde_kms); #endif /* __sde_kms_H__ */ diff --git a/msm/sde/sde_plane.c b/msm/sde/sde_plane.c index 8c22aa67f6..eb90373ab7 100644 --- a/msm/sde/sde_plane.c +++ b/msm/sde/sde_plane.c @@ -4852,3 +4852,14 @@ clean_plane: exit: return ERR_PTR(ret); } + +void sde_plane_add_data_to_minidump_va(struct drm_plane *plane) +{ + struct sde_plane *sde_plane; + struct sde_plane_state *pstate; + + sde_plane = to_sde_plane(plane); + pstate = to_sde_plane_state(plane->state); + sde_mini_dump_add_va_region("sde_plane", sizeof(*sde_plane), sde_plane); + sde_mini_dump_add_va_region("plane_state", sizeof(*pstate), pstate); +} diff --git a/msm/sde/sde_plane.h b/msm/sde/sde_plane.h index a0a22afe45..56617b9a25 100644 --- a/msm/sde/sde_plane.h +++ b/msm/sde/sde_plane.h @@ -358,4 +358,5 @@ bool sde_plane_is_cache_required(struct drm_plane *plane, void sde_plane_static_img_control(struct drm_plane *plane, enum sde_crtc_cache_state state); +void sde_plane_add_data_to_minidump_va(struct drm_plane *plane); #endif /* _SDE_PLANE_H_ */ diff --git a/msm/sde_dbg.c b/msm/sde_dbg.c index 7b9f0ad916..4c9888b220 100755 --- a/msm/sde_dbg.c +++ b/msm/sde_dbg.c @@ -18,6 +18,7 @@ #include "sde_dbg.h" #include "sde/sde_hw_catalog.h" +#include "sde/sde_kms.h" #define SDE_DBG_BASE_MAX 10 @@ -577,6 +578,95 @@ static u32 _sde_dbg_get_reg_dump_size(void) return size; } +#if IS_ENABLED(CONFIG_QCOM_VA_MINIDUMP) +static void sde_dbg_add_dbg_buses_to_minidump_va(void) +{ + static struct sde_dbg_base *dbg = &sde_dbg_base; + + sde_mini_dump_add_va_region("sde_dbgbus", dbg->dbgbus_sde.cmn.content_size*sizeof(u32), + dbg->dbgbus_sde.cmn.dumped_content); + + sde_mini_dump_add_va_region("vbif_dbgbus", dbg->dbgbus_vbif_rt.cmn.content_size*sizeof(u32), + dbg->dbgbus_vbif_rt.cmn.dumped_content); + + sde_mini_dump_add_va_region("dsi_dbgbus", dbg->dbgbus_dsi.cmn.content_size*sizeof(u32), + dbg->dbgbus_dsi.cmn.dumped_content); + + sde_mini_dump_add_va_region("lutdma_dbgbus", + dbg->dbgbus_lutdma.cmn.content_size*sizeof(u32), + dbg->dbgbus_lutdma.cmn.dumped_content); + + sde_mini_dump_add_va_region("rsc_dbgbus", dbg->dbgbus_rsc.cmn.content_size*sizeof(u32), + dbg->dbgbus_rsc.cmn.dumped_content); + + sde_mini_dump_add_va_region("dp_dbgbus", dbg->dbgbus_dp.cmn.content_size*sizeof(u32), + dbg->dbgbus_dp.cmn.dumped_content); +} + +static int sde_md_notify_handler(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct device *dev = sde_dbg_base.dev; + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *ddev = platform_get_drvdata(pdev); + struct msm_drm_private *priv = ddev->dev_private; + struct sde_kms *sde_kms = to_sde_kms(priv->kms); + struct sde_dbg_base *dbg_base = &sde_dbg_base; + u32 reg_dump_size = _sde_dbg_get_reg_dump_size(); + + sde_mini_dump_add_va_region("msm_drm_priv", sizeof(*priv), priv); + sde_mini_dump_add_va_region("sde_evtlog", + sizeof(*sde_dbg_base_evtlog), sde_dbg_base_evtlog); + sde_mini_dump_add_va_region("sde_reglog", + sizeof(*sde_dbg_base_reglog), sde_dbg_base_reglog); + + sde_mini_dump_add_va_region("sde_reg_dump", reg_dump_size, dbg_base->reg_dump_base); + + sde_dbg_add_dbg_buses_to_minidump_va(); + sde_kms_add_data_to_minidump_va(sde_kms); + + return 0; +} + +static struct notifier_block sde_md_notify_blk = { + .notifier_call = sde_md_notify_handler, + .priority = INT_MAX, +}; + +static int sde_register_md_panic_notifer() +{ + qcom_va_md_register("display", &sde_md_notify_blk); + return 0; +} + +void sde_mini_dump_add_va_region(const char *name, u32 size, void *virt_addr) +{ + struct va_md_entry md_entry; + int ret; + + strlcpy(md_entry.owner, name, sizeof(md_entry.owner)); + md_entry.vaddr = (uintptr_t)virt_addr; + md_entry.size = size; + + ret = qcom_va_md_add_region(&md_entry); + if (ret < 0) + SDE_ERROR("va minudmp add entry failed for %s, returned %d\n", + name, ret); + + return; +} +#else +static int sde_register_md_panic_notifer() +{ + return 0; +} + +void sde_mini_dump_add_va_region(const char *name, u32 size, void *virt_addr) +{ + return; +} +#endif + static int _sde_dump_reg_range_cmp(void *priv, struct list_head *a, struct list_head *b) { @@ -2310,6 +2400,7 @@ int sde_dbg_init(struct device *dev) sde_dbg_base.enable_dbgbus_dump = SDE_DBG_DEFAULT_DUMP_MODE; sde_dbg_base.dump_blk_mask = SDE_DBG_BUILT_IN_ALL; memset(&sde_dbg_base.regbuf, 0, sizeof(sde_dbg_base.regbuf)); + sde_register_md_panic_notifer(); pr_info("evtlog_status: enable:%d, panic:%d, dump:%d\n", sde_dbg_base.evtlog->enable, sde_dbg_base.panic_on_err, diff --git a/msm/sde_dbg.h b/msm/sde_dbg.h index 95598e094e..91b5a8a6e8 100644 --- a/msm/sde_dbg.h +++ b/msm/sde_dbg.h @@ -9,6 +9,7 @@ #include #include #include +#include /* select an uncommon hex value for the limiter */ #define SDE_EVTLOG_DATA_LIMITER (0xC0DEBEEF) @@ -279,6 +280,15 @@ extern struct sde_dbg_reglog *sde_dbg_base_reglog; #define SDE_DBG_CTRL(...) sde_dbg_ctrl(__func__, ##__VA_ARGS__, \ SDE_DBG_DUMP_DATA_LIMITER) +/** + * sde_mini_dump_add_va_region - add required va memory region to minidump. + * @size: size of the memory region to be added + * @name: minidump partition name + * @virt_addr: pointer to memory region + * Returns: none + */ +void sde_mini_dump_add_va_region(const char *name, u32 size, void *virt_addr); + /** * sde_evtlog_init - allocate a new event log object * Returns: evtlog or -ERROR