}
dev->logging_data->fault_addr = (unsigned int)addr;
- s5p_mfc_dump_buffer_info(dev, addr);
call_dop(dev, dump_info, dev);
return 0;
return -ENOENT;
}
+#ifdef CONFIG_EXYNOS_ITMON
+static int mfc_itmon_notifier(struct notifier_block *nb, unsigned long action, void *nb_data)
+{
+ struct s5p_mfc_dev *dev;
+ struct itmon_notifier *itmon_info = nb_data;
+ int is_mfc_itmon = 0, is_master = 0;
+
+ dev = container_of(nb, struct s5p_mfc_dev, itmon_nb);
+
+ if (IS_ERR_OR_NULL(itmon_info))
+ return NOTIFY_DONE;
+
+ /* print dump if it is an MFC ITMON error */
+ if ((strncmp("MFC", itmon_info->port, sizeof("MFC") - 1) == 0) &&
+ (strncmp("MFC", itmon_info->master, sizeof("MFC") - 1) == 0)) {
+ is_mfc_itmon = 1;
+ is_master = 1;
+ } else if (strncmp("MFC", itmon_info->dest, sizeof("MFC") - 1) == 0) {
+ is_mfc_itmon = 1;
+ is_master = 0;
+ }
+
+ if (is_mfc_itmon) {
+ pr_err("mfc_itmon_notifier: MFC +\n");
+ pr_err("MFC is %s.\n", is_master ? "master" : "dest");
+ if (!dev->itmon_notified) {
+ pr_err("dump MFC information.\n");
+ if (is_master || (!is_master && itmon_info->onoff))
+ call_dop(dev, dump_info, dev);
+ else
+ call_dop(dev, dump_info_without_regs, dev);
+ } else {
+ pr_err("MFC notifier has already been called. skip MFC information.\n");
+ }
+ pr_err("mfc_itmon_notifier: MFC -\n");
+ dev->itmon_notified = 1;
+ }
+ return NOTIFY_DONE;
+}
+#endif
+
/* MFC probe function */
static int s5p_mfc_probe(struct platform_device *pdev)
{
goto err_alloc_debug;
}
+#ifdef CONFIG_EXYNOS_ITMON
+ dev->itmon_nb.notifier_call = mfc_itmon_notifier;
+ itmon_notifier_chain_register(&dev->itmon_nb);
+#endif
+
s5p_mfc_init_debugfs(dev);
pr_debug("%s--\n", __func__);
#include <soc/samsung/bts.h>
#endif
#include <linux/videodev2.h>
+#ifdef CONFIG_EXYNOS_ITMON
+#include <soc/samsung/exynos-itmon.h>
+#endif
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
struct s5p_mfc_dump_ops {
void (*dump_regs)(struct s5p_mfc_dev *dev);
void (*dump_info)(struct s5p_mfc_dev *dev);
+ void (*dump_info_without_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_perf perf;
struct s5p_mfc_mmcache mmcache;
+
+#ifdef CONFIG_EXYNOS_ITMON
+ struct notifier_block itmon_nb;
+ int itmon_notified;
+#endif
};
/**
}
}
-void s5p_mfc_dump_buffer_info(struct s5p_mfc_dev *dev, unsigned long addr)
+void mfc_dump_buffer_info(struct s5p_mfc_dev *dev)
{
struct s5p_mfc_ctx *ctx;
ctx = dev->ctx[dev->curr_ctx];
if (ctx) {
- pr_err("-----------dumping MFC buffer info (fault at: %#lx)\n", addr);
+ pr_err("-----------dumping MFC buffer info (fault at: %#x)\n",
+ dev->logging_data->fault_addr);
pr_err("common:%#llx~%#llx, instance:%#llx~%#llx, codec:%#llx~%#llx\n",
dev->common_ctx_buf.daddr,
dev->common_ctx_buf.daddr + PAGE_ALIGN(0x7800),
}
}
-static void mfc_dump_info(struct s5p_mfc_dev *dev)
+static void mfc_dump_info_without_regs(struct s5p_mfc_dev *dev)
{
mfc_display_state(dev);
mfc_print_trace(dev);
+}
+
+static void mfc_dump_info(struct s5p_mfc_dev *dev)
+{
+ mfc_dump_info_without_regs(dev);
mfc_save_logging_sfr(dev);
+ mfc_dump_buffer_info(dev);
mfc_dump_regs(dev);
exynos_sysmmu_show_status(dev->device);
}
struct s5p_mfc_dump_ops mfc_dump_ops = {
.dump_regs = mfc_dump_regs,
.dump_info = mfc_dump_info,
+ .dump_info_without_regs = mfc_dump_info_without_regs,
.dump_and_stop_always = mfc_dump_info_and_stop_hw,
.dump_and_stop_debug_mode = mfc_dump_info_and_stop_hw_debug,
};
#include "s5p_mfc_common.h"
-void s5p_mfc_dump_buffer_info(struct s5p_mfc_dev *dev, unsigned long addr);
void s5p_mfc_watchdog_worker(struct work_struct *work);
#endif /* __S5P_MFC_WATCHDOG_H */