From patchwork Thu Jan 24 07:01:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Asutosh Das (asd)" X-Patchwork-Id: 10778425 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 95710139A for ; Thu, 24 Jan 2019 07:02:11 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 83B4C2E281 for ; Thu, 24 Jan 2019 07:02:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7791E2E282; Thu, 24 Jan 2019 07:02:11 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6D6012E2D7 for ; Thu, 24 Jan 2019 07:02:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726074AbfAXHCE (ORCPT ); Thu, 24 Jan 2019 02:02:04 -0500 Received: from alexa-out-blr-02.qualcomm.com ([103.229.18.198]:64373 "EHLO alexa-out-blr.qualcomm.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1725287AbfAXHCE (ORCPT ); Thu, 24 Jan 2019 02:02:04 -0500 X-IronPort-AV: E=Sophos;i="5.56,515,1539628200"; d="scan'208";a="321553" Received: from ironmsg04-blr.qualcomm.com ([10.86.208.133]) by alexa-out-blr.qualcomm.com with ESMTP/TLS/AES256-SHA; 24 Jan 2019 12:31:25 +0530 X-IronPort-AV: E=McAfee;i="5900,7806,9145"; a="3351238" Received: from asutoshd-linux.qualcomm.com ([10.206.24.163]) by ironmsg04-blr.qualcomm.com with ESMTP; 24 Jan 2019 12:31:24 +0530 Received: by asutoshd-linux.qualcomm.com (Postfix, from userid 92687) id C9E443B51; Thu, 24 Jan 2019 12:31:23 +0530 (IST) From: Asutosh Das To: subhashj@codeaurora.org, cang@codeaurora.org, vivek.gautam@codeaurora.org, rnayak@codeaurora.org, vinholikatti@gmail.com, jejb@linux.vnet.ibm.com, martin.petersen@oracle.com, linux-scsi@vger.kernel.org Cc: Asutosh Das , linux-arm-msm@vger.kernel.org, Rob Herring , Mark Rutland , devicetree@vger.kernel.org (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS), linux-kernel@vger.kernel.org (open list) Subject: [ 1/1] scsi: qcom-ufs: Add support for bus voting using ICB framework Date: Thu, 24 Jan 2019 12:31:02 +0530 Message-Id: X-Mailer: git-send-email 1.9.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Adapt to the new ICB framework for bus bandwidth voting. This requires the source/destination port ids. Also this requires a tuple of values. The tuple is for two different paths - from UFS master to BIMC slave. The other is from CPU master to UFS slave. This tuple consists of the average and peak bandwidth. Signed-off-by: Asutosh Das --- .../devicetree/bindings/ufs/ufshcd-pltfrm.txt | 12 ++ drivers/scsi/ufs/ufs-qcom.c | 234 ++++++++++++++++----- drivers/scsi/ufs/ufs-qcom.h | 20 ++ 3 files changed, 218 insertions(+), 48 deletions(-) diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt index a99ed55..94249ef 100644 --- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt +++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt @@ -45,6 +45,18 @@ Optional properties: Note: If above properties are not defined it can be assumed that the supply regulators or clocks are always on. +* Following bus parameters are required: +interconnects +interconnect-names +- Please refer to Documentation/devicetree/bindings/interconnect/ + for more details on the above. +qcom,msm-bus,name - string describing the bus path +qcom,msm-bus,num-cases - number of configurations in which ufs can operate in +qcom,msm-bus,num-paths - number of paths to vote for +qcom,msm-bus,vectors-KBps - Takes a tuple , (2 tuples for 2 num-paths) + The number of these entries *must* be same as + num-cases. + Example: ufshc@0xfc598000 { compatible = "jedec,ufs-1.1"; diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 2b38db2..213e975 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "ufshcd.h" @@ -27,6 +28,10 @@ #define UFS_QCOM_DEFAULT_DBG_PRINT_EN \ (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) +#define UFS_DDR "ufs-ddr" +#define CPU_UFS "cpu-ufs" + + enum { TSTBUS_UAWM, TSTBUS_UARM, @@ -714,7 +719,6 @@ static int ufs_qcom_get_pwr_dev_param(struct ufs_qcom_dev_params *qcom_param, return 0; } -#ifdef CONFIG_MSM_BUS_SCALING static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host, const char *speed_mode) { @@ -768,24 +772,83 @@ static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result) } } +static int ufs_qcom_get_ib_ab(struct ufs_qcom_host *host, int index, + struct qcom_bus_vectors *ufs_ddr_vec, + struct qcom_bus_vectors *cpu_ufs_vec) +{ + struct qcom_bus_path *usecase; + + if (!host->qbsd) + return -EINVAL; + + if (index > host->qbsd->num_usecase) + return -EINVAL; + + usecase = host->qbsd->usecase; + + /* + * + * usecase:0 usecase:0 + * ufs->ddr cpu->ufs + * |vec[0&1] | vec[2&3]| + * +----+----+----+----+ + * | ab | ib | ab | ib | + * |----+----+----+----+ + * . + * . + * . + * usecase:n usecase:n + * ufs->ddr cpu->ufs + * |vec[0&1] | vec[2&3]| + * +----+----+----+----+ + * | ab | ib | ab | ib | + * |----+----+----+----+ + */ + + /* index refers to offset in usecase */ + ufs_ddr_vec->ab = usecase[index].vec[0].ab; + ufs_ddr_vec->ib = usecase[index].vec[0].ib; + + cpu_ufs_vec->ab = usecase[index].vec[1].ab; + cpu_ufs_vec->ib = usecase[index].vec[1].ib; + + return 0; +} + static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) { int err = 0; + struct qcom_bus_scale_data *d = host->qbsd; + struct qcom_bus_vectors path0, path1; + struct device *dev = host->hba->dev; - if (vote != host->bus_vote.curr_vote) { - err = msm_bus_scale_client_update_request( - host->bus_vote.client_handle, vote); - if (err) { - dev_err(host->hba->dev, - "%s: msm_bus_scale_client_update_request() failed: bus_client_handle=0x%x, vote=%d, err=%d\n", - __func__, host->bus_vote.client_handle, - vote, err); - goto out; - } + err = ufs_qcom_get_ib_ab(host, vote, &path0, &path1); + if (err) { + dev_err(dev, "Error: failed (%d) to get ib/ab\n", + err); + return err; + } - host->bus_vote.curr_vote = vote; + dev_dbg(dev, "Setting vote: %d: ufs-ddr: ab: %llu ib: %llu\n", vote, + path0.ab, path0.ib); + err = icc_set_bw(d->ufs_ddr, path0.ab, path0.ib); + if (err) { + dev_err(dev, "Error: (%d) failed setting (%s) bus vote\n", err, + UFS_DDR); + return err; } -out: + + dev_dbg(dev, "Setting: cpu-ufs: ab: %llu ib: %llu\n", path1.ab, + path1.ib); + err = icc_set(d->cpu_ufs, path1.ab, path1.ib); + if (err) { + dev_err(dev, "Error: (%d) failed setting (%s) bus vote\n", err, + CPU_UFS); + return err; + } + + host->bus_vote.curr_vote = vote; + return err; } @@ -807,6 +870,7 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) dev_err(host->hba->dev, "%s: failed %d\n", __func__, err); else host->bus_vote.saved_vote = vote; + return err; } @@ -837,34 +901,114 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) return count; } +static struct qcom_bus_scale_data *ufs_qcom_get_bus_scale_data(struct device + *dev) + +{ + struct platform_device *pdev = to_platform_device(dev); + struct device_node *of_node = dev->of_node; + struct qcom_bus_scale_data *qsd; + struct qcom_bus_path *usecase = NULL; + int ret = 0, i = 0, j, num_paths, len; + const uint32_t *vec_arr = NULL; + bool mem_err = false; + + if (!pdev) { + dev_err(dev, "Null platform device!\n"); + return NULL; + } + + qsd = devm_kzalloc(dev, sizeof(struct qcom_bus_scale_data), GFP_KERNEL); + if (!qsd) + return NULL; + + ret = of_property_read_string(of_node, "qcom,msm-bus,name", &qsd->name); + if (ret) { + dev_err(dev, "Error: (%d) Bus name missing!\n", ret); + return NULL; + } + + ret = of_property_read_u32(of_node, "qcom,msm-bus,num-cases", + &qsd->num_usecase); + if (ret) { + pr_err("Error: num-usecases not found\n"); + goto err; + } + + usecase = devm_kzalloc(dev, (sizeof(struct qcom_bus_path) * + qsd->num_usecase), GFP_KERNEL); + if (!usecase) + return NULL; + + ret = of_property_read_u32(of_node, "qcom,msm-bus,num-paths", + &num_paths); + if (ret) { + pr_err("Error: num_paths not found\n"); + return NULL; + } + + vec_arr = of_get_property(of_node, "qcom,msm-bus,vectors-KBps", &len); + if (vec_arr == NULL) { + pr_err("Error: Vector array not found\n"); + return NULL; + } + + for (i = 0; i < qsd->num_usecase; i++) { + usecase[i].num_paths = num_paths; + usecase[i].vec = devm_kzalloc(dev, num_paths * + sizeof(struct qcom_bus_vectors), + GFP_KERNEL); + if (!usecase[i].vec) { + mem_err = true; + dev_err(dev, "Error: Failed to alloc mem for vectors\n"); + goto err; + } + + for (j = 0; j < num_paths; j++) { + int idx = ((i * num_paths) + j) * 2; + + usecase[i].vec[j].ab = (uint64_t) + be32_to_cpu(vec_arr[idx]); + usecase[i].vec[j].ib = (uint64_t) + be32_to_cpu(vec_arr[idx + 1]); + } + } + + qsd->usecase = usecase; + return qsd; +err: + if (mem_err) { + for (; i > 0; i--) + kfree(usecase[i].vec); + } + return NULL; +} + static int ufs_qcom_bus_register(struct ufs_qcom_host *host) { int err; - struct msm_bus_scale_pdata *bus_pdata; struct device *dev = host->hba->dev; - struct platform_device *pdev = to_platform_device(dev); - struct device_node *np = dev->of_node; + struct qcom_bus_scale_data *qsd; - bus_pdata = msm_bus_cl_get_pdata(pdev); - if (!bus_pdata) { - dev_err(dev, "%s: failed to get bus vectors\n", __func__); - err = -ENODATA; - goto out; + qsd = ufs_qcom_get_bus_scale_data(dev); + if (!qsd) { + dev_err(dev, "Failed: getting bus_scale data\n"); + return 0; } + host->qbsd = qsd; - err = of_property_count_strings(np, "qcom,bus-vector-names"); - if (err < 0 || err != bus_pdata->num_usecases) { - dev_err(dev, "%s: qcom,bus-vector-names not specified correctly %d\n", - __func__, err); - goto out; + qsd->ufs_ddr = of_icc_get(dev, UFS_DDR); + if (IS_ERR(qsd->ufs_ddr)) { + dev_err(dev, "Error: (%d) failed getting %s path\n", + PTR_ERR(qsd->ufs_ddr), UFS_DDR); + return PTR_ERR(qsd->ufs_ddr); } - host->bus_vote.client_handle = msm_bus_scale_register_client(bus_pdata); - if (!host->bus_vote.client_handle) { - dev_err(dev, "%s: msm_bus_scale_register_client failed\n", - __func__); - err = -EFAULT; - goto out; + qsd->cpu_ufs = of_icc_get(dev, CPU_UFS); + if (IS_ERR(qsd->cpu_ufs)) { + dev_err(dev, "Error: (%d) failed getting %s path\n", + PTR_ERR(qsd->cpu_ufs), CPU_UFS); + return PTR_ERR(qsd->cpu_ufs); } /* cache the vote index for minimum and maximum bandwidth */ @@ -877,25 +1021,19 @@ static int ufs_qcom_bus_register(struct ufs_qcom_host *host) host->bus_vote.max_bus_bw.attr.name = "max_bus_bw"; host->bus_vote.max_bus_bw.attr.mode = S_IRUGO | S_IWUSR; err = device_create_file(dev, &host->bus_vote.max_bus_bw); -out: - return err; -} -#else /* CONFIG_MSM_BUS_SCALING */ -static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host) -{ - return 0; -} + if (err) + dev_err(dev, "Error: (%d) Failed to create sysfs entries\n", + err); -static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote) -{ - return 0; -} + /* Full throttle */ + err = ufs_qcom_set_bus_vote(host, host->bus_vote.max_bw_vote); + if (err) + dev_err(dev, "Error: (%d) Failed to set max bus vote\n", err); -static int ufs_qcom_bus_register(struct ufs_qcom_host *host) -{ - return 0; + dev_info(dev, "-- (%s) Registered bus voting! (%d) --\n", err); + + return err; } -#endif /* CONFIG_MSM_BUS_SCALING */ static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable) { diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index 295f4be..02140bd 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -207,6 +207,25 @@ struct ufs_qcom_testbus { u8 select_minor; }; +struct qcom_bus_vectors { + uint64_t ab; + uint64_t ib; +}; + +struct qcom_bus_path { + unsigned int num_paths; + struct qcom_bus_vectors *vec; +}; + +struct qcom_bus_scale_data { + struct qcom_bus_path *usecase; + unsigned int num_usecase; + struct icc_path *ufs_ddr; + struct icc_path *cpu_ufs; + + const char *name; +}; + struct ufs_qcom_host { /* * Set this capability if host controller supports the QUniPro mode @@ -242,6 +261,7 @@ struct ufs_qcom_host { /* Bitmask for enabling debug prints */ u32 dbg_print_en; struct ufs_qcom_testbus testbus; + struct qcom_bus_scale_data *qbsd; }; static inline u32