From 511f694ae39b862c153785673ce75d658c138b80 Mon Sep 17 00:00:00 2001 From: Ayoung Sim Date: Fri, 16 Mar 2018 19:36:03 +0900 Subject: [PATCH] media: mfc: DRV3.2: support debugging mode This patch supports the debugging mode, we will enable it during the verification period. First of all, it applies to the timeout of interrupt. Change-Id: I3b1b402a3afadd1fe01d05f9f01c25eb46f43238 Signed-off-by: Ayoung Sim --- .../media/platform/exynos/mfc/s5p_mfc_cal.c | 14 ++++++ .../media/platform/exynos/mfc/s5p_mfc_cal.h | 9 +--- .../platform/exynos/mfc/s5p_mfc_common.h | 6 ++- .../platform/exynos/mfc/s5p_mfc_data_struct.h | 3 ++ .../media/platform/exynos/mfc/s5p_mfc_debug.h | 1 + .../platform/exynos/mfc/s5p_mfc_debugfs.c | 4 ++ .../platform/exynos/mfc/s5p_mfc_hwlock.c | 4 +- .../media/platform/exynos/mfc/s5p_mfc_sync.c | 45 ++++++++++++++++--- .../platform/exynos/mfc/s5p_mfc_watchdog.c | 25 ++++++++--- 9 files changed, 87 insertions(+), 24 deletions(-) diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_cal.c b/drivers/media/platform/exynos/mfc/s5p_mfc_cal.c index b2dcd9c243ae..1914d2658066 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_cal.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_cal.c @@ -13,6 +13,7 @@ #include #include "s5p_mfc_cal.h" +#include "s5p_mfc_pm.h" /* Reset the device */ int s5p_mfc_reset_mfc(struct s5p_mfc_dev *dev) @@ -85,3 +86,16 @@ void s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd) MFC_WRITEL(cmd, S5P_FIMV_HOST2RISC_CMD); MFC_WRITEL(0x1, S5P_FIMV_HOST2RISC_INT); } + +/* Check whether HW interrupt has occurred or not */ +int s5p_mfc_check_risc2host(struct s5p_mfc_dev *dev) +{ + if (s5p_mfc_pm_get_pwr_ref_cnt(dev) && s5p_mfc_pm_get_clk_ref_cnt(dev)) { + if (MFC_READL(S5P_FIMV_RISC2HOST_INT)) + return MFC_READL(S5P_FIMV_RISC2HOST_CMD); + else + return 0; + } + + return 0; +} diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_cal.h b/drivers/media/platform/exynos/mfc/s5p_mfc_cal.h index e8cdc7590cf3..6dfefddc34c5 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_cal.h +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_cal.h @@ -28,14 +28,6 @@ MFC_WRITEL(0, S5P_FIMV_RISC2HOST_INT); \ } while (0) -static inline int s5p_mfc_check_int_cmd(struct s5p_mfc_dev *dev) -{ - if (MFC_READL(S5P_FIMV_RISC2HOST_INT)) - return MFC_READL(S5P_FIMV_RISC2HOST_CMD); - else - return 0; -} - static inline int s5p_mfc_stop_bus(struct s5p_mfc_dev *dev) { unsigned int status; @@ -118,5 +110,6 @@ int s5p_mfc_reset_mfc(struct s5p_mfc_dev *dev); void s5p_mfc_set_risc_base_addr(struct s5p_mfc_dev *dev, enum mfc_buf_usage_type buf_type); void s5p_mfc_cmd_host2risc(struct s5p_mfc_dev *dev, int cmd); +int s5p_mfc_check_risc2host(struct s5p_mfc_dev *dev); #endif /* __S5P_MFC_CAL_H */ diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_common.h b/drivers/media/platform/exynos/mfc/s5p_mfc_common.h index f39cf55d3985..5d9b5c24cbb1 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_common.h +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_common.h @@ -37,11 +37,15 @@ #define MFC_MAX_DRM_CTX 2 /* Interrupt timeout */ -#define MFC_INT_TIMEOUT 5000 +#define MFC_INT_TIMEOUT 4000 /* Interrupt short timeout */ #define MFC_INT_SHORT_TIMEOUT 800 +/* hwlock timeout */ +#define MFC_HWLOCK_TIMEOUT 5000 /* Busy wait timeout */ #define MFC_BW_TIMEOUT 500 +/* Interrupt timeout count*/ +#define MFC_INT_TIMEOUT_CNT 2 /* This value guarantees 299.4msec ~ 2.25sec according to MFC clock (668MHz ~ 89MHz) * releated with S5P_FIMV_DEC_TIMEOUT_VALUE */ diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_data_struct.h b/drivers/media/platform/exynos/mfc/s5p_mfc_data_struct.h index d892b6df4fc8..ddff79fd4bb5 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_data_struct.h +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_data_struct.h @@ -337,6 +337,7 @@ struct s5p_mfc_debugfs { struct dentry *otf_dump; struct dentry *perf_measure_option; struct dentry *sfr_dump; + struct dentry *debug_mode; }; /** @@ -667,6 +668,7 @@ extern struct s5p_mfc_dump_ops mfc_dump_ops; struct s5p_mfc_dump_ops { void (*dump_regs)(struct s5p_mfc_dev *dev); void (*dump_and_stop_always)(struct s5p_mfc_dev *dev); + void (*dump_and_stop_debug_mode)(struct s5p_mfc_dev *dev); }; /** @@ -723,6 +725,7 @@ struct s5p_mfc_dev { struct s5p_mfc_hwlock hwlock; + atomic_t sched_wait_cnt; atomic_t watchdog_tick_running; atomic_t watchdog_tick_cnt; atomic_t watchdog_run; diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_debug.h b/drivers/media/platform/exynos/mfc/s5p_mfc_debug.h index c3eebc00893f..8d626590e93f 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_debug.h +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_debug.h @@ -25,6 +25,7 @@ extern unsigned int nal_q_disable; extern unsigned int nal_q_parallel_disable; extern unsigned int otf_dump; extern unsigned int sfr_dump; +extern unsigned int debug_mode; #define mfc_debug(level, fmt, args...) \ do { \ diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_debugfs.c b/drivers/media/platform/exynos/mfc/s5p_mfc_debugfs.c index ec2f015a9dd1..58a824fc0803 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_debugfs.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_debugfs.c @@ -29,6 +29,8 @@ unsigned int nal_q_parallel_disable; unsigned int otf_dump; unsigned int perf_measure_option; unsigned int sfr_dump; +/* It will be disable after driver is stabilized */ +unsigned int debug_mode = 1; static int mfc_info_show(struct seq_file *s, void *unused) { @@ -149,4 +151,6 @@ void s5p_mfc_init_debugfs(struct s5p_mfc_dev *dev) 0644, debugfs->root, &perf_measure_option); debugfs->sfr_dump = debugfs_create_u32("sfr_dump", 0644, debugfs->root, &sfr_dump); + debugfs->debug_mode = debugfs_create_u32("debug_mode", + 0644, debugfs->root, &debug_mode); } diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_hwlock.c b/drivers/media/platform/exynos/mfc/s5p_mfc_hwlock.c index 095cd3a9c6a0..b379f58ddd5a 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_hwlock.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_hwlock.c @@ -166,7 +166,7 @@ int s5p_mfc_get_hwlock_dev(struct s5p_mfc_dev *dev) ret = wait_event_timeout(dev->hwlock_wq.wait_queue, ((dev->hwlock.transfer_owner == 1) && (dev->hwlock.dev == 1)), - msecs_to_jiffies(MFC_INT_TIMEOUT)); + msecs_to_jiffies(MFC_HWLOCK_TIMEOUT)); MFC_TRACE_DEV_HWLOCK("get_hwlock_dev: before waiting\n"); MFC_TRACE_DEV_HWLOCK(">>dev:0x%lx, bits:0x%lx, owned:%d, wl:%d, trans:%d\n", @@ -258,7 +258,7 @@ int s5p_mfc_get_hwlock_ctx(struct s5p_mfc_ctx *curr_ctx) ret = wait_event_timeout(curr_ctx->hwlock_wq.wait_queue, ((dev->hwlock.transfer_owner == 1) && (test_bit(curr_ctx->num, &dev->hwlock.bits))), - msecs_to_jiffies(MFC_INT_TIMEOUT)); + msecs_to_jiffies(MFC_HWLOCK_TIMEOUT)); MFC_TRACE_CTX_HWLOCK("get_hwlock_ctx: after waiting, ret:%d\n", ret); MFC_TRACE_CTX_HWLOCK(">>dev:0x%lx, bits:0x%lx, owned:%d, wl:%d, trans:%d\n", diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_sync.c b/drivers/media/platform/exynos/mfc/s5p_mfc_sync.c index 66fbf1fbbc49..f318517b0ebf 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_sync.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_sync.c @@ -12,6 +12,7 @@ #include "s5p_mfc_sync.h" +#include "s5p_mfc_cal.h" #include "s5p_mfc_perf_measure.h" #include "s5p_mfc_queue.h" @@ -56,8 +57,22 @@ int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command) if (ret == 0) { mfc_err_dev("Interrupt (dev->int_reason:%d, command:%d) timed out.\n", dev->int_reason, command); + if (s5p_mfc_check_risc2host(dev)) { + ret = wait_event_timeout(dev->cmd_wq, + wait_condition(dev, command), + msecs_to_jiffies(MFC_INT_TIMEOUT * MFC_INT_TIMEOUT_CNT)); + if (ret == 0) { + mfc_err_dev("Timeout: MFC driver waited for upward of %dsec\n", + 3 * MFC_INT_TIMEOUT); + } else { + goto wait_done; + } + } + call_dop(dev, dump_and_stop_debug_mode, dev); return 1; } + +wait_done: mfc_debug(2, "Finished waiting (dev->int_reason:%d, command: %d).\n", dev->int_reason, command); return 0; @@ -71,6 +86,7 @@ int s5p_mfc_wait_for_done_dev(struct s5p_mfc_dev *dev, int command) */ int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, int command) { + struct s5p_mfc_dev *dev = ctx->dev; int ret; unsigned int timeout = MFC_INT_TIMEOUT; @@ -83,15 +99,30 @@ int s5p_mfc_wait_for_done_ctx(struct s5p_mfc_ctx *ctx, int command) if (ret == 0) { mfc_err_ctx("Interrupt (ctx->int_reason:%d, command:%d) timed out.\n", ctx->int_reason, command); - return 1; - } else if (ret > 0) { - if (is_err_cond(ctx)) { - mfc_err_ctx("Finished (ctx->int_reason:%d, command: %d).\n", - ctx->int_reason, command); - mfc_err_ctx("But error (ctx->int_err:%d).\n", ctx->int_err); - return -1; + if (s5p_mfc_check_risc2host(dev)) { + ret = wait_event_timeout(ctx->cmd_wq, + wait_condition(ctx, command), + msecs_to_jiffies(MFC_INT_TIMEOUT * MFC_INT_TIMEOUT_CNT)); + if (ret == 0) { + mfc_err_dev("Timeout: MFC driver waited for upward of %dsec\n", + 3 * MFC_INT_TIMEOUT); + } else { + goto wait_done; + } } + call_dop(dev, dump_and_stop_debug_mode, dev); + return 1; } + +wait_done: + if (is_err_cond(ctx)) { + mfc_err_ctx("Finished (ctx->int_reason:%d, command: %d).\n", + ctx->int_reason, command); + mfc_err_ctx("But error (ctx->int_err:%d).\n", ctx->int_err); + call_dop(dev, dump_and_stop_debug_mode, dev); + return -1; + } + mfc_debug(2, "Finished waiting (ctx->int_reason:%d, command: %d).\n", ctx->int_reason, command); return 0; diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_watchdog.c b/drivers/media/platform/exynos/mfc/s5p_mfc_watchdog.c index c80d9636dcaf..7fbdaeb98066 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_watchdog.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_watchdog.c @@ -275,10 +275,24 @@ static void mfc_dump_info_and_stop_hw(struct s5p_mfc_dev *dev) BUG(); } +static void mfc_dump_info_and_stop_hw_debug(struct s5p_mfc_dev *dev) +{ + if (!debug_mode) + return; + + MFC_TRACE_DEV("** mfc will stop!!!\n"); + mfc_display_state(dev); + mfc_print_trace(dev); + mfc_save_logging_sfr(dev); + mfc_dump_regs(dev); + exynos_sysmmu_show_status(dev->device); + BUG(); +} + void s5p_mfc_watchdog_worker(struct work_struct *work) { struct s5p_mfc_dev *dev; - int cmd = 0; + int cmd; dev = container_of(work, struct s5p_mfc_dev, watchdog_work); @@ -292,16 +306,14 @@ void s5p_mfc_watchdog_worker(struct work_struct *work) return; } - /* Check whether HW interrupt has occured or not */ - if (s5p_mfc_pm_get_pwr_ref_cnt(dev) && s5p_mfc_pm_get_clk_ref_cnt(dev)) - cmd = s5p_mfc_check_int_cmd(dev); + cmd = s5p_mfc_check_risc2host(dev); if (cmd) { if (atomic_read(&dev->watchdog_tick_cnt) == (3 * WATCHDOG_TICK_CNT_TO_START_WATCHDOG)) { mfc_err_dev("MFC driver waited for upward of %dsec\n", - 3 * WATCHDOG_TICK_CNT_TO_START_WATCHDOG); + 3 * WATCHDOG_TICK_CNT_TO_START_WATCHDOG); dev->logging_data->cause |= (1 << MFC_CAUSE_NO_SCHEDULING); } else { - mfc_err_dev("interrupt(%d) is occured, wait scheduling\n", cmd); + mfc_err_dev("interrupt(%d) is occurred, wait scheduling\n", cmd); return; } } else { @@ -322,4 +334,5 @@ void s5p_mfc_watchdog_worker(struct work_struct *work) struct s5p_mfc_dump_ops mfc_dump_ops = { .dump_regs = mfc_dump_regs, .dump_and_stop_always = mfc_dump_info_and_stop_hw, + .dump_and_stop_debug_mode = mfc_dump_info_and_stop_hw_debug, }; -- 2.20.1