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);
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) {
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:
#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);
}
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);
}
}
#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;
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;
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
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;
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;
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);
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)
{
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);
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)