Message ID | 1473696075-9190-3-git-send-email-jean-christophe.trotin@st.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Same thing here: this should be enabled in a Kconfig option. That new Kconfig option should depend on DEBUG_FS as well. BTW (independent of these two patches): I think it would be easier to maintain if you make a Kconfig file in the sti directory, rather than adding them to the Kconfig in platform. Regards, Hans On 09/12/2016 06:01 PM, Jean-Christophe Trotin wrote: > This patch creates 4 static debugfs entries to dump: > - the device-related information ("st-hva/device") > - the list of registered encoders ("st-hva/encoders") > - the current values of the hva registers ("st-hva/regs") > - the information about the last closed instance ("st-hva/last") > > It also creates dynamically a debugfs entry for each opened instance, > ("st-hva/<instance identifier>") to dump: > - the information about the stream (profile, level, resolution, > alignment...) > - the control parameters (bitrate mode, framerate, GOP size...) > - the potential (system, encoding...) errors > - the performance information about the encoding (HW processing > duration, average bitrate, average framerate...) > Each time a running instance is closed, its context (including the > debug information) is saved to feed, on demand, the last closed > instance debugfs entry. > > Signed-off-by: Yannick Fertre <yannick.fertre@st.com> > Signed-off-by: Jean-Christophe Trotin <jean-christophe.trotin@st.com> > --- > drivers/media/platform/sti/hva/hva-debug.c | 362 +++++++++++++++++++++++++++++ > drivers/media/platform/sti/hva/hva-hw.c | 39 ++++ > drivers/media/platform/sti/hva/hva-hw.h | 1 + > drivers/media/platform/sti/hva/hva-v4l2.c | 11 +- > drivers/media/platform/sti/hva/hva.h | 86 +++++-- > 5 files changed, 482 insertions(+), 17 deletions(-) > > diff --git a/drivers/media/platform/sti/hva/hva-debug.c b/drivers/media/platform/sti/hva/hva-debug.c > index 71bbf32..433b1d4 100644 > --- a/drivers/media/platform/sti/hva/hva-debug.c > +++ b/drivers/media/platform/sti/hva/hva-debug.c > @@ -5,7 +5,113 @@ > * License terms: GNU General Public License (GPL), version 2 > */ > > +#include <linux/debugfs.h> > + > #include "hva.h" > +#include "hva-hw.h" > + > +static void format_ctx(struct seq_file *s, struct hva_ctx *ctx) > +{ > + struct hva_streaminfo *stream = &ctx->streaminfo; > + struct hva_frameinfo *frame = &ctx->frameinfo; > + struct hva_controls *ctrls = &ctx->ctrls; > + struct hva_ctx_dbg *dbg = &ctx->dbg; > + u32 bitrate_mode, aspect, entropy, vui_sar, sei_fp; > + > + seq_printf(s, "|-%s\n |\n", ctx->name); > + > + seq_printf(s, " |-[%sframe info]\n", > + ctx->flags & HVA_FLAG_FRAMEINFO ? "" : "default "); > + seq_printf(s, " | |- pixel format=%4.4s\n" > + " | |- wxh=%dx%d\n" > + " | |- wxh (w/ encoder alignment constraint)=%dx%d\n" > + " |\n", > + (char *)&frame->pixelformat, > + frame->width, frame->height, > + frame->aligned_width, frame->aligned_height); > + > + seq_printf(s, " |-[%sstream info]\n", > + ctx->flags & HVA_FLAG_STREAMINFO ? "" : "default "); > + seq_printf(s, " | |- stream format=%4.4s\n" > + " | |- wxh=%dx%d\n" > + " | |- %s\n" > + " | |- %s\n" > + " |\n", > + (char *)&stream->streamformat, > + stream->width, stream->height, > + stream->profile, stream->level); > + > + bitrate_mode = V4L2_CID_MPEG_VIDEO_BITRATE_MODE; > + aspect = V4L2_CID_MPEG_VIDEO_ASPECT; > + seq_puts(s, " |-[parameters]\n"); > + seq_printf(s, " | |- %s\n" > + " | |- bitrate=%d bps\n" > + " | |- GOP size=%d\n" > + " | |- video aspect=%s\n" > + " | |- framerate=%d/%d\n", > + v4l2_ctrl_get_menu(bitrate_mode)[ctrls->bitrate_mode], > + ctrls->bitrate, > + ctrls->gop_size, > + v4l2_ctrl_get_menu(aspect)[ctrls->aspect], > + ctrls->time_per_frame.denominator, > + ctrls->time_per_frame.numerator); > + > + entropy = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE; > + vui_sar = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC; > + sei_fp = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE; > + if (stream->streamformat == V4L2_PIX_FMT_H264) { > + seq_printf(s, " | |- %s entropy mode\n" > + " | |- CPB size=%d kB\n" > + " | |- DCT8x8 enable=%s\n" > + " | |- qpmin=%d\n" > + " | |- qpmax=%d\n" > + " | |- PAR enable=%s\n" > + " | |- PAR id=%s\n" > + " | |- SEI frame packing enable=%s\n" > + " | |- SEI frame packing type=%s\n", > + v4l2_ctrl_get_menu(entropy)[ctrls->entropy_mode], > + ctrls->cpb_size, > + ctrls->dct8x8 ? "true" : "false", > + ctrls->qpmin, > + ctrls->qpmax, > + ctrls->vui_sar ? "true" : "false", > + v4l2_ctrl_get_menu(vui_sar)[ctrls->vui_sar_idc], > + ctrls->sei_fp ? "true" : "false", > + v4l2_ctrl_get_menu(sei_fp)[ctrls->sei_fp_type]); > + } > + > + if (dbg->sys_errors || dbg->encode_errors || dbg->frame_errors) { > + seq_puts(s, " |\n |-[errors]\n"); > + seq_printf(s, " | |- system=%d\n" > + " | |- encoding=%d\n" > + " | |- frame=%d\n", > + dbg->sys_errors, > + dbg->encode_errors, > + dbg->frame_errors); > + } > + > + seq_puts(s, " |\n |-[performances]\n"); > + seq_printf(s, " | |- frames encoded=%d\n" > + " | |- avg HW processing duration (0.1ms)=%d [min=%d, max=%d]\n" > + " | |- avg encoding period (0.1ms)=%d [min=%d, max=%d]\n" > + " | |- avg fps (0.1Hz)=%d\n" > + " | |- max reachable fps (0.1Hz)=%d\n" > + " | |- avg bitrate (kbps)=%d [min=%d, max=%d]\n" > + " | |- last bitrate (kbps)=%d\n", > + dbg->cnt_duration, > + dbg->avg_duration, > + dbg->min_duration, > + dbg->max_duration, > + dbg->avg_period, > + dbg->min_period, > + dbg->max_period, > + dbg->avg_fps, > + dbg->max_fps, > + dbg->avg_bitrate, > + dbg->min_bitrate, > + dbg->max_bitrate, > + dbg->last_bitrate); > +} > > /* > * encoding summary > @@ -77,10 +183,52 @@ char *hva_dbg_summary(struct hva_ctx *ctx) > > void hva_dbg_perf_begin(struct hva_ctx *ctx) > { > + u64 div; > + u32 period; > + u32 bitrate; > struct hva_ctx_dbg *dbg = &ctx->dbg; > + ktime_t prev = dbg->begin; > > dbg->begin = ktime_get(); > > + if (dbg->is_valid_period) { > + /* encoding period */ > + div = (u64)ktime_us_delta(dbg->begin, prev); > + do_div(div, 100); > + period = (u32)div; > + dbg->min_period = min(period, dbg->min_period); > + dbg->max_period = max(period, dbg->max_period); > + dbg->total_period += period; > + dbg->cnt_period++; > + > + /* > + * minimum and maximum bitrates are based on the > + * encoding period values upon a window of 32 samples > + */ > + dbg->window_duration += period; > + dbg->cnt_window++; > + if (dbg->cnt_window >= 32) { > + /* > + * bitrate in kbps = (size * 8 / 1000) / > + * (duration / 10000) > + * = size * 80 / duration > + */ > + if (dbg->window_duration > 0) { > + div = (u64)dbg->window_stream_size * 80; > + do_div(div, dbg->window_duration); > + bitrate = (u32)div; > + dbg->last_bitrate = bitrate; > + dbg->min_bitrate = min(bitrate, > + dbg->min_bitrate); > + dbg->max_bitrate = max(bitrate, > + dbg->max_bitrate); > + } > + dbg->window_stream_size = 0; > + dbg->window_duration = 0; > + dbg->cnt_window = 0; > + } > + } > + > /* > * filter sequences valid for performance: > * - begin/begin (no stream available) is an invalid sequence > @@ -118,8 +266,222 @@ void hva_dbg_perf_end(struct hva_ctx *ctx, struct hva_stream *stream) > do_div(div, 100); > duration = (u32)div; > > + dbg->min_duration = min(duration, dbg->min_duration); > + dbg->max_duration = max(duration, dbg->max_duration); > dbg->total_duration += duration; > dbg->cnt_duration++; > > + /* > + * the average bitrate is based on the total stream size > + * and the total encoding periods > + */ > + dbg->total_stream_size += bytesused; > + dbg->window_stream_size += bytesused; > + > dbg->is_valid_period = true; > } > + > +static void hva_dbg_perf_compute(struct hva_ctx *ctx) > +{ > + u64 div; > + struct hva_ctx_dbg *dbg = &ctx->dbg; > + > + if (dbg->cnt_duration > 0) { > + div = (u64)dbg->total_duration; > + do_div(div, dbg->cnt_duration); > + dbg->avg_duration = (u32)div; > + } else { > + dbg->avg_duration = 0; > + } > + > + if (dbg->total_duration > 0) { > + div = (u64)dbg->cnt_duration * 100000; > + do_div(div, dbg->total_duration); > + dbg->max_fps = (u32)div; > + } else { > + dbg->max_fps = 0; > + } > + > + if (dbg->cnt_period > 0) { > + div = (u64)dbg->total_period; > + do_div(div, dbg->cnt_period); > + dbg->avg_period = (u32)div; > + } else { > + dbg->avg_period = 0; > + } > + > + if (dbg->total_period > 0) { > + div = (u64)dbg->cnt_period * 100000; > + do_div(div, dbg->total_period); > + dbg->avg_fps = (u32)div; > + } else { > + dbg->avg_fps = 0; > + } > + > + if (dbg->total_period > 0) { > + /* > + * bitrate in kbps = (video size * 8 / 1000) / > + * (video duration / 10000) > + * = video size * 80 / video duration > + */ > + div = (u64)dbg->total_stream_size * 80; > + do_div(div, dbg->total_period); > + dbg->avg_bitrate = (u32)div; > + } else { > + dbg->avg_bitrate = 0; > + } > +} > + > +/* > + * device debug info > + */ > + > +static int hva_dbg_device(struct seq_file *s, void *data) > +{ > + struct hva_dev *hva = s->private; > + > + seq_printf(s, "[%s]\n", hva->v4l2_dev.name); > + seq_printf(s, "registered as /dev/video%d\n", hva->vdev->num); > + > + return 0; > +} > + > +static int hva_dbg_encoders(struct seq_file *s, void *data) > +{ > + struct hva_dev *hva = s->private; > + unsigned int i = 0; > + > + seq_printf(s, "[encoders]\n|- %d registered encoders:\n", > + hva->nb_of_encoders); > + > + while (hva->encoders[i]) { > + seq_printf(s, "|- %s: %4.4s => %4.4s\n", hva->encoders[i]->name, > + (char *)&hva->encoders[i]->pixelformat, > + (char *)&hva->encoders[i]->streamformat); > + i++; > + } > + > + return 0; > +} > + > +static int hva_dbg_last(struct seq_file *s, void *data) > +{ > + struct hva_dev *hva = s->private; > + struct hva_ctx *last_ctx = &hva->dbg.last_ctx; > + > + if (last_ctx->flags & HVA_FLAG_STREAMINFO) { > + seq_puts(s, "[last encoding]\n"); > + > + hva_dbg_perf_compute(last_ctx); > + format_ctx(s, last_ctx); > + } else { > + seq_puts(s, "[no information recorded about last encoding]\n"); > + } > + > + return 0; > +} > + > +static int hva_dbg_regs(struct seq_file *s, void *data) > +{ > + struct hva_dev *hva = s->private; > + > + hva_hw_dump_regs(hva, s); > + > + return 0; > +} > + > +#define hva_dbg_declare(name) \ > + static int hva_dbg_##name##_open(struct inode *i, struct file *f) \ > + { \ > + return single_open(f, hva_dbg_##name, i->i_private); \ > + } \ > + static const struct file_operations hva_dbg_##name##_fops = { \ > + .open = hva_dbg_##name##_open, \ > + .read = seq_read, \ > + .llseek = seq_lseek, \ > + .release = single_release, \ > + } > + > +#define hva_dbg_create_entry(name) \ > + debugfs_create_file(#name, S_IRUGO, hva->dbg.debugfs_entry, hva, \ > + &hva_dbg_##name##_fops) > + > +hva_dbg_declare(device); > +hva_dbg_declare(encoders); > +hva_dbg_declare(last); > +hva_dbg_declare(regs); > + > +void hva_debugfs_create(struct hva_dev *hva) > +{ > + hva->dbg.debugfs_entry = debugfs_create_dir(HVA_NAME, NULL); > + if (!hva->dbg.debugfs_entry) > + goto err; > + > + if (!hva_dbg_create_entry(device)) > + goto err; > + > + if (!hva_dbg_create_entry(encoders)) > + goto err; > + > + if (!hva_dbg_create_entry(last)) > + goto err; > + > + if (!hva_dbg_create_entry(regs)) > + goto err; > + > + return; > + > +err: > + hva_debugfs_remove(hva); > +} > + > +void hva_debugfs_remove(struct hva_dev *hva) > +{ > + debugfs_remove_recursive(hva->dbg.debugfs_entry); > + hva->dbg.debugfs_entry = NULL; > +} > + > +/* > + * context (instance) debug info > + */ > + > +static int hva_dbg_ctx(struct seq_file *s, void *data) > +{ > + struct hva_ctx *ctx = s->private; > + > + seq_printf(s, "[running encoding %d]\n", ctx->id); > + > + hva_dbg_perf_compute(ctx); > + format_ctx(s, ctx); > + > + return 0; > +} > + > +hva_dbg_declare(ctx); > + > +void hva_dbg_ctx_create(struct hva_ctx *ctx) > +{ > + struct hva_dev *hva = ctx->hva_dev; > + char name[4] = ""; > + > + ctx->dbg.min_duration = UINT_MAX; > + ctx->dbg.min_period = UINT_MAX; > + ctx->dbg.min_bitrate = UINT_MAX; > + > + snprintf(name, sizeof(name), "%d", hva->instance_id); > + > + ctx->dbg.debugfs_entry = debugfs_create_file(name, S_IRUGO, > + hva->dbg.debugfs_entry, > + ctx, &hva_dbg_ctx_fops); > +} > + > +void hva_dbg_ctx_remove(struct hva_ctx *ctx) > +{ > + struct hva_dev *hva = ctx->hva_dev; > + > + if (ctx->flags & HVA_FLAG_STREAMINFO) > + /* save context before removing */ > + memcpy(&hva->dbg.last_ctx, ctx, sizeof(*ctx)); > + > + debugfs_remove(ctx->dbg.debugfs_entry); > +} > diff --git a/drivers/media/platform/sti/hva/hva-hw.c b/drivers/media/platform/sti/hva/hva-hw.c > index c84b860..d395204 100644 > --- a/drivers/media/platform/sti/hva/hva-hw.c > +++ b/drivers/media/platform/sti/hva/hva-hw.c > @@ -9,6 +9,7 @@ > #include <linux/interrupt.h> > #include <linux/platform_device.h> > #include <linux/pm_runtime.h> > +#include <linux/seq_file.h> > > #include "hva.h" > #include "hva-hw.h" > @@ -541,3 +542,41 @@ out: > > return ret; > } > + > +#define DUMP(reg) seq_printf(s, "%-30s: 0x%08X\n",\ > + #reg, readl_relaxed(hva->regs + reg)) > + > +void hva_hw_dump_regs(struct hva_dev *hva, struct seq_file *s) > +{ > + struct device *dev = hva_to_dev(hva); > + > + mutex_lock(&hva->protect_mutex); > + > + if (pm_runtime_get_sync(dev) < 0) { > + seq_puts(s, "Cannot wake up IP\n"); > + mutex_unlock(&hva->protect_mutex); > + return; > + } > + > + seq_printf(s, "Registers:\nReg @ = 0x%p\n", hva->regs); > + > + DUMP(HVA_HIF_REG_RST); > + DUMP(HVA_HIF_REG_RST_ACK); > + DUMP(HVA_HIF_REG_MIF_CFG); > + DUMP(HVA_HIF_REG_HEC_MIF_CFG); > + DUMP(HVA_HIF_REG_CFL); > + DUMP(HVA_HIF_REG_SFL); > + DUMP(HVA_HIF_REG_LMI_ERR); > + DUMP(HVA_HIF_REG_EMI_ERR); > + DUMP(HVA_HIF_REG_HEC_MIF_ERR); > + DUMP(HVA_HIF_REG_HEC_STS); > + DUMP(HVA_HIF_REG_HVC_STS); > + DUMP(HVA_HIF_REG_HJE_STS); > + DUMP(HVA_HIF_REG_CNT); > + DUMP(HVA_HIF_REG_HEC_CHKSYN_DIS); > + DUMP(HVA_HIF_REG_CLK_GATING); > + DUMP(HVA_HIF_REG_VERSION); > + > + pm_runtime_put_autosuspend(dev); > + mutex_unlock(&hva->protect_mutex); > +} > diff --git a/drivers/media/platform/sti/hva/hva-hw.h b/drivers/media/platform/sti/hva/hva-hw.h > index efb45b9..f8df405 100644 > --- a/drivers/media/platform/sti/hva/hva-hw.h > +++ b/drivers/media/platform/sti/hva/hva-hw.h > @@ -38,5 +38,6 @@ int hva_hw_runtime_suspend(struct device *dev); > int hva_hw_runtime_resume(struct device *dev); > int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd, > struct hva_buffer *task); > +void hva_hw_dump_regs(struct hva_dev *hva, struct seq_file *s); > > #endif /* HVA_HW_H */ > diff --git a/drivers/media/platform/sti/hva/hva-v4l2.c b/drivers/media/platform/sti/hva/hva-v4l2.c > index fb65816..71bb7b3 100644 > --- a/drivers/media/platform/sti/hva/hva-v4l2.c > +++ b/drivers/media/platform/sti/hva/hva-v4l2.c > @@ -15,8 +15,6 @@ > #include "hva.h" > #include "hva-hw.h" > > -#define HVA_NAME "st-hva" > - > #define MIN_FRAMES 1 > #define MIN_STREAMS 1 > > @@ -1181,6 +1179,8 @@ static int hva_open(struct file *file) > /* default parameters for frame and stream */ > set_default_params(ctx); > > + hva_dbg_ctx_create(ctx); > + > dev_info(dev, "%s encoder instance created\n", ctx->name); > > return 0; > @@ -1223,6 +1223,8 @@ static int hva_release(struct file *file) > v4l2_fh_del(&ctx->fh); > v4l2_fh_exit(&ctx->fh); > > + hva_dbg_ctx_remove(ctx); > + > dev_info(dev, "%s encoder instance released\n", ctx->name); > > kfree(ctx); > @@ -1347,6 +1349,8 @@ static int hva_probe(struct platform_device *pdev) > goto err_hw; > } > > + hva_debugfs_create(hva); > + > hva->work_queue = create_workqueue(HVA_NAME); > if (!hva->work_queue) { > dev_err(dev, "%s %s failed to allocate work queue\n", > @@ -1368,6 +1372,7 @@ static int hva_probe(struct platform_device *pdev) > err_work_queue: > destroy_workqueue(hva->work_queue); > err_v4l2: > + hva_debugfs_remove(hva); > v4l2_device_unregister(&hva->v4l2_dev); > err_hw: > hva_hw_remove(hva); > @@ -1386,6 +1391,8 @@ static int hva_remove(struct platform_device *pdev) > > hva_hw_remove(hva); > > + hva_debugfs_remove(hva); > + > v4l2_device_unregister(&hva->v4l2_dev); > > dev_info(dev, "%s %s removed\n", HVA_PREFIX, pdev->name); > diff --git a/drivers/media/platform/sti/hva/hva.h b/drivers/media/platform/sti/hva/hva.h > index badc5f4..eef9769 100644 > --- a/drivers/media/platform/sti/hva/hva.h > +++ b/drivers/media/platform/sti/hva/hva.h > @@ -21,7 +21,8 @@ > > #define ctx_to_hdev(c) (c->hva_dev) > > -#define HVA_PREFIX "[---:----]" > +#define HVA_NAME "st-hva" > +#define HVA_PREFIX "[---:----]" > > extern const struct hva_enc nv12h264enc; > extern const struct hva_enc nv21h264enc; > @@ -156,22 +157,60 @@ struct hva_stream { > /** > * struct hva_ctx_dbg - instance context debug info > * > - * @is_valid_period: true if the sequence is valid for performance > - * @begin: start time of last HW task > - * @total_duration: total HW processing durations in 0.1ms > - * @cnt_duration: number of HW processings > - * @sys_errors: number of system errors (memory, resource, pm..) > - * @encode_errors: number of encoding errors (hw/driver errors) > - * @frame_errors: number of frame errors (format, size, header...) > + * @debugfs_entry: debugfs entry > + * @is_valid_period: true if the sequence is valid for performance > + * @begin: start time of last HW task > + * @total_duration: total HW processing durations in 0.1ms > + * @cnt_duration: number of HW processings > + * @min_duration: minimum HW processing duration in 0.1ms > + * @max_duration: maximum HW processing duration in 0.1ms > + * @avg_duration: average HW processing duration in 0.1ms > + * @max_fps: maximum frames encoded per second (in 0.1Hz) > + * @total_period: total encoding periods in 0.1ms > + * @cnt_period: number of periods > + * @min_period: minimum encoding period in 0.1ms > + * @max_period: maximum encoding period in 0.1ms > + * @avg_period: average encoding period in 0.1ms > + * @total_stream_size: total number of encoded bytes > + * @avg_fps: average frames encoded per second (in 0.1Hz) > + * @window_duration: duration of the sampling window in 0.1ms > + * @cnt_window: number of samples in the window > + * @window_stream_size: number of encoded bytes upon the sampling window > + * @last_bitrate: bitrate upon the last sampling window > + * @min_bitrate: minimum bitrate in kbps > + * @max_bitrate: maximum bitrate in kbps > + * @avg_bitrate: average bitrate in kbps > + * @sys_errors: number of system errors (memory, resource, pm..) > + * @encode_errors: number of encoding errors (hw/driver errors) > + * @frame_errors: number of frame errors (format, size, header...) > */ > struct hva_ctx_dbg { > - bool is_valid_period; > - ktime_t begin; > - u32 total_duration; > - u32 cnt_duration; > - u32 sys_errors; > - u32 encode_errors; > - u32 frame_errors; > + struct dentry *debugfs_entry; > + bool is_valid_period; > + ktime_t begin; > + u32 total_duration; > + u32 cnt_duration; > + u32 min_duration; > + u32 max_duration; > + u32 avg_duration; > + u32 max_fps; > + u32 total_period; > + u32 cnt_period; > + u32 min_period; > + u32 max_period; > + u32 avg_period; > + u32 total_stream_size; > + u32 avg_fps; > + u32 window_duration; > + u32 cnt_window; > + u32 window_stream_size; > + u32 last_bitrate; > + u32 min_bitrate; > + u32 max_bitrate; > + u32 avg_bitrate; > + u32 sys_errors; > + u32 encode_errors; > + u32 frame_errors; > }; > > struct hva_dev; > @@ -235,6 +274,17 @@ struct hva_ctx { > #define HVA_FLAG_STREAMINFO 0x0001 > #define HVA_FLAG_FRAMEINFO 0x0002 > > +/** > + * struct hva_dev_dbg - device debug info > + * > + * @debugfs_entry: debugfs entry > + * @last_ctx: debug information about last running instance context > + */ > +struct hva_dev_dbg { > + struct dentry *debugfs_entry; > + struct hva_ctx last_ctx; > +}; > + > #define HVA_MAX_INSTANCES 16 > #define HVA_MAX_ENCODERS 10 > #define HVA_MAX_FORMATS HVA_MAX_ENCODERS > @@ -273,6 +323,7 @@ struct hva_ctx { > * @lmi_err_reg: local memory interface error register value > * @emi_err_reg: external memory interface error register value > * @hec_mif_err_reg: HEC memory interface error register value > + * @dbg: device debug info > */ > struct hva_dev { > struct v4l2_device v4l2_dev; > @@ -307,6 +358,7 @@ struct hva_dev { > u32 lmi_err_reg; > u32 emi_err_reg; > u32 hec_mif_err_reg; > + struct hva_dev_dbg dbg; > }; > > /** > @@ -335,6 +387,10 @@ struct hva_enc { > struct hva_stream *stream); > }; > > +void hva_debugfs_create(struct hva_dev *hva); > +void hva_debugfs_remove(struct hva_dev *hva); > +void hva_dbg_ctx_create(struct hva_ctx *ctx); > +void hva_dbg_ctx_remove(struct hva_ctx *ctx); > char *hva_dbg_summary(struct hva_ctx *ctx); > void hva_dbg_perf_begin(struct hva_ctx *ctx); > void hva_dbg_perf_end(struct hva_ctx *ctx, struct hva_stream *stream); > -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 09/15/2016 12:30 PM, Hans Verkuil wrote: > Same thing here: this should be enabled in a Kconfig option. That new Kconfig > option should depend on DEBUG_FS as well. > > BTW (independent of these two patches): I think it would be easier to maintain > if you make a Kconfig file in the sti directory, rather than adding them to the > Kconfig in platform. > > Regards, > > Hans Hi Hans, Thank you for your remarks about the 2 debug patches for HVA. I've just sent a version 2 with the following propositions: - the encoding summary (first patch) doesn't include any longer information about the encoding performance. There's no more computation in this patch (hva_dbg_perf_begin and hva_dbg_perf_end removed). Thus, there's no potential penalty on the encoding performance. So, I propose that the short summary (very useful to easily get a status about the encoding operation) is always enabled (dev_info). - for the second patch, I propose that the computation of the performances (hva_dbg_perf_begin and hva_dbg_perf_end) is conditioned by CONFIG_DEBUG_FS. It avoids the definition of a new Kconfig option (mkt-vpu also uses CONFIG_DEBUG_FS). As to the functions that manage the debugfs entries (hva_*_create/remove), I propose that they are called even if DEBUG_FS is disabled: in this case, thanks to the debugfs API, the entries will simply not created. Finally, I think that your proposition of having a Kconfig in the sti directory makes sense. It might be part of a different patch series dealing with the "sti coherency" (we discussed about that on IRC with Benjamin Gaignard few weeks ago). Regards, Jean-Christophe. > > On 09/12/2016 06:01 PM, Jean-Christophe Trotin wrote: >> This patch creates 4 static debugfs entries to dump: >> - the device-related information ("st-hva/device") >> - the list of registered encoders ("st-hva/encoders") >> - the current values of the hva registers ("st-hva/regs") >> - the information about the last closed instance ("st-hva/last") >> >> It also creates dynamically a debugfs entry for each opened instance, >> ("st-hva/<instance identifier>") to dump: >> - the information about the stream (profile, level, resolution, >> alignment...) >> - the control parameters (bitrate mode, framerate, GOP size...) >> - the potential (system, encoding...) errors >> - the performance information about the encoding (HW processing >> duration, average bitrate, average framerate...) >> Each time a running instance is closed, its context (including the >> debug information) is saved to feed, on demand, the last closed >> instance debugfs entry. >> >> Signed-off-by: Yannick Fertre <yannick.fertre@st.com> >> Signed-off-by: Jean-Christophe Trotin <jean-christophe.trotin@st.com> >> --- >> drivers/media/platform/sti/hva/hva-debug.c | 362 +++++++++++++++++++++++++++++ >> drivers/media/platform/sti/hva/hva-hw.c | 39 ++++ >> drivers/media/platform/sti/hva/hva-hw.h | 1 + >> drivers/media/platform/sti/hva/hva-v4l2.c | 11 +- >> drivers/media/platform/sti/hva/hva.h | 86 +++++-- >> 5 files changed, 482 insertions(+), 17 deletions(-) >> >> diff --git a/drivers/media/platform/sti/hva/hva-debug.c b/drivers/media/platform/sti/hva/hva-debug.c >> index 71bbf32..433b1d4 100644 >> --- a/drivers/media/platform/sti/hva/hva-debug.c >> +++ b/drivers/media/platform/sti/hva/hva-debug.c >> @@ -5,7 +5,113 @@ >> * License terms: GNU General Public License (GPL), version 2 >> */ >> >> +#include <linux/debugfs.h> >> + >> #include "hva.h" >> +#include "hva-hw.h" >> + >> +static void format_ctx(struct seq_file *s, struct hva_ctx *ctx) >> +{ >> + struct hva_streaminfo *stream = &ctx->streaminfo; >> + struct hva_frameinfo *frame = &ctx->frameinfo; >> + struct hva_controls *ctrls = &ctx->ctrls; >> + struct hva_ctx_dbg *dbg = &ctx->dbg; >> + u32 bitrate_mode, aspect, entropy, vui_sar, sei_fp; >> + >> + seq_printf(s, "|-%s\n |\n", ctx->name); >> + >> + seq_printf(s, " |-[%sframe info]\n", >> + ctx->flags & HVA_FLAG_FRAMEINFO ? "" : "default "); >> + seq_printf(s, " | |- pixel format=%4.4s\n" >> + " | |- wxh=%dx%d\n" >> + " | |- wxh (w/ encoder alignment constraint)=%dx%d\n" >> + " |\n", >> + (char *)&frame->pixelformat, >> + frame->width, frame->height, >> + frame->aligned_width, frame->aligned_height); >> + >> + seq_printf(s, " |-[%sstream info]\n", >> + ctx->flags & HVA_FLAG_STREAMINFO ? "" : "default "); >> + seq_printf(s, " | |- stream format=%4.4s\n" >> + " | |- wxh=%dx%d\n" >> + " | |- %s\n" >> + " | |- %s\n" >> + " |\n", >> + (char *)&stream->streamformat, >> + stream->width, stream->height, >> + stream->profile, stream->level); >> + >> + bitrate_mode = V4L2_CID_MPEG_VIDEO_BITRATE_MODE; >> + aspect = V4L2_CID_MPEG_VIDEO_ASPECT; >> + seq_puts(s, " |-[parameters]\n"); >> + seq_printf(s, " | |- %s\n" >> + " | |- bitrate=%d bps\n" >> + " | |- GOP size=%d\n" >> + " | |- video aspect=%s\n" >> + " | |- framerate=%d/%d\n", >> + v4l2_ctrl_get_menu(bitrate_mode)[ctrls->bitrate_mode], >> + ctrls->bitrate, >> + ctrls->gop_size, >> + v4l2_ctrl_get_menu(aspect)[ctrls->aspect], >> + ctrls->time_per_frame.denominator, >> + ctrls->time_per_frame.numerator); >> + >> + entropy = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE; >> + vui_sar = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC; >> + sei_fp = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE; >> + if (stream->streamformat == V4L2_PIX_FMT_H264) { >> + seq_printf(s, " | |- %s entropy mode\n" >> + " | |- CPB size=%d kB\n" >> + " | |- DCT8x8 enable=%s\n" >> + " | |- qpmin=%d\n" >> + " | |- qpmax=%d\n" >> + " | |- PAR enable=%s\n" >> + " | |- PAR id=%s\n" >> + " | |- SEI frame packing enable=%s\n" >> + " | |- SEI frame packing type=%s\n", >> + v4l2_ctrl_get_menu(entropy)[ctrls->entropy_mode], >> + ctrls->cpb_size, >> + ctrls->dct8x8 ? "true" : "false", >> + ctrls->qpmin, >> + ctrls->qpmax, >> + ctrls->vui_sar ? "true" : "false", >> + v4l2_ctrl_get_menu(vui_sar)[ctrls->vui_sar_idc], >> + ctrls->sei_fp ? "true" : "false", >> + v4l2_ctrl_get_menu(sei_fp)[ctrls->sei_fp_type]); >> + } >> + >> + if (dbg->sys_errors || dbg->encode_errors || dbg->frame_errors) { >> + seq_puts(s, " |\n |-[errors]\n"); >> + seq_printf(s, " | |- system=%d\n" >> + " | |- encoding=%d\n" >> + " | |- frame=%d\n", >> + dbg->sys_errors, >> + dbg->encode_errors, >> + dbg->frame_errors); >> + } >> + >> + seq_puts(s, " |\n |-[performances]\n"); >> + seq_printf(s, " | |- frames encoded=%d\n" >> + " | |- avg HW processing duration (0.1ms)=%d [min=%d, max=%d]\n" >> + " | |- avg encoding period (0.1ms)=%d [min=%d, max=%d]\n" >> + " | |- avg fps (0.1Hz)=%d\n" >> + " | |- max reachable fps (0.1Hz)=%d\n" >> + " | |- avg bitrate (kbps)=%d [min=%d, max=%d]\n" >> + " | |- last bitrate (kbps)=%d\n", >> + dbg->cnt_duration, >> + dbg->avg_duration, >> + dbg->min_duration, >> + dbg->max_duration, >> + dbg->avg_period, >> + dbg->min_period, >> + dbg->max_period, >> + dbg->avg_fps, >> + dbg->max_fps, >> + dbg->avg_bitrate, >> + dbg->min_bitrate, >> + dbg->max_bitrate, >> + dbg->last_bitrate); >> +} >> >> /* >> * encoding summary >> @@ -77,10 +183,52 @@ char *hva_dbg_summary(struct hva_ctx *ctx) >> >> void hva_dbg_perf_begin(struct hva_ctx *ctx) >> { >> + u64 div; >> + u32 period; >> + u32 bitrate; >> struct hva_ctx_dbg *dbg = &ctx->dbg; >> + ktime_t prev = dbg->begin; >> >> dbg->begin = ktime_get(); >> >> + if (dbg->is_valid_period) { >> + /* encoding period */ >> + div = (u64)ktime_us_delta(dbg->begin, prev); >> + do_div(div, 100); >> + period = (u32)div; >> + dbg->min_period = min(period, dbg->min_period); >> + dbg->max_period = max(period, dbg->max_period); >> + dbg->total_period += period; >> + dbg->cnt_period++; >> + >> + /* >> + * minimum and maximum bitrates are based on the >> + * encoding period values upon a window of 32 samples >> + */ >> + dbg->window_duration += period; >> + dbg->cnt_window++; >> + if (dbg->cnt_window >= 32) { >> + /* >> + * bitrate in kbps = (size * 8 / 1000) / >> + * (duration / 10000) >> + * = size * 80 / duration >> + */ >> + if (dbg->window_duration > 0) { >> + div = (u64)dbg->window_stream_size * 80; >> + do_div(div, dbg->window_duration); >> + bitrate = (u32)div; >> + dbg->last_bitrate = bitrate; >> + dbg->min_bitrate = min(bitrate, >> + dbg->min_bitrate); >> + dbg->max_bitrate = max(bitrate, >> + dbg->max_bitrate); >> + } >> + dbg->window_stream_size = 0; >> + dbg->window_duration = 0; >> + dbg->cnt_window = 0; >> + } >> + } >> + >> /* >> * filter sequences valid for performance: >> * - begin/begin (no stream available) is an invalid sequence >> @@ -118,8 +266,222 @@ void hva_dbg_perf_end(struct hva_ctx *ctx, struct hva_stream *stream) >> do_div(div, 100); >> duration = (u32)div; >> >> + dbg->min_duration = min(duration, dbg->min_duration); >> + dbg->max_duration = max(duration, dbg->max_duration); >> dbg->total_duration += duration; >> dbg->cnt_duration++; >> >> + /* >> + * the average bitrate is based on the total stream size >> + * and the total encoding periods >> + */ >> + dbg->total_stream_size += bytesused; >> + dbg->window_stream_size += bytesused; >> + >> dbg->is_valid_period = true; >> } >> + >> +static void hva_dbg_perf_compute(struct hva_ctx *ctx) >> +{ >> + u64 div; >> + struct hva_ctx_dbg *dbg = &ctx->dbg; >> + >> + if (dbg->cnt_duration > 0) { >> + div = (u64)dbg->total_duration; >> + do_div(div, dbg->cnt_duration); >> + dbg->avg_duration = (u32)div; >> + } else { >> + dbg->avg_duration = 0; >> + } >> + >> + if (dbg->total_duration > 0) { >> + div = (u64)dbg->cnt_duration * 100000; >> + do_div(div, dbg->total_duration); >> + dbg->max_fps = (u32)div; >> + } else { >> + dbg->max_fps = 0; >> + } >> + >> + if (dbg->cnt_period > 0) { >> + div = (u64)dbg->total_period; >> + do_div(div, dbg->cnt_period); >> + dbg->avg_period = (u32)div; >> + } else { >> + dbg->avg_period = 0; >> + } >> + >> + if (dbg->total_period > 0) { >> + div = (u64)dbg->cnt_period * 100000; >> + do_div(div, dbg->total_period); >> + dbg->avg_fps = (u32)div; >> + } else { >> + dbg->avg_fps = 0; >> + } >> + >> + if (dbg->total_period > 0) { >> + /* >> + * bitrate in kbps = (video size * 8 / 1000) / >> + * (video duration / 10000) >> + * = video size * 80 / video duration >> + */ >> + div = (u64)dbg->total_stream_size * 80; >> + do_div(div, dbg->total_period); >> + dbg->avg_bitrate = (u32)div; >> + } else { >> + dbg->avg_bitrate = 0; >> + } >> +} >> + >> +/* >> + * device debug info >> + */ >> + >> +static int hva_dbg_device(struct seq_file *s, void *data) >> +{ >> + struct hva_dev *hva = s->private; >> + >> + seq_printf(s, "[%s]\n", hva->v4l2_dev.name); >> + seq_printf(s, "registered as /dev/video%d\n", hva->vdev->num); >> + >> + return 0; >> +} >> + >> +static int hva_dbg_encoders(struct seq_file *s, void *data) >> +{ >> + struct hva_dev *hva = s->private; >> + unsigned int i = 0; >> + >> + seq_printf(s, "[encoders]\n|- %d registered encoders:\n", >> + hva->nb_of_encoders); >> + >> + while (hva->encoders[i]) { >> + seq_printf(s, "|- %s: %4.4s => %4.4s\n", hva->encoders[i]->name, >> + (char *)&hva->encoders[i]->pixelformat, >> + (char *)&hva->encoders[i]->streamformat); >> + i++; >> + } >> + >> + return 0; >> +} >> + >> +static int hva_dbg_last(struct seq_file *s, void *data) >> +{ >> + struct hva_dev *hva = s->private; >> + struct hva_ctx *last_ctx = &hva->dbg.last_ctx; >> + >> + if (last_ctx->flags & HVA_FLAG_STREAMINFO) { >> + seq_puts(s, "[last encoding]\n"); >> + >> + hva_dbg_perf_compute(last_ctx); >> + format_ctx(s, last_ctx); >> + } else { >> + seq_puts(s, "[no information recorded about last encoding]\n"); >> + } >> + >> + return 0; >> +} >> + >> +static int hva_dbg_regs(struct seq_file *s, void *data) >> +{ >> + struct hva_dev *hva = s->private; >> + >> + hva_hw_dump_regs(hva, s); >> + >> + return 0; >> +} >> + >> +#define hva_dbg_declare(name) \ >> + static int hva_dbg_##name##_open(struct inode *i, struct file *f) \ >> + { \ >> + return single_open(f, hva_dbg_##name, i->i_private); \ >> + } \ >> + static const struct file_operations hva_dbg_##name##_fops = { \ >> + .open = hva_dbg_##name##_open, \ >> + .read = seq_read, \ >> + .llseek = seq_lseek, \ >> + .release = single_release, \ >> + } >> + >> +#define hva_dbg_create_entry(name) \ >> + debugfs_create_file(#name, S_IRUGO, hva->dbg.debugfs_entry, hva, \ >> + &hva_dbg_##name##_fops) >> + >> +hva_dbg_declare(device); >> +hva_dbg_declare(encoders); >> +hva_dbg_declare(last); >> +hva_dbg_declare(regs); >> + >> +void hva_debugfs_create(struct hva_dev *hva) >> +{ >> + hva->dbg.debugfs_entry = debugfs_create_dir(HVA_NAME, NULL); >> + if (!hva->dbg.debugfs_entry) >> + goto err; >> + >> + if (!hva_dbg_create_entry(device)) >> + goto err; >> + >> + if (!hva_dbg_create_entry(encoders)) >> + goto err; >> + >> + if (!hva_dbg_create_entry(last)) >> + goto err; >> + >> + if (!hva_dbg_create_entry(regs)) >> + goto err; >> + >> + return; >> + >> +err: >> + hva_debugfs_remove(hva); >> +} >> + >> +void hva_debugfs_remove(struct hva_dev *hva) >> +{ >> + debugfs_remove_recursive(hva->dbg.debugfs_entry); >> + hva->dbg.debugfs_entry = NULL; >> +} >> + >> +/* >> + * context (instance) debug info >> + */ >> + >> +static int hva_dbg_ctx(struct seq_file *s, void *data) >> +{ >> + struct hva_ctx *ctx = s->private; >> + >> + seq_printf(s, "[running encoding %d]\n", ctx->id); >> + >> + hva_dbg_perf_compute(ctx); >> + format_ctx(s, ctx); >> + >> + return 0; >> +} >> + >> +hva_dbg_declare(ctx); >> + >> +void hva_dbg_ctx_create(struct hva_ctx *ctx) >> +{ >> + struct hva_dev *hva = ctx->hva_dev; >> + char name[4] = ""; >> + >> + ctx->dbg.min_duration = UINT_MAX; >> + ctx->dbg.min_period = UINT_MAX; >> + ctx->dbg.min_bitrate = UINT_MAX; >> + >> + snprintf(name, sizeof(name), "%d", hva->instance_id); >> + >> + ctx->dbg.debugfs_entry = debugfs_create_file(name, S_IRUGO, >> + hva->dbg.debugfs_entry, >> + ctx, &hva_dbg_ctx_fops); >> +} >> + >> +void hva_dbg_ctx_remove(struct hva_ctx *ctx) >> +{ >> + struct hva_dev *hva = ctx->hva_dev; >> + >> + if (ctx->flags & HVA_FLAG_STREAMINFO) >> + /* save context before removing */ >> + memcpy(&hva->dbg.last_ctx, ctx, sizeof(*ctx)); >> + >> + debugfs_remove(ctx->dbg.debugfs_entry); >> +} >> diff --git a/drivers/media/platform/sti/hva/hva-hw.c b/drivers/media/platform/sti/hva/hva-hw.c >> index c84b860..d395204 100644 >> --- a/drivers/media/platform/sti/hva/hva-hw.c >> +++ b/drivers/media/platform/sti/hva/hva-hw.c >> @@ -9,6 +9,7 @@ >> #include <linux/interrupt.h> >> #include <linux/platform_device.h> >> #include <linux/pm_runtime.h> >> +#include <linux/seq_file.h> >> >> #include "hva.h" >> #include "hva-hw.h" >> @@ -541,3 +542,41 @@ out: >> >> return ret; >> } >> + >> +#define DUMP(reg) seq_printf(s, "%-30s: 0x%08X\n",\ >> + #reg, readl_relaxed(hva->regs + reg)) >> + >> +void hva_hw_dump_regs(struct hva_dev *hva, struct seq_file *s) >> +{ >> + struct device *dev = hva_to_dev(hva); >> + >> + mutex_lock(&hva->protect_mutex); >> + >> + if (pm_runtime_get_sync(dev) < 0) { >> + seq_puts(s, "Cannot wake up IP\n"); >> + mutex_unlock(&hva->protect_mutex); >> + return; >> + } >> + >> + seq_printf(s, "Registers:\nReg @ = 0x%p\n", hva->regs); >> + >> + DUMP(HVA_HIF_REG_RST); >> + DUMP(HVA_HIF_REG_RST_ACK); >> + DUMP(HVA_HIF_REG_MIF_CFG); >> + DUMP(HVA_HIF_REG_HEC_MIF_CFG); >> + DUMP(HVA_HIF_REG_CFL); >> + DUMP(HVA_HIF_REG_SFL); >> + DUMP(HVA_HIF_REG_LMI_ERR); >> + DUMP(HVA_HIF_REG_EMI_ERR); >> + DUMP(HVA_HIF_REG_HEC_MIF_ERR); >> + DUMP(HVA_HIF_REG_HEC_STS); >> + DUMP(HVA_HIF_REG_HVC_STS); >> + DUMP(HVA_HIF_REG_HJE_STS); >> + DUMP(HVA_HIF_REG_CNT); >> + DUMP(HVA_HIF_REG_HEC_CHKSYN_DIS); >> + DUMP(HVA_HIF_REG_CLK_GATING); >> + DUMP(HVA_HIF_REG_VERSION); >> + >> + pm_runtime_put_autosuspend(dev); >> + mutex_unlock(&hva->protect_mutex); >> +} >> diff --git a/drivers/media/platform/sti/hva/hva-hw.h b/drivers/media/platform/sti/hva/hva-hw.h >> index efb45b9..f8df405 100644 >> --- a/drivers/media/platform/sti/hva/hva-hw.h >> +++ b/drivers/media/platform/sti/hva/hva-hw.h >> @@ -38,5 +38,6 @@ int hva_hw_runtime_suspend(struct device *dev); >> int hva_hw_runtime_resume(struct device *dev); >> int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd, >> struct hva_buffer *task); >> +void hva_hw_dump_regs(struct hva_dev *hva, struct seq_file *s); >> >> #endif /* HVA_HW_H */ >> diff --git a/drivers/media/platform/sti/hva/hva-v4l2.c b/drivers/media/platform/sti/hva/hva-v4l2.c >> index fb65816..71bb7b3 100644 >> --- a/drivers/media/platform/sti/hva/hva-v4l2.c >> +++ b/drivers/media/platform/sti/hva/hva-v4l2.c >> @@ -15,8 +15,6 @@ >> #include "hva.h" >> #include "hva-hw.h" >> >> -#define HVA_NAME "st-hva" >> - >> #define MIN_FRAMES 1 >> #define MIN_STREAMS 1 >> >> @@ -1181,6 +1179,8 @@ static int hva_open(struct file *file) >> /* default parameters for frame and stream */ >> set_default_params(ctx); >> >> + hva_dbg_ctx_create(ctx); >> + >> dev_info(dev, "%s encoder instance created\n", ctx->name); >> >> return 0; >> @@ -1223,6 +1223,8 @@ static int hva_release(struct file *file) >> v4l2_fh_del(&ctx->fh); >> v4l2_fh_exit(&ctx->fh); >> >> + hva_dbg_ctx_remove(ctx); >> + >> dev_info(dev, "%s encoder instance released\n", ctx->name); >> >> kfree(ctx); >> @@ -1347,6 +1349,8 @@ static int hva_probe(struct platform_device *pdev) >> goto err_hw; >> } >> >> + hva_debugfs_create(hva); >> + >> hva->work_queue = create_workqueue(HVA_NAME); >> if (!hva->work_queue) { >> dev_err(dev, "%s %s failed to allocate work queue\n", >> @@ -1368,6 +1372,7 @@ static int hva_probe(struct platform_device *pdev) >> err_work_queue: >> destroy_workqueue(hva->work_queue); >> err_v4l2: >> + hva_debugfs_remove(hva); >> v4l2_device_unregister(&hva->v4l2_dev); >> err_hw: >> hva_hw_remove(hva); >> @@ -1386,6 +1391,8 @@ static int hva_remove(struct platform_device *pdev) >> >> hva_hw_remove(hva); >> >> + hva_debugfs_remove(hva); >> + >> v4l2_device_unregister(&hva->v4l2_dev); >> >> dev_info(dev, "%s %s removed\n", HVA_PREFIX, pdev->name); >> diff --git a/drivers/media/platform/sti/hva/hva.h b/drivers/media/platform/sti/hva/hva.h >> index badc5f4..eef9769 100644 >> --- a/drivers/media/platform/sti/hva/hva.h >> +++ b/drivers/media/platform/sti/hva/hva.h >> @@ -21,7 +21,8 @@ >> >> #define ctx_to_hdev(c) (c->hva_dev) >> >> -#define HVA_PREFIX "[---:----]" >> +#define HVA_NAME "st-hva" >> +#define HVA_PREFIX "[---:----]" >> >> extern const struct hva_enc nv12h264enc; >> extern const struct hva_enc nv21h264enc; >> @@ -156,22 +157,60 @@ struct hva_stream { >> /** >> * struct hva_ctx_dbg - instance context debug info >> * >> - * @is_valid_period: true if the sequence is valid for performance >> - * @begin: start time of last HW task >> - * @total_duration: total HW processing durations in 0.1ms >> - * @cnt_duration: number of HW processings >> - * @sys_errors: number of system errors (memory, resource, pm..) >> - * @encode_errors: number of encoding errors (hw/driver errors) >> - * @frame_errors: number of frame errors (format, size, header...) >> + * @debugfs_entry: debugfs entry >> + * @is_valid_period: true if the sequence is valid for performance >> + * @begin: start time of last HW task >> + * @total_duration: total HW processing durations in 0.1ms >> + * @cnt_duration: number of HW processings >> + * @min_duration: minimum HW processing duration in 0.1ms >> + * @max_duration: maximum HW processing duration in 0.1ms >> + * @avg_duration: average HW processing duration in 0.1ms >> + * @max_fps: maximum frames encoded per second (in 0.1Hz) >> + * @total_period: total encoding periods in 0.1ms >> + * @cnt_period: number of periods >> + * @min_period: minimum encoding period in 0.1ms >> + * @max_period: maximum encoding period in 0.1ms >> + * @avg_period: average encoding period in 0.1ms >> + * @total_stream_size: total number of encoded bytes >> + * @avg_fps: average frames encoded per second (in 0.1Hz) >> + * @window_duration: duration of the sampling window in 0.1ms >> + * @cnt_window: number of samples in the window >> + * @window_stream_size: number of encoded bytes upon the sampling window >> + * @last_bitrate: bitrate upon the last sampling window >> + * @min_bitrate: minimum bitrate in kbps >> + * @max_bitrate: maximum bitrate in kbps >> + * @avg_bitrate: average bitrate in kbps >> + * @sys_errors: number of system errors (memory, resource, pm..) >> + * @encode_errors: number of encoding errors (hw/driver errors) >> + * @frame_errors: number of frame errors (format, size, header...) >> */ >> struct hva_ctx_dbg { >> - bool is_valid_period; >> - ktime_t begin; >> - u32 total_duration; >> - u32 cnt_duration; >> - u32 sys_errors; >> - u32 encode_errors; >> - u32 frame_errors; >> + struct dentry *debugfs_entry; >> + bool is_valid_period; >> + ktime_t begin; >> + u32 total_duration; >> + u32 cnt_duration; >> + u32 min_duration; >> + u32 max_duration; >> + u32 avg_duration; >> + u32 max_fps; >> + u32 total_period; >> + u32 cnt_period; >> + u32 min_period; >> + u32 max_period; >> + u32 avg_period; >> + u32 total_stream_size; >> + u32 avg_fps; >> + u32 window_duration; >> + u32 cnt_window; >> + u32 window_stream_size; >> + u32 last_bitrate; >> + u32 min_bitrate; >> + u32 max_bitrate; >> + u32 avg_bitrate; >> + u32 sys_errors; >> + u32 encode_errors; >> + u32 frame_errors; >> }; >> >> struct hva_dev; >> @@ -235,6 +274,17 @@ struct hva_ctx { >> #define HVA_FLAG_STREAMINFO 0x0001 >> #define HVA_FLAG_FRAMEINFO 0x0002 >> >> +/** >> + * struct hva_dev_dbg - device debug info >> + * >> + * @debugfs_entry: debugfs entry >> + * @last_ctx: debug information about last running instance context >> + */ >> +struct hva_dev_dbg { >> + struct dentry *debugfs_entry; >> + struct hva_ctx last_ctx; >> +}; >> + >> #define HVA_MAX_INSTANCES 16 >> #define HVA_MAX_ENCODERS 10 >> #define HVA_MAX_FORMATS HVA_MAX_ENCODERS >> @@ -273,6 +323,7 @@ struct hva_ctx { >> * @lmi_err_reg: local memory interface error register value >> * @emi_err_reg: external memory interface error register value >> * @hec_mif_err_reg: HEC memory interface error register value >> + * @dbg: device debug info >> */ >> struct hva_dev { >> struct v4l2_device v4l2_dev; >> @@ -307,6 +358,7 @@ struct hva_dev { >> u32 lmi_err_reg; >> u32 emi_err_reg; >> u32 hec_mif_err_reg; >> + struct hva_dev_dbg dbg; >> }; >> >> /** >> @@ -335,6 +387,10 @@ struct hva_enc { >> struct hva_stream *stream); >> }; >> >> +void hva_debugfs_create(struct hva_dev *hva); >> +void hva_debugfs_remove(struct hva_dev *hva); >> +void hva_dbg_ctx_create(struct hva_ctx *ctx); >> +void hva_dbg_ctx_remove(struct hva_ctx *ctx); >> char *hva_dbg_summary(struct hva_ctx *ctx); >> void hva_dbg_perf_begin(struct hva_ctx *ctx); >> void hva_dbg_perf_end(struct hva_ctx *ctx, struct hva_stream *stream); >> -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/media/platform/sti/hva/hva-debug.c b/drivers/media/platform/sti/hva/hva-debug.c index 71bbf32..433b1d4 100644 --- a/drivers/media/platform/sti/hva/hva-debug.c +++ b/drivers/media/platform/sti/hva/hva-debug.c @@ -5,7 +5,113 @@ * License terms: GNU General Public License (GPL), version 2 */ +#include <linux/debugfs.h> + #include "hva.h" +#include "hva-hw.h" + +static void format_ctx(struct seq_file *s, struct hva_ctx *ctx) +{ + struct hva_streaminfo *stream = &ctx->streaminfo; + struct hva_frameinfo *frame = &ctx->frameinfo; + struct hva_controls *ctrls = &ctx->ctrls; + struct hva_ctx_dbg *dbg = &ctx->dbg; + u32 bitrate_mode, aspect, entropy, vui_sar, sei_fp; + + seq_printf(s, "|-%s\n |\n", ctx->name); + + seq_printf(s, " |-[%sframe info]\n", + ctx->flags & HVA_FLAG_FRAMEINFO ? "" : "default "); + seq_printf(s, " | |- pixel format=%4.4s\n" + " | |- wxh=%dx%d\n" + " | |- wxh (w/ encoder alignment constraint)=%dx%d\n" + " |\n", + (char *)&frame->pixelformat, + frame->width, frame->height, + frame->aligned_width, frame->aligned_height); + + seq_printf(s, " |-[%sstream info]\n", + ctx->flags & HVA_FLAG_STREAMINFO ? "" : "default "); + seq_printf(s, " | |- stream format=%4.4s\n" + " | |- wxh=%dx%d\n" + " | |- %s\n" + " | |- %s\n" + " |\n", + (char *)&stream->streamformat, + stream->width, stream->height, + stream->profile, stream->level); + + bitrate_mode = V4L2_CID_MPEG_VIDEO_BITRATE_MODE; + aspect = V4L2_CID_MPEG_VIDEO_ASPECT; + seq_puts(s, " |-[parameters]\n"); + seq_printf(s, " | |- %s\n" + " | |- bitrate=%d bps\n" + " | |- GOP size=%d\n" + " | |- video aspect=%s\n" + " | |- framerate=%d/%d\n", + v4l2_ctrl_get_menu(bitrate_mode)[ctrls->bitrate_mode], + ctrls->bitrate, + ctrls->gop_size, + v4l2_ctrl_get_menu(aspect)[ctrls->aspect], + ctrls->time_per_frame.denominator, + ctrls->time_per_frame.numerator); + + entropy = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE; + vui_sar = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC; + sei_fp = V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE; + if (stream->streamformat == V4L2_PIX_FMT_H264) { + seq_printf(s, " | |- %s entropy mode\n" + " | |- CPB size=%d kB\n" + " | |- DCT8x8 enable=%s\n" + " | |- qpmin=%d\n" + " | |- qpmax=%d\n" + " | |- PAR enable=%s\n" + " | |- PAR id=%s\n" + " | |- SEI frame packing enable=%s\n" + " | |- SEI frame packing type=%s\n", + v4l2_ctrl_get_menu(entropy)[ctrls->entropy_mode], + ctrls->cpb_size, + ctrls->dct8x8 ? "true" : "false", + ctrls->qpmin, + ctrls->qpmax, + ctrls->vui_sar ? "true" : "false", + v4l2_ctrl_get_menu(vui_sar)[ctrls->vui_sar_idc], + ctrls->sei_fp ? "true" : "false", + v4l2_ctrl_get_menu(sei_fp)[ctrls->sei_fp_type]); + } + + if (dbg->sys_errors || dbg->encode_errors || dbg->frame_errors) { + seq_puts(s, " |\n |-[errors]\n"); + seq_printf(s, " | |- system=%d\n" + " | |- encoding=%d\n" + " | |- frame=%d\n", + dbg->sys_errors, + dbg->encode_errors, + dbg->frame_errors); + } + + seq_puts(s, " |\n |-[performances]\n"); + seq_printf(s, " | |- frames encoded=%d\n" + " | |- avg HW processing duration (0.1ms)=%d [min=%d, max=%d]\n" + " | |- avg encoding period (0.1ms)=%d [min=%d, max=%d]\n" + " | |- avg fps (0.1Hz)=%d\n" + " | |- max reachable fps (0.1Hz)=%d\n" + " | |- avg bitrate (kbps)=%d [min=%d, max=%d]\n" + " | |- last bitrate (kbps)=%d\n", + dbg->cnt_duration, + dbg->avg_duration, + dbg->min_duration, + dbg->max_duration, + dbg->avg_period, + dbg->min_period, + dbg->max_period, + dbg->avg_fps, + dbg->max_fps, + dbg->avg_bitrate, + dbg->min_bitrate, + dbg->max_bitrate, + dbg->last_bitrate); +} /* * encoding summary @@ -77,10 +183,52 @@ char *hva_dbg_summary(struct hva_ctx *ctx) void hva_dbg_perf_begin(struct hva_ctx *ctx) { + u64 div; + u32 period; + u32 bitrate; struct hva_ctx_dbg *dbg = &ctx->dbg; + ktime_t prev = dbg->begin; dbg->begin = ktime_get(); + if (dbg->is_valid_period) { + /* encoding period */ + div = (u64)ktime_us_delta(dbg->begin, prev); + do_div(div, 100); + period = (u32)div; + dbg->min_period = min(period, dbg->min_period); + dbg->max_period = max(period, dbg->max_period); + dbg->total_period += period; + dbg->cnt_period++; + + /* + * minimum and maximum bitrates are based on the + * encoding period values upon a window of 32 samples + */ + dbg->window_duration += period; + dbg->cnt_window++; + if (dbg->cnt_window >= 32) { + /* + * bitrate in kbps = (size * 8 / 1000) / + * (duration / 10000) + * = size * 80 / duration + */ + if (dbg->window_duration > 0) { + div = (u64)dbg->window_stream_size * 80; + do_div(div, dbg->window_duration); + bitrate = (u32)div; + dbg->last_bitrate = bitrate; + dbg->min_bitrate = min(bitrate, + dbg->min_bitrate); + dbg->max_bitrate = max(bitrate, + dbg->max_bitrate); + } + dbg->window_stream_size = 0; + dbg->window_duration = 0; + dbg->cnt_window = 0; + } + } + /* * filter sequences valid for performance: * - begin/begin (no stream available) is an invalid sequence @@ -118,8 +266,222 @@ void hva_dbg_perf_end(struct hva_ctx *ctx, struct hva_stream *stream) do_div(div, 100); duration = (u32)div; + dbg->min_duration = min(duration, dbg->min_duration); + dbg->max_duration = max(duration, dbg->max_duration); dbg->total_duration += duration; dbg->cnt_duration++; + /* + * the average bitrate is based on the total stream size + * and the total encoding periods + */ + dbg->total_stream_size += bytesused; + dbg->window_stream_size += bytesused; + dbg->is_valid_period = true; } + +static void hva_dbg_perf_compute(struct hva_ctx *ctx) +{ + u64 div; + struct hva_ctx_dbg *dbg = &ctx->dbg; + + if (dbg->cnt_duration > 0) { + div = (u64)dbg->total_duration; + do_div(div, dbg->cnt_duration); + dbg->avg_duration = (u32)div; + } else { + dbg->avg_duration = 0; + } + + if (dbg->total_duration > 0) { + div = (u64)dbg->cnt_duration * 100000; + do_div(div, dbg->total_duration); + dbg->max_fps = (u32)div; + } else { + dbg->max_fps = 0; + } + + if (dbg->cnt_period > 0) { + div = (u64)dbg->total_period; + do_div(div, dbg->cnt_period); + dbg->avg_period = (u32)div; + } else { + dbg->avg_period = 0; + } + + if (dbg->total_period > 0) { + div = (u64)dbg->cnt_period * 100000; + do_div(div, dbg->total_period); + dbg->avg_fps = (u32)div; + } else { + dbg->avg_fps = 0; + } + + if (dbg->total_period > 0) { + /* + * bitrate in kbps = (video size * 8 / 1000) / + * (video duration / 10000) + * = video size * 80 / video duration + */ + div = (u64)dbg->total_stream_size * 80; + do_div(div, dbg->total_period); + dbg->avg_bitrate = (u32)div; + } else { + dbg->avg_bitrate = 0; + } +} + +/* + * device debug info + */ + +static int hva_dbg_device(struct seq_file *s, void *data) +{ + struct hva_dev *hva = s->private; + + seq_printf(s, "[%s]\n", hva->v4l2_dev.name); + seq_printf(s, "registered as /dev/video%d\n", hva->vdev->num); + + return 0; +} + +static int hva_dbg_encoders(struct seq_file *s, void *data) +{ + struct hva_dev *hva = s->private; + unsigned int i = 0; + + seq_printf(s, "[encoders]\n|- %d registered encoders:\n", + hva->nb_of_encoders); + + while (hva->encoders[i]) { + seq_printf(s, "|- %s: %4.4s => %4.4s\n", hva->encoders[i]->name, + (char *)&hva->encoders[i]->pixelformat, + (char *)&hva->encoders[i]->streamformat); + i++; + } + + return 0; +} + +static int hva_dbg_last(struct seq_file *s, void *data) +{ + struct hva_dev *hva = s->private; + struct hva_ctx *last_ctx = &hva->dbg.last_ctx; + + if (last_ctx->flags & HVA_FLAG_STREAMINFO) { + seq_puts(s, "[last encoding]\n"); + + hva_dbg_perf_compute(last_ctx); + format_ctx(s, last_ctx); + } else { + seq_puts(s, "[no information recorded about last encoding]\n"); + } + + return 0; +} + +static int hva_dbg_regs(struct seq_file *s, void *data) +{ + struct hva_dev *hva = s->private; + + hva_hw_dump_regs(hva, s); + + return 0; +} + +#define hva_dbg_declare(name) \ + static int hva_dbg_##name##_open(struct inode *i, struct file *f) \ + { \ + return single_open(f, hva_dbg_##name, i->i_private); \ + } \ + static const struct file_operations hva_dbg_##name##_fops = { \ + .open = hva_dbg_##name##_open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ + } + +#define hva_dbg_create_entry(name) \ + debugfs_create_file(#name, S_IRUGO, hva->dbg.debugfs_entry, hva, \ + &hva_dbg_##name##_fops) + +hva_dbg_declare(device); +hva_dbg_declare(encoders); +hva_dbg_declare(last); +hva_dbg_declare(regs); + +void hva_debugfs_create(struct hva_dev *hva) +{ + hva->dbg.debugfs_entry = debugfs_create_dir(HVA_NAME, NULL); + if (!hva->dbg.debugfs_entry) + goto err; + + if (!hva_dbg_create_entry(device)) + goto err; + + if (!hva_dbg_create_entry(encoders)) + goto err; + + if (!hva_dbg_create_entry(last)) + goto err; + + if (!hva_dbg_create_entry(regs)) + goto err; + + return; + +err: + hva_debugfs_remove(hva); +} + +void hva_debugfs_remove(struct hva_dev *hva) +{ + debugfs_remove_recursive(hva->dbg.debugfs_entry); + hva->dbg.debugfs_entry = NULL; +} + +/* + * context (instance) debug info + */ + +static int hva_dbg_ctx(struct seq_file *s, void *data) +{ + struct hva_ctx *ctx = s->private; + + seq_printf(s, "[running encoding %d]\n", ctx->id); + + hva_dbg_perf_compute(ctx); + format_ctx(s, ctx); + + return 0; +} + +hva_dbg_declare(ctx); + +void hva_dbg_ctx_create(struct hva_ctx *ctx) +{ + struct hva_dev *hva = ctx->hva_dev; + char name[4] = ""; + + ctx->dbg.min_duration = UINT_MAX; + ctx->dbg.min_period = UINT_MAX; + ctx->dbg.min_bitrate = UINT_MAX; + + snprintf(name, sizeof(name), "%d", hva->instance_id); + + ctx->dbg.debugfs_entry = debugfs_create_file(name, S_IRUGO, + hva->dbg.debugfs_entry, + ctx, &hva_dbg_ctx_fops); +} + +void hva_dbg_ctx_remove(struct hva_ctx *ctx) +{ + struct hva_dev *hva = ctx->hva_dev; + + if (ctx->flags & HVA_FLAG_STREAMINFO) + /* save context before removing */ + memcpy(&hva->dbg.last_ctx, ctx, sizeof(*ctx)); + + debugfs_remove(ctx->dbg.debugfs_entry); +} diff --git a/drivers/media/platform/sti/hva/hva-hw.c b/drivers/media/platform/sti/hva/hva-hw.c index c84b860..d395204 100644 --- a/drivers/media/platform/sti/hva/hva-hw.c +++ b/drivers/media/platform/sti/hva/hva-hw.c @@ -9,6 +9,7 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/seq_file.h> #include "hva.h" #include "hva-hw.h" @@ -541,3 +542,41 @@ out: return ret; } + +#define DUMP(reg) seq_printf(s, "%-30s: 0x%08X\n",\ + #reg, readl_relaxed(hva->regs + reg)) + +void hva_hw_dump_regs(struct hva_dev *hva, struct seq_file *s) +{ + struct device *dev = hva_to_dev(hva); + + mutex_lock(&hva->protect_mutex); + + if (pm_runtime_get_sync(dev) < 0) { + seq_puts(s, "Cannot wake up IP\n"); + mutex_unlock(&hva->protect_mutex); + return; + } + + seq_printf(s, "Registers:\nReg @ = 0x%p\n", hva->regs); + + DUMP(HVA_HIF_REG_RST); + DUMP(HVA_HIF_REG_RST_ACK); + DUMP(HVA_HIF_REG_MIF_CFG); + DUMP(HVA_HIF_REG_HEC_MIF_CFG); + DUMP(HVA_HIF_REG_CFL); + DUMP(HVA_HIF_REG_SFL); + DUMP(HVA_HIF_REG_LMI_ERR); + DUMP(HVA_HIF_REG_EMI_ERR); + DUMP(HVA_HIF_REG_HEC_MIF_ERR); + DUMP(HVA_HIF_REG_HEC_STS); + DUMP(HVA_HIF_REG_HVC_STS); + DUMP(HVA_HIF_REG_HJE_STS); + DUMP(HVA_HIF_REG_CNT); + DUMP(HVA_HIF_REG_HEC_CHKSYN_DIS); + DUMP(HVA_HIF_REG_CLK_GATING); + DUMP(HVA_HIF_REG_VERSION); + + pm_runtime_put_autosuspend(dev); + mutex_unlock(&hva->protect_mutex); +} diff --git a/drivers/media/platform/sti/hva/hva-hw.h b/drivers/media/platform/sti/hva/hva-hw.h index efb45b9..f8df405 100644 --- a/drivers/media/platform/sti/hva/hva-hw.h +++ b/drivers/media/platform/sti/hva/hva-hw.h @@ -38,5 +38,6 @@ int hva_hw_runtime_suspend(struct device *dev); int hva_hw_runtime_resume(struct device *dev); int hva_hw_execute_task(struct hva_ctx *ctx, enum hva_hw_cmd_type cmd, struct hva_buffer *task); +void hva_hw_dump_regs(struct hva_dev *hva, struct seq_file *s); #endif /* HVA_HW_H */ diff --git a/drivers/media/platform/sti/hva/hva-v4l2.c b/drivers/media/platform/sti/hva/hva-v4l2.c index fb65816..71bb7b3 100644 --- a/drivers/media/platform/sti/hva/hva-v4l2.c +++ b/drivers/media/platform/sti/hva/hva-v4l2.c @@ -15,8 +15,6 @@ #include "hva.h" #include "hva-hw.h" -#define HVA_NAME "st-hva" - #define MIN_FRAMES 1 #define MIN_STREAMS 1 @@ -1181,6 +1179,8 @@ static int hva_open(struct file *file) /* default parameters for frame and stream */ set_default_params(ctx); + hva_dbg_ctx_create(ctx); + dev_info(dev, "%s encoder instance created\n", ctx->name); return 0; @@ -1223,6 +1223,8 @@ static int hva_release(struct file *file) v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); + hva_dbg_ctx_remove(ctx); + dev_info(dev, "%s encoder instance released\n", ctx->name); kfree(ctx); @@ -1347,6 +1349,8 @@ static int hva_probe(struct platform_device *pdev) goto err_hw; } + hva_debugfs_create(hva); + hva->work_queue = create_workqueue(HVA_NAME); if (!hva->work_queue) { dev_err(dev, "%s %s failed to allocate work queue\n", @@ -1368,6 +1372,7 @@ static int hva_probe(struct platform_device *pdev) err_work_queue: destroy_workqueue(hva->work_queue); err_v4l2: + hva_debugfs_remove(hva); v4l2_device_unregister(&hva->v4l2_dev); err_hw: hva_hw_remove(hva); @@ -1386,6 +1391,8 @@ static int hva_remove(struct platform_device *pdev) hva_hw_remove(hva); + hva_debugfs_remove(hva); + v4l2_device_unregister(&hva->v4l2_dev); dev_info(dev, "%s %s removed\n", HVA_PREFIX, pdev->name); diff --git a/drivers/media/platform/sti/hva/hva.h b/drivers/media/platform/sti/hva/hva.h index badc5f4..eef9769 100644 --- a/drivers/media/platform/sti/hva/hva.h +++ b/drivers/media/platform/sti/hva/hva.h @@ -21,7 +21,8 @@ #define ctx_to_hdev(c) (c->hva_dev) -#define HVA_PREFIX "[---:----]" +#define HVA_NAME "st-hva" +#define HVA_PREFIX "[---:----]" extern const struct hva_enc nv12h264enc; extern const struct hva_enc nv21h264enc; @@ -156,22 +157,60 @@ struct hva_stream { /** * struct hva_ctx_dbg - instance context debug info * - * @is_valid_period: true if the sequence is valid for performance - * @begin: start time of last HW task - * @total_duration: total HW processing durations in 0.1ms - * @cnt_duration: number of HW processings - * @sys_errors: number of system errors (memory, resource, pm..) - * @encode_errors: number of encoding errors (hw/driver errors) - * @frame_errors: number of frame errors (format, size, header...) + * @debugfs_entry: debugfs entry + * @is_valid_period: true if the sequence is valid for performance + * @begin: start time of last HW task + * @total_duration: total HW processing durations in 0.1ms + * @cnt_duration: number of HW processings + * @min_duration: minimum HW processing duration in 0.1ms + * @max_duration: maximum HW processing duration in 0.1ms + * @avg_duration: average HW processing duration in 0.1ms + * @max_fps: maximum frames encoded per second (in 0.1Hz) + * @total_period: total encoding periods in 0.1ms + * @cnt_period: number of periods + * @min_period: minimum encoding period in 0.1ms + * @max_period: maximum encoding period in 0.1ms + * @avg_period: average encoding period in 0.1ms + * @total_stream_size: total number of encoded bytes + * @avg_fps: average frames encoded per second (in 0.1Hz) + * @window_duration: duration of the sampling window in 0.1ms + * @cnt_window: number of samples in the window + * @window_stream_size: number of encoded bytes upon the sampling window + * @last_bitrate: bitrate upon the last sampling window + * @min_bitrate: minimum bitrate in kbps + * @max_bitrate: maximum bitrate in kbps + * @avg_bitrate: average bitrate in kbps + * @sys_errors: number of system errors (memory, resource, pm..) + * @encode_errors: number of encoding errors (hw/driver errors) + * @frame_errors: number of frame errors (format, size, header...) */ struct hva_ctx_dbg { - bool is_valid_period; - ktime_t begin; - u32 total_duration; - u32 cnt_duration; - u32 sys_errors; - u32 encode_errors; - u32 frame_errors; + struct dentry *debugfs_entry; + bool is_valid_period; + ktime_t begin; + u32 total_duration; + u32 cnt_duration; + u32 min_duration; + u32 max_duration; + u32 avg_duration; + u32 max_fps; + u32 total_period; + u32 cnt_period; + u32 min_period; + u32 max_period; + u32 avg_period; + u32 total_stream_size; + u32 avg_fps; + u32 window_duration; + u32 cnt_window; + u32 window_stream_size; + u32 last_bitrate; + u32 min_bitrate; + u32 max_bitrate; + u32 avg_bitrate; + u32 sys_errors; + u32 encode_errors; + u32 frame_errors; }; struct hva_dev; @@ -235,6 +274,17 @@ struct hva_ctx { #define HVA_FLAG_STREAMINFO 0x0001 #define HVA_FLAG_FRAMEINFO 0x0002 +/** + * struct hva_dev_dbg - device debug info + * + * @debugfs_entry: debugfs entry + * @last_ctx: debug information about last running instance context + */ +struct hva_dev_dbg { + struct dentry *debugfs_entry; + struct hva_ctx last_ctx; +}; + #define HVA_MAX_INSTANCES 16 #define HVA_MAX_ENCODERS 10 #define HVA_MAX_FORMATS HVA_MAX_ENCODERS @@ -273,6 +323,7 @@ struct hva_ctx { * @lmi_err_reg: local memory interface error register value * @emi_err_reg: external memory interface error register value * @hec_mif_err_reg: HEC memory interface error register value + * @dbg: device debug info */ struct hva_dev { struct v4l2_device v4l2_dev; @@ -307,6 +358,7 @@ struct hva_dev { u32 lmi_err_reg; u32 emi_err_reg; u32 hec_mif_err_reg; + struct hva_dev_dbg dbg; }; /** @@ -335,6 +387,10 @@ struct hva_enc { struct hva_stream *stream); }; +void hva_debugfs_create(struct hva_dev *hva); +void hva_debugfs_remove(struct hva_dev *hva); +void hva_dbg_ctx_create(struct hva_ctx *ctx); +void hva_dbg_ctx_remove(struct hva_ctx *ctx); char *hva_dbg_summary(struct hva_ctx *ctx); void hva_dbg_perf_begin(struct hva_ctx *ctx); void hva_dbg_perf_end(struct hva_ctx *ctx, struct hva_stream *stream);