[COMMON] media: mfc: adjust the MFC freq by bps
authorAyoung Sim <a.sim@samsung.com>
Fri, 22 Mar 2019 05:45:38 +0000 (14:45 +0900)
committerKim Gunho <gunho.kim@samsung.com>
Fri, 28 Jun 2019 14:45:46 +0000 (23:45 +0900)
Change-Id: Iccfd2678dc957e53776f271174be60f19f37d503
Signed-off-by: Ayoung Sim <a.sim@samsung.com>
drivers/media/platform/exynos/mfc/mfc_data_struct.h
drivers/media/platform/exynos/mfc/mfc_qos.c

index d662b2bda09941b7748e4fd291ae0838badddf9c..6fbb116df3316a77a28e5bcac71b97c0b697b323 100644 (file)
@@ -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;
 
index d3e8c37347477557b90e04c10febafc53227d14a..d37048fa6d3eddbcf7bf1bd3f5a9dca44f4f26ce 100644 (file)
@@ -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)