From 710f989e84dd436399307e09ba6327799e10b2ef Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Fri, 24 May 2019 14:51:23 -0700 Subject: [PATCH] msm: ipa3: support ipa clk scaling for pcie modem Add the QMI support to change ipa clk scaling from PCIE modem. Change-Id: Iee77ff4b8027c2a042f2e6c640749cdec09d92dc Signed-off-by: Arnav Sharma --- ipa/ipa_v3/ipa.c | 5 +-- ipa/ipa_v3/ipa_debugfs.c | 33 ++++++++++++++++--- ipa/ipa_v3/ipa_odl.c | 42 +++++++++++++++++++++++- ipa/ipa_v3/ipa_odl.h | 3 +- ipa/ipa_v3/ipa_pm.c | 13 ++++++-- ipa/ipa_v3/ipa_pm.h | 2 +- ipa/ipa_v3/ipa_qmi_service.c | 62 +++++++++++++++++++++++++++++++----- ipa/ipa_v3/rmnet_ipa.c | 3 +- 8 files changed, 142 insertions(+), 21 deletions(-) diff --git a/ipa/ipa_v3/ipa.c b/ipa/ipa_v3/ipa.c index 81de4a1478a9..022aed42b1f1 100644 --- a/ipa/ipa_v3/ipa.c +++ b/ipa/ipa_v3/ipa.c @@ -6708,7 +6708,7 @@ static int get_ipa_dts_pm_info(struct platform_device *pdev, result = of_property_read_string_index(pdev->dev.of_node, "qcom,scaling-exceptions", - i * ipa_drv_res->pm_init.threshold_size, + i * (ipa_drv_res->pm_init.threshold_size + 1), &ex[i].usecase); if (result) { IPAERR("failed to read qcom,scaling-exceptions"); @@ -6721,7 +6721,8 @@ static int get_ipa_dts_pm_info(struct platform_device *pdev, result = of_property_read_string_index( pdev->dev.of_node, "qcom,scaling-exceptions", - i * ipa_drv_res->pm_init.threshold_size + j + 1, + i * (ipa_drv_res->pm_init.threshold_size + 1) + + j + 1, &str); if (result) { IPAERR("failed to read qcom,scaling-exceptions" diff --git a/ipa/ipa_v3/ipa_debugfs.c b/ipa/ipa_v3/ipa_debugfs.c index 51a2fc7d9a1f..107df555a1de 100644 --- a/ipa/ipa_v3/ipa_debugfs.c +++ b/ipa/ipa_v3/ipa_debugfs.c @@ -12,6 +12,7 @@ #include "../ipa_rm_i.h" #include "ipahal/ipahal_nat.h" #include "ipa_odl.h" +#include "ipa_qmi_service.h" #define IPA_MAX_ENTRY_STRING_LEN 500 #define IPA_MAX_MSG_LEN 4096 @@ -319,17 +320,41 @@ static ssize_t ipa3_write_keep_awake(struct file *file, const char __user *buf, { s8 option = 0; int ret; + uint32_t bw_mbps = 0; ret = kstrtos8_from_user(buf, count, 0, &option); if (ret) return ret; - if (option == 1) - IPA_ACTIVE_CLIENTS_INC_SIMPLE(); - else if (option == 0) + switch (option) { + case 0: IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); - else + bw_mbps = 0; + break; + case 1: + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + bw_mbps = 0; + break; + case 2: + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + bw_mbps = 700; + break; + case 3: + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + bw_mbps = 3000; + break; + case 4: + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + bw_mbps = 7000; + break; + default: + pr_err("Not support this vote (%d)\n", option); return -EFAULT; + } + if (ipa3_vote_for_bus_bw(&bw_mbps)) { + IPAERR("Failed to vote for bus BW (%u)\n", bw_mbps); + return -EFAULT; + } return count; } diff --git a/ipa/ipa_v3/ipa_odl.c b/ipa/ipa_v3/ipa_odl.c index feef25d37b9c..f6173cea6145 100644 --- a/ipa/ipa_v3/ipa_odl.c +++ b/ipa/ipa_v3/ipa_odl.c @@ -318,6 +318,30 @@ int ipa_setup_odl_pipe(void) } +/** + * ipa3_odl_register_pm - Register odl client for PM + * + * This function will register 1 client with IPA PM to represent odl + * in clock scaling calculation: + * - "ODL" - this client will be activated when pipe connected + */ +static int ipa3_odl_register_pm(void) +{ + int result = 0; + struct ipa_pm_register_params pm_reg; + + memset(&pm_reg, 0, sizeof(pm_reg)); + pm_reg.name = "ODL"; + pm_reg.group = IPA_PM_GROUP_DEFAULT; + pm_reg.skip_clk_vote = true; + result = ipa_pm_register(&pm_reg, &ipa3_odl_ctx->odl_pm_hdl); + if (result) { + IPAERR("failed to create IPA PM client %d\n", result); + return result; + } + return result; +} + int ipa3_odl_pipe_open(void) { int ret = 0; @@ -367,6 +391,10 @@ static int ipa_adpl_open(struct inode *inode, struct file *filp) IPADBG("Called the function :\n"); if (ipa3_odl_ctx->odl_state.odl_init && !ipa3_odl_ctx->odl_state.adpl_open) { + /* Activate ipa_pm*/ + ret = ipa_pm_activate_sync(ipa3_odl_ctx->odl_pm_hdl); + if (ret) + IPAERR("failed to activate pm\n"); ipa3_odl_ctx->odl_state.adpl_open = true; ret = ipa3_odl_pipe_open(); } else { @@ -380,8 +408,13 @@ static int ipa_adpl_open(struct inode *inode, struct file *filp) static int ipa_adpl_release(struct inode *inode, struct file *filp) { + int ret = 0; + /* Deactivate ipa_pm */ + ret = ipa_pm_deactivate_sync(ipa3_odl_ctx->odl_pm_hdl); + if (ret) + IPAERR("failed to activate pm\n"); ipa3_odl_pipe_cleanup(false); - return 0; + return ret; } void ipa3_odl_pipe_cleanup(bool is_ssr) @@ -668,6 +701,13 @@ int ipa_odl_init(void) } ipa3_odl_ctx->odl_state.odl_init = true; + + /* register ipa_pm */ + result = ipa3_odl_register_pm(); + if (result) { + IPAWANERR("ipa3_odl_register_pm failed, ret: %d\n", + result); + } return 0; cdev1_add_fail: device_destroy(odl_cdev[1].class, odl_cdev[1].dev_num); diff --git a/ipa/ipa_v3/ipa_odl.h b/ipa/ipa_v3/ipa_odl.h index c6e4a47b43fc..8090a8d7d892 100644 --- a/ipa/ipa_v3/ipa_odl.h +++ b/ipa/ipa_v3/ipa_odl.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ #ifndef _IPA3_ODL_H_ @@ -56,6 +56,7 @@ struct ipa_odl_context { struct odl_state_bit_mask odl_state; bool odl_ctl_msg_wq_flag; struct ipa3_odlstats stats; + u32 odl_pm_hdl; }; struct ipa3_push_msg_odl { diff --git a/ipa/ipa_v3/ipa_pm.c b/ipa/ipa_v3/ipa_pm.c index afc2b7b5b10d..c73f32cb2c9a 100644 --- a/ipa/ipa_v3/ipa_pm.c +++ b/ipa/ipa_v3/ipa_pm.c @@ -361,7 +361,7 @@ static int do_clk_scaling(void) mutex_unlock(&ipa_pm_ctx->client_mutex); for (i = 0; i < clk_scaling->threshold_size; i++) { - if (tput > clk_scaling->current_threshold[i]) + if (tput >= clk_scaling->current_threshold[i]) new_th_idx++; } @@ -526,15 +526,19 @@ static int find_next_open_array_element(const char *name) */ static int add_client_to_exception_list(u32 hdl) { - int i; + int i, len = 0; struct ipa_pm_exception_list *exception; mutex_lock(&ipa_pm_ctx->client_mutex); + len = strlen(ipa_pm_ctx->clients[hdl]->name); for (i = 0; i < ipa_pm_ctx->clk_scaling.exception_size; i++) { exception = &ipa_pm_ctx->clk_scaling.exception_list[i]; if (strnstr(exception->clients, ipa_pm_ctx->clients[hdl]->name, - strlen(exception->clients))) { + len) && (strlen(exception->clients) + == len)) { exception->pending--; + IPA_PM_DBG("Pending: %d\n", + exception->pending); if (exception->pending < 0) { WARN_ON(1); @@ -568,6 +572,8 @@ static int remove_client_from_exception_list(u32 hdl) exception = &ipa_pm_ctx->clk_scaling.exception_list[i]; if (exception->bitmask & (1 << hdl)) { exception->pending++; + IPA_PM_DBG("Pending: %d\n", + exception->pending); exception->bitmask &= ~(1 << hdl); } } @@ -651,6 +657,7 @@ int ipa_pm_init(struct ipa_pm_init_params *params) clk_scaling->exception_list[i].pending++; } + /* for the first client */ clk_scaling->exception_list[i].pending++; IPA_PM_DBG("Pending: %d\n", clk_scaling->exception_list[i].pending); diff --git a/ipa/ipa_v3/ipa_pm.h b/ipa/ipa_v3/ipa_pm.h index 118a64ccabd3..044330b1760c 100644 --- a/ipa/ipa_v3/ipa_pm.h +++ b/ipa/ipa_v3/ipa_pm.h @@ -12,7 +12,7 @@ #define IPA_PM_MAX_CLIENTS 32 /* actual max is value -1 since we start from 1*/ #define IPA_PM_MAX_EX_CL 64 #define IPA_PM_THRESHOLD_MAX 5 -#define IPA_PM_EXCEPTION_MAX 2 +#define IPA_PM_EXCEPTION_MAX 5 #define IPA_PM_DEFERRED_TIMEOUT 10 /* diff --git a/ipa/ipa_v3/ipa_qmi_service.c b/ipa/ipa_v3/ipa_qmi_service.c index 82565376cdd2..2db32453576e 100644 --- a/ipa/ipa_v3/ipa_qmi_service.c +++ b/ipa/ipa_v3/ipa_qmi_service.c @@ -313,7 +313,7 @@ static void ipa3_handle_mhi_alloc_channel_req(struct qmi_handle *qmi_handle, resp = imp_handle_allocate_channel_req(ch_alloc_req); if (!resp) { - IPAWANERR("imp handle allocate channel req fails"); + IPAWANERR("imp handle allocate channel req fails\n"); return; } @@ -338,18 +338,62 @@ static void ipa3_handle_mhi_vote_req(struct qmi_handle *qmi_handle, const void *decoded_msg) { struct ipa_mhi_clk_vote_req_msg_v01 *vote_req; - struct ipa_mhi_clk_vote_resp_msg_v01 *resp = NULL; + struct ipa_mhi_clk_vote_resp_msg_v01 *resp = NULL, resp2; int rc; + uint32_t bw_mbps = 0; vote_req = (struct ipa_mhi_clk_vote_req_msg_v01 *)decoded_msg; IPAWANDBG("Received QMI_IPA_MHI_CLK_VOTE_REQ_V01(%d)\n", vote_req->mhi_vote); - resp = imp_handle_vote_req(vote_req->mhi_vote); - if (!resp) { - IPAWANERR("imp handle allocate channel req fails"); - return; + + memset(&resp2, 0, sizeof(struct ipa_mhi_clk_vote_resp_msg_v01)); + + /* for mpm used for ipa clk voting */ + if (ipa3_is_apq()) { + IPAWANDBG("Throughput(%d:%d) clk-rate(%d:%d)\n", + vote_req->tput_value_valid, + vote_req->tput_value, + vote_req->clk_rate_valid, + vote_req->clk_rate); + if (vote_req->clk_rate_valid) { + switch (vote_req->clk_rate) { + case QMI_IPA_CLOCK_RATE_LOW_SVS_V01: + bw_mbps = 0; + break; + case QMI_IPA_CLOCK_RATE_SVS_V01: + bw_mbps = 350; + break; + case QMI_IPA_CLOCK_RATE_NOMINAL_V01: + bw_mbps = 690; + break; + case QMI_IPA_CLOCK_RATE_TURBO_V01: + bw_mbps = 1200; + break; + default: + IPAWANERR("Note supported clk_rate (%d)\n", + vote_req->clk_rate); + bw_mbps = 0; + resp2.resp.result = IPA_QMI_RESULT_FAILURE_V01; + resp2.resp.error = + IPA_QMI_ERR_NOT_SUPPORTED_V01; + break; + } + if (ipa3_vote_for_bus_bw(&bw_mbps)) { + IPAWANERR("Failed to vote BW (%u)\n", bw_mbps); + resp2.resp.result = IPA_QMI_RESULT_FAILURE_V01; + resp2.resp.error = + IPA_QMI_ERR_NOT_SUPPORTED_V01; + } + resp = &resp2; + } + } else { + resp = imp_handle_vote_req(vote_req->mhi_vote); + if (!resp) { + IPAWANERR("imp handle allocate channel req fails"); + return; + } + IPAWANDBG("start sending QMI_IPA_MHI_CLK_VOTE_RESP_V01\n"); } - IPAWANDBG("start sending QMI_IPA_MHI_CLK_VOTE_RESP_V01\n"); IPAWANDBG("qmi_snd_rsp: result %d, err %d\n", resp->resp.result, resp->resp.error); @@ -1419,7 +1463,7 @@ static void ipa3_q6_clnt_svc_arrive(struct work_struct *work) return; IPAWANDBG("Q6 QMI service available now\n"); - if (ipa3_ctx->platform_type == IPA_PLAT_TYPE_APQ) { + if (ipa3_is_apq()) { ipa3_qmi_modem_init_fin = true; IPAWANDBG("QMI-client complete, ipa3_qmi_modem_init_fin : %d\n", ipa3_qmi_modem_init_fin); @@ -1812,6 +1856,8 @@ int ipa3_vote_for_bus_bw(uint32_t *bw_mbps) { int ret; + IPAWANDBG("Bus BW is %d\n", *bw_mbps); + if (bw_mbps == NULL) { IPAWANERR("Bus BW is invalid\n"); return -EINVAL; diff --git a/ipa/ipa_v3/rmnet_ipa.c b/ipa/ipa_v3/rmnet_ipa.c index 85742ccf05eb..00131163d3f8 100644 --- a/ipa/ipa_v3/rmnet_ipa.c +++ b/ipa/ipa_v3/rmnet_ipa.c @@ -2161,6 +2161,7 @@ int ipa3_wwan_set_modem_perf_profile(int throughput) int ret; int tether_bridge_handle = 0; + IPAWANDBG("throughput: %d\n", throughput); /* query rmnet-tethering handle */ tether_bridge_handle = ipa3_teth_bridge_get_pm_hdl(); if (tether_bridge_handle > 0) { @@ -2170,7 +2171,7 @@ int ipa3_wwan_set_modem_perf_profile(int throughput) } /* for TETH MODEM on softap/rndis */ ret = ipa_pm_set_throughput(rmnet_ipa3_ctx->q6_teth_pm_hdl, - throughput); + throughput); return ret; }