linux/drivers/media/platform/sti/hva/hva-debugfs.c
Greg Kroah-Hartman 8c23f41129 media: sti: no need to check return value of debugfs_create functions
When calling debugfs functions, there is no need to ever check the
return value.  The function can work or not, but the code logic should
never do something different based on this.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
2020-09-01 14:13:26 +02:00

397 lines
9.9 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) STMicroelectronics SA 2015
* Authors: Yannick Fertre <yannick.fertre@st.com>
* Hugues Fruchet <hugues.fruchet@st.com>
*/
#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 (ctx->sys_errors || ctx->encode_errors || ctx->frame_errors) {
seq_puts(s, " |\n |-[errors]\n");
seq_printf(s, " | |- system=%d\n"
" | |- encoding=%d\n"
" | |- frame=%d\n",
ctx->sys_errors,
ctx->encode_errors,
ctx->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);
}
/*
* performance debug info
*/
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
* - begin/end is a valid sequence
*/
dbg->is_valid_period = false;
}
void hva_dbg_perf_end(struct hva_ctx *ctx, struct hva_stream *stream)
{
struct device *dev = ctx_to_dev(ctx);
u64 div;
u32 duration;
u32 bytesused;
u32 timestamp;
struct hva_ctx_dbg *dbg = &ctx->dbg;
ktime_t end = ktime_get();
/* stream bytesused and timestamp in us */
bytesused = vb2_get_plane_payload(&stream->vbuf.vb2_buf, 0);
div = stream->vbuf.vb2_buf.timestamp;
do_div(div, 1000);
timestamp = (u32)div;
/* encoding duration */
div = (u64)ktime_us_delta(end, dbg->begin);
dev_dbg(dev,
"%s perf stream[%d] dts=%d encoded using %d bytes in %d us",
ctx->name,
stream->vbuf.sequence,
timestamp,
bytesused, (u32)div);
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 device_show(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 encoders_show(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 last_show(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 regs_show(struct seq_file *s, void *data)
{
struct hva_dev *hva = s->private;
hva_hw_dump_regs(hva, s);
return 0;
}
#define hva_dbg_create_entry(name) \
debugfs_create_file(#name, 0444, hva->dbg.debugfs_entry, hva, \
&name##_fops)
DEFINE_SHOW_ATTRIBUTE(device);
DEFINE_SHOW_ATTRIBUTE(encoders);
DEFINE_SHOW_ATTRIBUTE(last);
DEFINE_SHOW_ATTRIBUTE(regs);
void hva_debugfs_create(struct hva_dev *hva)
{
hva->dbg.debugfs_entry = debugfs_create_dir(HVA_NAME, NULL);
hva_dbg_create_entry(device);
hva_dbg_create_entry(encoders);
hva_dbg_create_entry(last);
hva_dbg_create_entry(regs);
}
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 ctx_show(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;
}
DEFINE_SHOW_ATTRIBUTE(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, 0444,
hva->dbg.debugfs_entry,
ctx, &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);
}