#include <trace/events/mfc.h>
#include "s5p_mfc_cal.h"
+#include "s5p_mfc_pm.h"
/* Reset the device */
int s5p_mfc_reset_mfc(struct s5p_mfc_dev *dev)
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;
+}
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;
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 */
#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 */
struct dentry *otf_dump;
struct dentry *perf_measure_option;
struct dentry *sfr_dump;
+ struct dentry *debug_mode;
};
/**
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);
};
/**
struct s5p_mfc_hwlock hwlock;
+ atomic_t sched_wait_cnt;
atomic_t watchdog_tick_running;
atomic_t watchdog_tick_cnt;
atomic_t watchdog_run;
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 { \
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)
{
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);
}
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",
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",
#include "s5p_mfc_sync.h"
+#include "s5p_mfc_cal.h"
#include "s5p_mfc_perf_measure.h"
#include "s5p_mfc_queue.h"
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;
*/
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;
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;
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);
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 {
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,
};