From patchwork Mon Jan 6 15:49:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stanimir Varbanov X-Patchwork-Id: 206101 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.8 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 601AEC33C8C for ; Mon, 6 Jan 2020 15:51:11 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2B1C12081E for ; Mon, 6 Jan 2020 15:51:11 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="MD/KyYTV" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727046AbgAFPuK (ORCPT ); Mon, 6 Jan 2020 10:50:10 -0500 Received: from mail-lf1-f67.google.com ([209.85.167.67]:35495 "EHLO mail-lf1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726620AbgAFPuK (ORCPT ); Mon, 6 Jan 2020 10:50:10 -0500 Received: by mail-lf1-f67.google.com with SMTP id 15so36694107lfr.2 for ; Mon, 06 Jan 2020 07:50:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=NVL5+pBVbAL5rpEkMW1hQcPnra9m/vRP70pZvH2RbgM=; b=MD/KyYTVUIBMi2KaxcIyVNlZVX6jQoBJiMULaEZnYo6Gxozi8WrMti2ageBVD6S4Zm O9Nh5aRRuW3scPQ7Jvp1vdEqvzaTKrYILfWSj+99d5nVVHZ6FrEmd8VigntmF8OuKi2n CrIf+XytNPxjaaOppntG9GBLMpmby+QC0+xl9hUktwW2PNPQHEUIszef4LRiM01rt/QZ GxXMATV1MZr6JWv0zIQsIU11INOmBK8+nt22TCnbZkMqD5ZUOKVNRzH0HNR9SAHH5GUF mOT5duJxdPhRUnTJhVOoPmRRyxLhq/cU4nxLszkjhG/fRJKtiFscTvSveOJwWIZk+VFr OpjQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=NVL5+pBVbAL5rpEkMW1hQcPnra9m/vRP70pZvH2RbgM=; b=cNIkT2WE6lQgXn3/tW+49l93GdDINS2+bLkYt+K/kkaa6DJCexel6Xg2/dDlFZAj/g jMDPyBpwICWrFWxJZkaR+ZT1StyB3AnR/MZHTUY/QPB0HetiEf07FmCx5q6t4svgDHDp 3/deHlR7Vrd/eJ1PkwkgKmcuzSblQAbv0XC+iGFSfZQvRXvgCCBLleD6T9kcC9X82xhn o2FmYmscSAJr8CNhqcJ5U55Ct29WWCjenKRHKVUBVBbH81X8Ph4qE/uSZYwkbpPSkNM6 dCKADIljGMu/YKuQnbuAzlBzT2bCqcn05J5NqTF705c43YrDCX3Ez6pAC/zeDkg3L8pt VCAQ== X-Gm-Message-State: APjAAAXz2Eas/qgG+9A5d1C6eRjj42E64eJ6jsmuHqVBNd/NdG2qeBhb QHMeiAnpp7cN9+HLkuDojqPbETLY8o4= X-Google-Smtp-Source: APXvYqwVBXN4a2fWqZfLcG1fnIxrjRnZlkTMMJtACS/CKoC1pc6cdpBtl8btcWY/fb57ipxypmlC7g== X-Received: by 2002:a19:5013:: with SMTP id e19mr57756651lfb.8.1578325807430; Mon, 06 Jan 2020 07:50:07 -0800 (PST) Received: from localhost.localdomain ([37.157.136.193]) by smtp.gmail.com with ESMTPSA id x84sm29388259lfa.97.2020.01.06.07.50.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 06 Jan 2020 07:50:06 -0800 (PST) From: Stanimir Varbanov To: linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org, linux-media@vger.kernel.org, devicetree@vger.kernel.org Cc: Vikash Garodia , dikshita@codeaurora.org, Aniket Masule , Stanimir Varbanov Subject: [PATCH v4 02/12] media: venus: introduce core selection Date: Mon, 6 Jan 2020 17:49:19 +0200 Message-Id: <20200106154929.4331-3-stanimir.varbanov@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200106154929.4331-1-stanimir.varbanov@linaro.org> References: <20200106154929.4331-1-stanimir.varbanov@linaro.org> Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org From: Aniket Masule Presently the core (vcodec pipelines) assignment is static. Here we introduce dynamic load balancing across the cores depending on the current session load. The load on earch core is calculated and core with minimum load is assigned to given instance. This will be applicable on Venus v4 with more than one vcodec cores. Signed-off-by: Aniket Masule Co-developed-by: Stanimir Varbanov Signed-off-by: Stanimir Varbanov --- drivers/media/platform/qcom/venus/core.h | 3 + drivers/media/platform/qcom/venus/helpers.c | 17 +- drivers/media/platform/qcom/venus/helpers.h | 1 - .../media/platform/qcom/venus/hfi_helper.h | 1 + .../media/platform/qcom/venus/hfi_parser.h | 5 + .../media/platform/qcom/venus/pm_helpers.c | 183 ++++++++++++++++-- .../media/platform/qcom/venus/pm_helpers.h | 26 +++ drivers/media/platform/qcom/venus/vdec.c | 11 +- drivers/media/platform/qcom/venus/venc.c | 10 +- 9 files changed, 221 insertions(+), 36 deletions(-) diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index c66763e1b8f1..bfbd4a1ba089 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -181,6 +181,8 @@ struct venus_core { struct delayed_work work; struct venus_caps caps[MAX_CODEC_NUM]; unsigned int codecs_count; + unsigned int core0_usage_count; + unsigned int core1_usage_count; }; struct vdec_controls { @@ -379,6 +381,7 @@ struct venus_inst { const struct hfi_inst_ops *ops; u32 session_type; union hfi_get_property hprop; + unsigned int core_acquired: 1; }; #define IS_V1(core) ((core)->res->hfi_version == HFI_VERSION_1XX) diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index cbeeaf6077e0..043e0d8705a8 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -723,21 +723,6 @@ int venus_helper_set_work_mode(struct venus_inst *inst, u32 mode) } EXPORT_SYMBOL_GPL(venus_helper_set_work_mode); -int venus_helper_set_core_usage(struct venus_inst *inst, u32 usage) -{ - const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE; - struct hfi_videocores_usage_type cu; - - inst->clk_data.core_id = usage; - if (!IS_V4(inst->core)) - return 0; - - cu.video_core_enable_mask = usage; - - return hfi_session_set_property(inst, ptype, &cu); -} -EXPORT_SYMBOL_GPL(venus_helper_set_core_usage); - int venus_helper_init_codec_freq_data(struct venus_inst *inst) { const struct codec_freq_data *data; @@ -1101,6 +1086,8 @@ void venus_helper_vb2_stop_streaming(struct vb2_queue *q) else inst->streamon_cap = 0; + venus_pm_release_core(inst); + mutex_unlock(&inst->lock); } EXPORT_SYMBOL_GPL(venus_helper_vb2_stop_streaming); diff --git a/drivers/media/platform/qcom/venus/helpers.h b/drivers/media/platform/qcom/venus/helpers.h index 44b50914cd12..b64875564064 100644 --- a/drivers/media/platform/qcom/venus/helpers.h +++ b/drivers/media/platform/qcom/venus/helpers.h @@ -34,7 +34,6 @@ int venus_helper_set_output_resolution(struct venus_inst *inst, u32 buftype); int venus_helper_set_work_mode(struct venus_inst *inst, u32 mode); int venus_helper_init_codec_freq_data(struct venus_inst *inst); -int venus_helper_set_core_usage(struct venus_inst *inst, u32 usage); int venus_helper_set_num_bufs(struct venus_inst *inst, unsigned int input_bufs, unsigned int output_bufs, unsigned int output2_bufs); diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h index b70551e296b7..2a47f6c0a07a 100644 --- a/drivers/media/platform/qcom/venus/hfi_helper.h +++ b/drivers/media/platform/qcom/venus/hfi_helper.h @@ -550,6 +550,7 @@ struct hfi_bitrate { #define HFI_CAPABILITY_LCU_SIZE 0x14 #define HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS 0x15 #define HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE 0x16 +#define HFI_CAPABILITY_MAX_VIDEOCORES 0x2b struct hfi_capability { u32 capability_type; diff --git a/drivers/media/platform/qcom/venus/hfi_parser.h b/drivers/media/platform/qcom/venus/hfi_parser.h index 3e931c747e19..264e6dd2415f 100644 --- a/drivers/media/platform/qcom/venus/hfi_parser.h +++ b/drivers/media/platform/qcom/venus/hfi_parser.h @@ -107,4 +107,9 @@ static inline u32 frate_step(struct venus_inst *inst) return cap_step(inst, HFI_CAPABILITY_FRAMERATE); } +static inline u32 core_num_max(struct venus_inst *inst) +{ + return cap_max(inst, HFI_CAPABILITY_MAX_VIDEOCORES); +} + #endif diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index 9531c01f067b..46d9d2fb5e23 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -14,6 +14,7 @@ #include #include "core.h" +#include "hfi_parser.h" #include "hfi_venus_io.h" #include "pm_helpers.h" @@ -480,6 +481,173 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask) return 0; } +static void +min_loaded_core(struct venus_inst *inst, u32 *min_coreid, u32 *min_load) +{ + u32 mbs_per_sec, load, core1_load = 0, core2_load = 0; + u32 cores_max = core_num_max(inst); + struct venus_core *core = inst->core; + struct venus_inst *inst_pos; + unsigned long vpp_freq; + u32 coreid; + + mutex_lock(&core->lock); + + list_for_each_entry(inst_pos, &core->instances, list) { + if (inst_pos == inst) + continue; + vpp_freq = inst_pos->clk_data.codec_freq_data->vpp_freq; + coreid = inst_pos->clk_data.core_id; + + mbs_per_sec = load_per_instance(inst_pos); + load = mbs_per_sec * vpp_freq; + + if ((coreid & VIDC_CORE_ID_3) == VIDC_CORE_ID_3) { + core1_load += load / 2; + core2_load += load / 2; + } else if (coreid & VIDC_CORE_ID_1) { + core1_load += load; + } else if (coreid & VIDC_CORE_ID_2) { + core2_load += load; + } + } + + *min_coreid = core1_load <= core2_load ? + VIDC_CORE_ID_1 : VIDC_CORE_ID_2; + *min_load = min(core1_load, core2_load); + + if (cores_max < VIDC_CORE_ID_2 || core->res->vcodec_num < 2) { + *min_coreid = VIDC_CORE_ID_1; + *min_load = core1_load; + } + + mutex_unlock(&core->lock); +} + +static int decide_core(struct venus_inst *inst) +{ + const u32 ptype = HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE; + struct venus_core *core = inst->core; + u32 min_coreid, min_load, inst_load; + struct hfi_videocores_usage_type cu; + unsigned long max_freq; + + if (legacy_binding) { + if (inst->session_type == VIDC_SESSION_TYPE_DEC) + cu.video_core_enable_mask = VIDC_CORE_ID_1; + else + cu.video_core_enable_mask = VIDC_CORE_ID_2; + + goto done; + } + + if (inst->clk_data.core_id != VIDC_CORE_ID_DEFAULT) + return 0; + + inst_load = load_per_instance(inst); + inst_load *= inst->clk_data.codec_freq_data->vpp_freq; + max_freq = core->res->freq_tbl[0].freq; + + min_loaded_core(inst, &min_coreid, &min_load); + + if ((inst_load + min_load) > max_freq) { + dev_warn(core->dev, "HW is overloaded, needed: %u max: %lu\n", + inst_load, max_freq); + return -EINVAL; + } + + inst->clk_data.core_id = min_coreid; + cu.video_core_enable_mask = min_coreid; + +done: + return hfi_session_set_property(inst, ptype, &cu); +} + +static int acquire_core(struct venus_inst *inst) +{ + struct venus_core *core = inst->core; + unsigned int coreid_mask = 0; + + if (inst->core_acquired) + return 0; + + inst->core_acquired = true; + + if (inst->clk_data.core_id & VIDC_CORE_ID_1) { + if (core->core0_usage_count++) + return 0; + + coreid_mask = VIDC_CORE_ID_1; + } + + if (inst->clk_data.core_id & VIDC_CORE_ID_2) { + if (core->core1_usage_count++) + return 0; + + coreid_mask |= VIDC_CORE_ID_2; + } + + return poweron_coreid(core, coreid_mask); +} + +static int release_core(struct venus_inst *inst) +{ + struct venus_core *core = inst->core; + unsigned int coreid_mask = 0; + int ret; + + if (!inst->core_acquired) + return 0; + + if (inst->clk_data.core_id & VIDC_CORE_ID_1) { + if (--core->core0_usage_count) + goto done; + + coreid_mask = VIDC_CORE_ID_1; + } + + if (inst->clk_data.core_id & VIDC_CORE_ID_2) { + if (--core->core1_usage_count) + goto done; + + coreid_mask |= VIDC_CORE_ID_2; + } + + ret = poweroff_coreid(core, coreid_mask); + if (ret) + return ret; + +done: + inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT; + inst->core_acquired = false; + return 0; +} + +static int coreid_power_v4(struct venus_inst *inst, int on) +{ + struct venus_core *core = inst->core; + int ret; + + if (legacy_binding) + return 0; + + if (on == POWER_ON) { + ret = decide_core(inst); + if (ret) + return ret; + + mutex_lock(&core->lock); + ret = acquire_core(inst); + mutex_unlock(&core->lock); + } else { + mutex_lock(&core->lock); + ret = release_core(inst); + mutex_unlock(&core->lock); + } + + return ret; +} + static int vdec_get_v4(struct device *dev) { struct venus_core *core = dev_get_drvdata(dev); @@ -661,22 +829,12 @@ static void core_put_v4(struct device *dev) static int core_power_v4(struct device *dev, int on) { struct venus_core *core = dev_get_drvdata(dev); - const unsigned int coreid_mask = VIDC_CORE_ID_1 | VIDC_CORE_ID_2; int ret = 0; - if (on == POWER_ON) { + if (on == POWER_ON) ret = core_clks_enable(core); - if (ret) - return ret; - - if (!legacy_binding) - ret = poweron_coreid(core, coreid_mask); - } else { - if (!legacy_binding) - ret = poweroff_coreid(core, coreid_mask); - + else core_clks_disable(core); - } return ret; } @@ -786,6 +944,7 @@ static const struct venus_pm_ops pm_ops_v4 = { .venc_get = venc_get_v4, .venc_put = venc_put_v4, .venc_power = venc_power_v4, + .coreid_power = coreid_power_v4, .load_scale = load_scale_v4, }; diff --git a/drivers/media/platform/qcom/venus/pm_helpers.h b/drivers/media/platform/qcom/venus/pm_helpers.h index d98b6dc20740..aa2f6afa2354 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.h +++ b/drivers/media/platform/qcom/venus/pm_helpers.h @@ -21,6 +21,8 @@ struct venus_pm_ops { void (*venc_put)(struct device *dev); int (*venc_power)(struct device *dev, int on); + int (*coreid_power)(struct venus_inst *inst, int on); + int (*load_scale)(struct venus_inst *inst); }; @@ -36,4 +38,28 @@ static inline int venus_pm_load_scale(struct venus_inst *inst) return core->pm_ops->load_scale(inst); } +static inline int venus_pm_acquire_core(struct venus_inst *inst) +{ + struct venus_core *core = inst->core; + const struct venus_pm_ops *pm_ops = core->pm_ops; + int ret = 0; + + if (pm_ops && pm_ops->coreid_power) + ret = pm_ops->coreid_power(inst, POWER_ON); + + return ret; +} + +static inline int venus_pm_release_core(struct venus_inst *inst) +{ + struct venus_core *core = inst->core; + const struct venus_pm_ops *pm_ops = core->pm_ops; + int ret = 0; + + if (pm_ops && pm_ops->coreid_power) + ret = pm_ops->coreid_power(inst, POWER_OFF); + + return ret; +} + #endif diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 83ce30516591..7b7a4f3377cf 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -579,10 +579,6 @@ static int vdec_output_conf(struct venus_inst *inst) if (ret) return ret; - ret = venus_helper_set_core_usage(inst, VIDC_CORE_ID_1); - if (ret) - return ret; - if (core->res->hfi_version == HFI_VERSION_1XX) { ptype = HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER; ret = hfi_session_set_property(inst, ptype, &en); @@ -951,6 +947,10 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count) mutex_lock(&inst->lock); + ret = venus_pm_acquire_core(inst); + if (ret) + return ret; + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) ret = vdec_start_capture(inst); else @@ -1078,6 +1078,7 @@ static void vdec_session_release(struct venus_inst *inst) venus_helper_free_dpb_bufs(inst); venus_pm_load_scale(inst); + venus_pm_release_core(inst); INIT_LIST_HEAD(&inst->registeredbufs); mutex_unlock(&inst->lock); @@ -1337,6 +1338,8 @@ static int vdec_open(struct file *file) inst->num_output_bufs = 1; inst->codec_state = VENUS_DEC_STATE_DEINIT; inst->buf_count = 0; + inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT; + inst->core_acquired = false; init_waitqueue_head(&inst->reconf_wait); venus_helper_init_instance(inst); diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 5fa1724cb537..4f594fe4b661 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -656,10 +656,6 @@ static int venc_set_properties(struct venus_inst *inst) if (ret) return ret; - ret = venus_helper_set_core_usage(inst, VIDC_CORE_ID_2); - if (ret) - return ret; - ptype = HFI_PROPERTY_CONFIG_FRAME_RATE; frate.buffer_type = HFI_BUFFER_OUTPUT; frate.framerate = inst->fps * (1 << 16); @@ -992,6 +988,10 @@ static int venc_start_streaming(struct vb2_queue *q, unsigned int count) if (ret) goto bufs_done; + ret = venus_pm_acquire_core(inst); + if (ret) + goto deinit_sess; + ret = venc_set_properties(inst); if (ret) goto deinit_sess; @@ -1160,6 +1160,8 @@ static int venc_open(struct file *file) inst->core = core; inst->session_type = VIDC_SESSION_TYPE_ENC; + inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT; + inst->core_acquired = false; venus_helper_init_instance(inst);