From d139cc0efd98737c592dca0ccb53d90fac368cb9 Mon Sep 17 00:00:00 2001 From: Ayoung Sim Date: Fri, 22 Mar 2019 14:45:38 +0900 Subject: [PATCH] [COMMON] media: mfc: adjust the MFC freq by bps Change-Id: Iccfd2678dc957e53776f271174be60f19f37d503 Signed-off-by: Ayoung Sim --- .../platform/exynos/mfc/mfc_data_struct.h | 2 + drivers/media/platform/exynos/mfc/mfc_qos.c | 135 +++++++++++++++--- 2 files changed, 114 insertions(+), 23 deletions(-) diff --git a/drivers/media/platform/exynos/mfc/mfc_data_struct.h b/drivers/media/platform/exynos/mfc/mfc_data_struct.h index d662b2bda099..6fbb116df331 100644 --- a/drivers/media/platform/exynos/mfc/mfc_data_struct.h +++ b/drivers/media/platform/exynos/mfc/mfc_data_struct.h @@ -865,6 +865,7 @@ struct mfc_dev { struct pm_qos_request qos_req_cluster[MAX_NUM_CLUSTER]; int qos_has_enc_ctx; struct mutex qos_mutex; + int mfc_freq_by_bps; #endif struct mfc_bitrate_table bitrate_table[MAX_NUM_MFC_FREQ]; int bps_ratio; @@ -1583,6 +1584,7 @@ struct mfc_ctx { int bitrate_index; int bitrate_is_full; int Kbps; + int last_bps_section; int buf_process_type; diff --git a/drivers/media/platform/exynos/mfc/mfc_qos.c b/drivers/media/platform/exynos/mfc/mfc_qos.c index d3e8c3734747..d37048fa6d3e 100644 --- a/drivers/media/platform/exynos/mfc/mfc_qos.c +++ b/drivers/media/platform/exynos/mfc/mfc_qos.c @@ -104,13 +104,20 @@ static void __mfc_qos_operate(struct mfc_ctx *ctx, int opr_type, int idx) struct mfc_dev *dev = ctx->dev; struct mfc_platdata *pdata = dev->pdata; struct mfc_qos *qos_table = pdata->qos_table; + int freq_mfc = pdata->qos_table[idx].freq_mfc; switch (opr_type) { case MFC_QOS_ADD: + if (dev->mfc_freq_by_bps > freq_mfc) { + mfc_debug(2, "[QoS] mfc freq set to high %d -> %d by bps\n", + freq_mfc, dev->mfc_freq_by_bps); + freq_mfc = dev->mfc_freq_by_bps; + } + if (pdata->mfc_freq_control) pm_qos_add_request(&dev->qos_req_mfc, PM_QOS_MFC_THROUGHPUT, - qos_table[idx].freq_mfc); + freq_mfc); pm_qos_add_request(&dev->qos_req_int, PM_QOS_DEVICE_THROUGHPUT, qos_table[idx].freq_int); @@ -134,20 +141,23 @@ static void __mfc_qos_operate(struct mfc_ctx *ctx, int opr_type, int idx) atomic_set(&dev->qos_req_cur, idx + 1); MFC_TRACE_CTX("QoS add[%d] - mfc:%d(%s), int:%d, mif:%d\n", - idx, qos_table[idx].freq_mfc, pdata->mfc_freq_control ? "used" : "un-used", + idx, freq_mfc, pdata->mfc_freq_control ? "used" : "un-used", qos_table[idx].freq_int, qos_table[idx].freq_mif); mfc_debug(2, "[QoS] QoS add[%d] - mfc:%d(%s), int:%d, mif:%d\n", - idx, qos_table[idx].freq_mfc, pdata->mfc_freq_control ? "used" : "un-used", + idx, freq_mfc, pdata->mfc_freq_control ? "used" : "un-used", qos_table[idx].freq_int, qos_table[idx].freq_mif); break; case MFC_QOS_UPDATE: + if (dev->mfc_freq_by_bps > freq_mfc) { + mfc_debug(2, "[QoS] mfc freq set to high %d -> %d by bps\n", + freq_mfc, dev->mfc_freq_by_bps); + freq_mfc = dev->mfc_freq_by_bps; + } + if (pdata->mfc_freq_control) - pm_qos_update_request(&dev->qos_req_mfc, - qos_table[idx].freq_mfc); - pm_qos_update_request(&dev->qos_req_int, - qos_table[idx].freq_int); - pm_qos_update_request(&dev->qos_req_mif, - qos_table[idx].freq_mif); + pm_qos_update_request(&dev->qos_req_mfc, freq_mfc); + pm_qos_update_request(&dev->qos_req_int, qos_table[idx].freq_int); + pm_qos_update_request(&dev->qos_req_mif, qos_table[idx].freq_mif); #ifdef CONFIG_EXYNOS_BTS if (pdata->mo_control) { @@ -165,10 +175,10 @@ static void __mfc_qos_operate(struct mfc_ctx *ctx, int opr_type, int idx) atomic_set(&dev->qos_req_cur, idx + 1); MFC_TRACE_CTX("QoS update[%d] - mfc:%d(%s), int:%d, mif:%d\n", - idx, qos_table[idx].freq_mfc, pdata->mfc_freq_control ? "used" : "un-used", + idx, freq_mfc, pdata->mfc_freq_control ? "used" : "un-used", qos_table[idx].freq_int, qos_table[idx].freq_mif); mfc_debug(2, "[QoS] QoS update[%d] - mfc:%d(%s), int:%d, mif:%d\n", - idx, qos_table[idx].freq_mfc, pdata->mfc_freq_control ? "used" : "un-used", + idx, freq_mfc, pdata->mfc_freq_control ? "used" : "un-used", qos_table[idx].freq_int, qos_table[idx].freq_mif); break; case MFC_QOS_REMOVE: @@ -240,10 +250,17 @@ static void __mfc_qos_set(struct mfc_ctx *ctx, int i) #endif mutex_lock(&dev->qos_mutex); - if (atomic_read(&dev->qos_req_cur) == 0) + if (atomic_read(&dev->qos_req_cur) == 0) { __mfc_qos_operate(ctx, MFC_QOS_ADD, i); - else if (atomic_read(&dev->qos_req_cur) != (i + 1)) - __mfc_qos_operate(ctx, MFC_QOS_UPDATE, i); + } else { + /* + * 1) QoS level is changed + * 2) MFC freq should be high regardless of QoS level + */ + if ((atomic_read(&dev->qos_req_cur) != (i + 1)) || + (dev->mfc_freq_by_bps > pdata->qos_table[i].freq_mfc)) + __mfc_qos_operate(ctx, MFC_QOS_UPDATE, i); + } mutex_unlock(&dev->qos_mutex); } @@ -385,9 +402,9 @@ static inline unsigned long __mfc_qos_get_mb_per_second(struct mfc_ctx *ctx) fps = ctx->framerate / 1000; mb = mb_width * mb_height * fps; - mfc_debug(4, "[QoS] ctx[%d:%s] %d x %d @ %ld fps (mb: %ld)\n", + mfc_debug(4, "[QoS] ctx[%d:%s] %d x %d @ %ld fps (mb: %ld), %dKbps\n", ctx->num, ctx->type == MFCINST_ENCODER ? "ENC" : "DEC", - ctx->crop_width, ctx->crop_height, fps, mb); + ctx->crop_width, ctx->crop_height, fps, mb, ctx->Kbps); return __mfc_qos_get_weighted_mb(ctx, mb); } @@ -501,13 +518,32 @@ static void __mfc_qos_get_bw_per_second(struct mfc_ctx *ctx, struct bts_bw *curr } #endif +static int __mfc_qos_get_freq_by_bps(struct mfc_dev *dev, unsigned long total_bps) +{ + int i; + + if (total_bps > dev->pdata->max_Kbps[0]) { + mfc_debug(4, "[QoS] overspec bps %d > %d\n", + total_bps, dev->pdata->max_Kbps[0]); + return dev->bitrate_table[dev->pdata->num_mfc_freq - 1].mfc_freq; + } + + for (i = 0; i < dev->pdata->num_mfc_freq; i++) { + if (total_bps <= dev->bitrate_table[i].bps_interval) + return dev->bitrate_table[i].mfc_freq; + } + + /* Not changed the MFC freq according to BPS */ + return 0; +} + void mfc_qos_on(struct mfc_ctx *ctx) { struct mfc_dev *dev = ctx->dev; struct mfc_platdata *pdata = dev->pdata; struct mfc_qos *qos_table = pdata->qos_table; struct mfc_ctx *qos_ctx; - unsigned long hw_mb = 0, total_mb = 0, total_fps = 0; + unsigned long hw_mb = 0, total_mb = 0, total_fps = 0, total_bps = 0; unsigned int fw_time, sw_time; int i, found = 0, enc_found = 0; int start_qos_step; @@ -538,6 +574,7 @@ void mfc_qos_on(struct mfc_ctx *ctx) enc_found = 1; hw_mb += __mfc_qos_get_mb_per_second(qos_ctx); total_fps += (qos_ctx->framerate / 1000); + total_bps += qos_ctx->Kbps; #ifdef CONFIG_EXYNOS_BTS __mfc_qos_get_bw_per_second(qos_ctx, &curr_mfc_bw_ctx); curr_mfc_bw.peak += curr_mfc_bw_ctx.peak; @@ -571,6 +608,9 @@ void mfc_qos_on(struct mfc_ctx *ctx) if (total_mb > pdata->max_mb) mfc_debug(4, "[QoS] overspec mb %ld > %d\n", total_mb, pdata->max_mb); + /* search the suitable independent mfc freq using bps */ + dev->mfc_freq_by_bps = __mfc_qos_get_freq_by_bps(dev, total_bps); + #ifdef CONFIG_EXYNOS_BTS __mfc_qos_set(ctx, &curr_mfc_bw, i); #else @@ -584,7 +624,7 @@ void mfc_qos_off(struct mfc_ctx *ctx) struct mfc_platdata *pdata = dev->pdata; struct mfc_qos *qos_table = pdata->qos_table; struct mfc_ctx *qos_ctx; - unsigned long hw_mb = 0, total_mb = 0, total_fps = 0; + unsigned long hw_mb = 0, total_mb = 0, total_fps = 0, total_bps = 0; unsigned int fw_time, sw_time; int i, found = 0, enc_found = 0; int start_qos_step; @@ -623,6 +663,7 @@ void mfc_qos_off(struct mfc_ctx *ctx) enc_found = 1; hw_mb += __mfc_qos_get_mb_per_second(qos_ctx); total_fps += (qos_ctx->framerate / 1000); + total_bps += qos_ctx->Kbps; #ifdef CONFIG_EXYNOS_BTS __mfc_qos_get_bw_per_second(qos_ctx, &mfc_bw_ctx); mfc_bw.peak += mfc_bw_ctx.peak; @@ -656,6 +697,9 @@ void mfc_qos_off(struct mfc_ctx *ctx) if (total_mb > pdata->max_mb) mfc_debug(4, "[QoS] overspec mb %ld > %d\n", total_mb, pdata->max_mb); + /* search the suitable independent mfc freq using bps */ + dev->mfc_freq_by_bps = __mfc_qos_get_freq_by_bps(dev, total_bps); + if (found) list_del(&ctx->qos_list); @@ -720,6 +764,27 @@ static unsigned long __mfc_qos_get_framerate_by_interval(int interval) return 0; } +static int __mfc_qos_get_bps_section_by_bps(struct mfc_dev *dev, int Kbps) +{ + int i; + + if (Kbps > dev->pdata->max_Kbps[0]) { + mfc_debug(4, "[QoS] overspec bps %d > %d\n", + Kbps, dev->pdata->max_Kbps[0]); + return dev->pdata->num_mfc_freq - 1; + } + + for (i = 0; i < dev->pdata->num_mfc_freq; i++) { + if (Kbps <= dev->bitrate_table[i].bps_interval) { + mfc_debug(3, "[QoS] MFC freq lv%d, %dKHz is needed\n", + i, dev->bitrate_table[i].mfc_freq); + return i; + } + } + + return 0; +} + /* Return the minimum interval between previous and next entry */ static int __mfc_qos_get_interval(struct list_head *head, struct list_head *entry) { @@ -847,14 +912,14 @@ static unsigned long __mfc_qos_get_fps_by_timestamp(struct mfc_ctx *ctx, struct return max_framerate; } -static void __mfc_qos_get_bps(struct mfc_ctx *ctx, u32 bytesused) +static int __mfc_qos_get_bps_section(struct mfc_ctx *ctx, u32 bytesused) { struct mfc_dev *dev = ctx->dev; struct list_head *head = &ctx->bitrate_list; struct mfc_bitrate *temp_bitrate; struct mfc_bitrate *new_bitrate = &ctx->bitrate_array[ctx->bitrate_index]; unsigned long sum_size = 0, avg_Kbits; - int count = 0; + int count = 0, bps_section = 0; if (ctx->bitrate_is_full) { temp_bitrate = list_entry(head->next, struct mfc_bitrate, list); @@ -882,19 +947,43 @@ static void __mfc_qos_get_bps(struct mfc_ctx *ctx, u32 bytesused) ctx->bitrate_is_full = 1; ctx->bitrate_index %= MAX_TIME_INDEX; } + + /* + * When there is a value of ts_is_full, + * we can trust fps(trusted fps calculated by timestamp diff). + * When fps information becomes reliable, + * we will start QoS handling by obtaining bps section. + */ + if (ctx->ts_is_full) + bps_section = __mfc_qos_get_bps_section_by_bps(dev, ctx->Kbps); + + return bps_section; } void mfc_qos_update_framerate(struct mfc_ctx *ctx, u32 bytesused) { - if (ctx->type == MFCINST_DECODER) - __mfc_qos_get_bps(ctx, bytesused); + int bps_section; + bool update = false; + + if (ctx->type == MFCINST_DECODER) { + bps_section = __mfc_qos_get_bps_section(ctx, bytesused); + if (ctx->last_bps_section != bps_section) { + mfc_debug(2, "[QoS] bps section changed: %d -> %d\n", + ctx->last_bps_section, bps_section); + ctx->last_bps_section = bps_section; + update = true; + } + } if (ctx->last_framerate != 0 && ctx->last_framerate != ctx->framerate) { mfc_debug(2, "[QoS] fps changed: %ld -> %ld, qos ratio: %d\n", ctx->framerate, ctx->last_framerate, ctx->qos_ratio); ctx->framerate = ctx->last_framerate; - mfc_qos_on(ctx); + update = true; } + + if (update) + mfc_qos_on(ctx); } void mfc_qos_update_last_framerate(struct mfc_ctx *ctx, u64 timestamp) -- 2.20.1