diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 93a644eda17b..2c55c0711c75 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -38,6 +38,14 @@ #define GSI_STTS_REG_BITS 32 +#define GSI_INST_RAM_FW_VER_OFFSET (0) +#define GSI_INST_RAM_FW_VER_HW_MASK (0xFC00) +#define GSI_INST_RAM_FW_VER_HW_SHIFT (10) +#define GSI_INST_RAM_FW_VER_FLAVOR_MASK (0x380) +#define GSI_INST_RAM_FW_VER_FLAVOR_SHIFT (7) +#define GSI_INST_RAM_FW_VER_FW_MASK (0x7f) +#define GSI_INST_RAM_FW_VER_FW_SHIFT (0) + #ifndef CONFIG_DEBUG_FS void gsi_debugfs_init(void) { @@ -5059,6 +5067,69 @@ static union __packed gsi_channel_scratch __gsi_update_mhi_channel_scratch( return scr; } +/** + * gsi_get_hw_profiling_stats() - Query GSI HW profiling stats + * @stats: [out] stats blob from client populated by driver + * + * Returns: 0 on success, negative on failure + * + */ +int gsi_get_hw_profiling_stats(struct gsi_hw_profiling_data *stats) +{ + if (stats == NULL) { + GSIERR("bad parms NULL stats == NULL\n"); + return -EINVAL; + } + + stats->bp_cnt = (u64)gsi_readl(gsi_ctx->base + + GSI_GSI_MCS_PROFILING_BP_CNT_LSB_OFFS) + + ((u64)gsi_readl(gsi_ctx->base + + GSI_GSI_MCS_PROFILING_BP_CNT_MSB_OFFS) << 32); + stats->bp_and_pending_cnt = (u64)gsi_readl( gsi_ctx->base + + GSI_GSI_MCS_PROFILING_BP_AND_PENDING_CNT_LSB_OFFS) + + ((u64)gsi_readl(gsi_ctx->base + + GSI_GSI_MCS_PROFILING_BP_AND_PENDING_CNT_MSB_OFFS) + << 32); + stats->mcs_busy_cnt = (u64)gsi_readl(gsi_ctx->base + + GSI_GSI_MCS_PROFILING_MCS_BUSY_CNT_LSB_OFFS) + + ((u64)gsi_readl(gsi_ctx->base + + GSI_GSI_MCS_PROFILING_MCS_BUSY_CNT_MSB_OFFS) << 32); + stats->mcs_idle_cnt = (u64)gsi_readl(gsi_ctx->base + + GSI_GSI_MCS_PROFILING_MCS_IDLE_CNT_LSB_OFFS) + + ((u64)gsi_readl(gsi_ctx->base + + GSI_GSI_MCS_PROFILING_MCS_IDLE_CNT_MSB_OFFS) << 32); + + return 0; +} + +/** + * gsi_get_fw_version() - Query GSI FW version + * @ver: [out] ver blob from client populated by driver + * + * Returns: 0 on success, negative on failure + * + */ +int gsi_get_fw_version(struct gsi_fw_version *ver) +{ + u32 raw = 0; + + if (ver == NULL) { + GSIERR("bad parms: ver == NULL\n"); + return -EINVAL; + } + + raw = gsi_readl(gsi_ctx->base + + GSI_V2_5_GSI_INST_RAM_n_OFFS(GSI_INST_RAM_FW_VER_OFFSET)); + + ver->hw = (raw & GSI_INST_RAM_FW_VER_HW_MASK) >> + GSI_INST_RAM_FW_VER_HW_SHIFT; + ver->flavor = (raw & GSI_INST_RAM_FW_VER_FLAVOR_MASK) >> + GSI_INST_RAM_FW_VER_FLAVOR_SHIFT; + ver->fw = (raw & GSI_INST_RAM_FW_VER_FW_MASK) >> + GSI_INST_RAM_FW_VER_FW_SHIFT; + + return 0; +} static int msm_gsi_probe(struct platform_device *pdev) { diff --git a/drivers/platform/msm/gsi/gsi.h b/drivers/platform/msm/gsi/gsi.h index bd60e67528ff..261575ff3542 100644 --- a/drivers/platform/msm/gsi/gsi.h +++ b/drivers/platform/msm/gsi/gsi.h @@ -1412,6 +1412,32 @@ enum gsi_generic_ee_cmd_return_code { GSI_GEN_EE_CMD_RETURN_CODE_OUT_OF_RESOURCES = 0x7, }; +/** + * struct gsi_hw_profiling_data - GSI profiling data + * @bp_cnt_lsb: Back Pressure occurences count + * @bp_and_pending_cnt_lsb: Back Pressure with pending back pressure count + * @mcs_busy_cnt_lsb: Cycle count for MCS busy + * @mcs_idle_cnt_lsb: Cycle count for MCS idle + */ +struct gsi_hw_profiling_data { + u64 bp_cnt; + u64 bp_and_pending_cnt; + u64 mcs_busy_cnt; + u64 mcs_idle_cnt; +}; + +/** + * struct gsi_fw_version - GSI fw version data + * @hw: HW version + * @flavor: Flavor identifier + * @fw: FW version + */ +struct gsi_fw_version { + u32 hw; + u32 flavor; + u32 fw; +}; + enum gsi_generic_ee_cmd_query_retun_val { GSI_GEN_EE_CMD_RETURN_VAL_FLOW_CONTROL_PRIMARY = 0, GSI_GEN_EE_CMD_RETURN_VAL_FLOW_CONTROL_SECONDARY = 1, @@ -2127,6 +2153,25 @@ int gsi_alloc_channel_ee(unsigned int chan_idx, unsigned int ee, int *code); */ int gsi_enable_flow_control_ee(unsigned int chan_idx, unsigned int ee, int *code); + +/** + * gsi_get_hw_profiling_stats() - Query GSI HW profiling stats + * @stats: [out] stats blob from client populated by driver + * + * Returns: 0 on success, negative on failure + * + */ +int gsi_get_hw_profiling_stats(struct gsi_hw_profiling_data *stats); + +/** + * gsi_get_fw_version() - Query GSI FW version + * @ver: [out] ver blob from client populated by driver + * + * Returns: 0 on success, negative on failure + * + */ +int gsi_get_fw_version(struct gsi_fw_version *ver); + int gsi_flow_control_ee(unsigned int chan_idx, unsigned int ee, bool enable, bool prmy_scnd_fc, int *code); int gsi_query_flow_control_state_ee(unsigned int chan_idx, unsigned int ee, diff --git a/drivers/platform/msm/gsi/gsi_dbg.c b/drivers/platform/msm/gsi/gsi_dbg.c index e264ea68250d..5ffd2c8e22f5 100644 --- a/drivers/platform/msm/gsi/gsi_dbg.c +++ b/drivers/platform/msm/gsi/gsi_dbg.c @@ -12,6 +12,8 @@ #include "gsi_reg.h" #include "gsi.h" +#define GSI_MAX_MSG_LEN 4096 + #define TERR(fmt, args...) \ pr_err("%s:%d " fmt, __func__, __LINE__, ## args) #define TDBG(fmt, args...) \ @@ -20,7 +22,7 @@ pr_err(fmt, ## args) static struct dentry *dent; -static char dbg_buff[4096]; +static char dbg_buff[GSI_MAX_MSG_LEN]; static void *gsi_ipc_logbuf_low; static void gsi_wq_print_dp_stats(struct work_struct *work); @@ -662,6 +664,79 @@ static ssize_t gsi_enable_ipc_low(struct file *file, return count; } +static ssize_t gsi_read_gsi_hw_profiling_stats(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + struct gsi_hw_profiling_data stats; + int nbytes, cnt = 0; + u64 totalCycles = 0, util = 0; + + if (gsi_ctx->per.ver < GSI_VER_2_9) { + nbytes = scnprintf(dbg_buff, GSI_MAX_MSG_LEN, + "This feature only support on GSI2.9+\n"); + cnt += nbytes; + goto done; + } + if (!gsi_get_hw_profiling_stats(&stats)) { + totalCycles = stats.mcs_busy_cnt + stats.mcs_idle_cnt + + stats.bp_and_pending_cnt; + if (totalCycles != 0) + util = (100 * (stats.mcs_busy_cnt + stats.bp_and_pending_cnt)) / + totalCycles; + else + util = 0; + + nbytes = scnprintf(dbg_buff, GSI_MAX_MSG_LEN, + "bp_count=0x%llx\n" + "bp_and_pending_count=0x%llx\n" + "mcs_busy=0x%llx\n" + "mcs_idle=0x%llx\n" + "total_cycle_count=0x%llx\n" + "utilization_percentage=%llu%%\n", + stats.bp_cnt, + stats.bp_and_pending_cnt, + stats.mcs_busy_cnt, + stats.mcs_idle_cnt, + totalCycles, + util); + cnt += nbytes; + } else { + nbytes = scnprintf(dbg_buff, GSI_MAX_MSG_LEN, + "Fail to read GSI HW Profiling stats\n"); + cnt += nbytes; + } +done: + return simple_read_from_buffer(buf, count, ppos, dbg_buff, cnt); +} + +static ssize_t gsi_read_gsi_fw_version(struct file *file, + char __user *buf, size_t count, loff_t *ppos) +{ + struct gsi_fw_version ver; + int nbytes, cnt = 0; + + if (gsi_ctx->per.ver < GSI_VER_2_9) { + nbytes = scnprintf(dbg_buff, GSI_MAX_MSG_LEN, + "This feature only support on GSI2.9+\n"); + cnt += nbytes; + goto done; + } + if (!gsi_get_fw_version(&ver)) { + nbytes = scnprintf(dbg_buff, GSI_MAX_MSG_LEN, + "hw=%d\nflavor=%d\nfw=%d\n", + ver.hw, + ver.flavor, + ver.fw); + cnt += nbytes; + } else { + nbytes = scnprintf(dbg_buff, GSI_MAX_MSG_LEN, + "Fail to read GSI FW version\n"); + cnt += nbytes; + } +done: + return simple_read_from_buffer(buf, count, ppos, dbg_buff, cnt); +} + static const struct file_operations gsi_ev_dump_ops = { .write = gsi_dump_evt, }; @@ -694,10 +769,19 @@ static const struct file_operations gsi_ipc_low_ops = { .write = gsi_enable_ipc_low, }; +static const struct file_operations gsi_hw_profiling_ops = { + .read = gsi_read_gsi_hw_profiling_stats, +}; + +static const struct file_operations gsi_ver_ops = { + .read = gsi_read_gsi_fw_version, +}; + void gsi_debugfs_init(void) { static struct dentry *dfile; const mode_t write_only_mode = 0220; + const mode_t read_only_mode = 0440; dent = debugfs_create_dir("gsi", 0); if (IS_ERR(dent)) { @@ -761,8 +845,22 @@ void gsi_debugfs_init(void) goto fail; } + dfile = debugfs_create_file("gsi_hw_profiling_stats", read_only_mode, + dent, 0, &gsi_hw_profiling_ops); + if (!dfile || IS_ERR(dfile)) { + TERR("could not create gsi_hw_profiling_stats\n"); + goto fail; + } + + dfile = debugfs_create_file("gsi_fw_version", read_only_mode, dent, 0, + &gsi_ver_ops); + if (!dfile || IS_ERR(dfile)) { + TERR("could not create gsi_fw_version\n"); + goto fail; + } + return; + fail: debugfs_remove_recursive(dent); } - diff --git a/drivers/platform/msm/gsi/gsi_reg_v2.h b/drivers/platform/msm/gsi/gsi_reg_v2.h index 8fdc83f00ff9..defe28fac99c 100644 --- a/drivers/platform/msm/gsi/gsi_reg_v2.h +++ b/drivers/platform/msm/gsi/gsi_reg_v2.h @@ -1212,4 +1212,44 @@ #define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_PHY_CH_BMSK 0x1f #define GSI_V2_5_GSI_MAP_EE_n_CH_k_VP_TABLE_PHY_CH_SHFT 0x0 +#define GSI_GSI_MCS_PROFILING_BP_CNT_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000185c) +#define GSI_GSI_MCS_PROFILING_BP_CNT_LSB_RMSK 0xffffffff +#define GSI_GSI_MCS_PROFILING_BP_CNT_LSB_SHFT 0x0 + +#define GSI_GSI_MCS_PROFILING_BP_CNT_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00001860) +#define GSI_GSI_MCS_PROFILING_BP_CNT_MSB_RMSK 0xffffffff +#define GSI_GSI_MCS_PROFILING_BP_CNT_MSB_SHFT 0x0 + +#define GSI_GSI_MCS_PROFILING_BP_AND_PENDING_CNT_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00001864) +#define GSI_GSI_MCS_PROFILING_BP_AND_PENDING_CNT_LSB_RMSK 0xffffffff +#define GSI_GSI_MCS_PROFILING_BP_AND_PENDING_CNT_LSB_SHFT 0x0 + +#define GSI_GSI_MCS_PROFILING_BP_AND_PENDING_CNT_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00001868) +#define GSI_GSI_MCS_PROFILING_BP_AND_PENDING_CNT_MSB_RMSK 0xffffffff +#define GSI_GSI_MCS_PROFILING_BP_AND_PENDING_CNT_MSB_SHFT 0x0 + +#define GSI_GSI_MCS_PROFILING_MCS_BUSY_CNT_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x0000186c) +#define GSI_GSI_MCS_PROFILING_MCS_BUSY_CNT_LSB_RMSK 0xffffffff +#define GSI_GSI_MCS_PROFILING_MCS_BUSY_CNT_LSB_SHFT 0x0 + +#define GSI_GSI_MCS_PROFILING_MCS_BUSY_CNT_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00001870) +#define GSI_GSI_MCS_PROFILING_MCS_BUSY_CNT_MSB_RMSK 0xffffffff +#define GSI_GSI_MCS_PROFILING_MCS_BUSY_CNT_MSB_SHFT 0x0 + +#define GSI_GSI_MCS_PROFILING_MCS_IDLE_CNT_LSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00001874) +#define GSI_GSI_MCS_PROFILING_MCS_IDLE_CNT_LSB_RMSK 0xffffffff +#define GSI_GSI_MCS_PROFILING_MCS_IDLE_CNT_LSB_SHFT 0x0 + +#define GSI_GSI_MCS_PROFILING_MCS_IDLE_CNT_MSB_OFFS \ + (GSI_GSI_REG_BASE_OFFS + 0x00001878) +#define GSI_GSI_MCS_PROFILING_MCS_IDLE_CNT_MSB_RMSK 0xffffffff +#define GSI_GSI_MCS_PROFILING_MCS_IDLE_CNT_MSB_SHFT 0x0 + #endif /* __GSI_REG_V2_H__ */