From patchwork Wed Jan 11 10:17:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sibi Sankar X-Patchwork-Id: 13096373 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 83FA1C46467 for ; Wed, 11 Jan 2023 10:18:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231979AbjAKKSq (ORCPT ); Wed, 11 Jan 2023 05:18:46 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44540 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232154AbjAKKSA (ORCPT ); Wed, 11 Jan 2023 05:18:00 -0500 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B0AB31038; Wed, 11 Jan 2023 02:17:59 -0800 (PST) Received: from pps.filterd (m0279868.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30B51xQk017194; Wed, 11 Jan 2023 10:17:54 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=qcppdkim1; bh=+YgbCYAPSVK90SB97LphXVYIY5ZBmjOJkMcTj+4RzHo=; b=J2TOtTd0umFveEHJYpfrbdwvXDgMt/9FNUEuN8VTi4PrMWzkpkFZ9x4/bKIJ6tb/94xZ 3mp3oK/9M4l72zDuwlMhhEhJniPTS8wM8XCdVYFBF4PtISpxLtJMzjqeo0HlLq6dlY2P Ypo/UuzBvteKSUWdsE4eeRo68jAfs170XlYPq3jOONAM0jCi6R+sYiAlTIfTSGu6Vyra TnqXm/w4y2Mv0aM5ZCG/ltVvYuM7uEoOwzdDAhuG2SHs9RnfK8iN3YNSMnXh79J0OQB3 oWnspqX70vW7Bw798TGWH0JZH16KIZo0URM/kDsLGEIBMPswtt1/AvPQGS3YQ0Om1CRl DA== Received: from nalasppmta03.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3n1k6a0xkn-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 11 Jan 2023 10:17:53 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA03.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 30BAHqJp020598 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 11 Jan 2023 10:17:52 GMT Received: from blr-ubuntu-87.ap.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.36; Wed, 11 Jan 2023 02:17:48 -0800 From: Sibi Sankar To: , CC: , , , , , , , , , Sibi Sankar Subject: [PATCH V8 1/2] dt-bindings: firmware: qcom,scm: Add optional interrupt Date: Wed, 11 Jan 2023 15:47:17 +0530 Message-ID: <20230111101718.9225-2-quic_sibis@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20230111101718.9225-1-quic_sibis@quicinc.com> References: <20230111101718.9225-1-quic_sibis@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-ORIG-GUID: q8Io6auYhCx4p0vFzIELQCL1GS0rhq-5 X-Proofpoint-GUID: q8Io6auYhCx4p0vFzIELQCL1GS0rhq-5 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.923,Hydra:6.0.545,FMLib:17.11.122.1 definitions=2023-01-11_04,2023-01-11_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 adultscore=0 lowpriorityscore=0 impostorscore=0 phishscore=0 clxscore=1015 malwarescore=0 mlxscore=0 priorityscore=1501 spamscore=0 bulkscore=0 mlxlogscore=999 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301110078 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org From: Guru Das Srinagesh Add an interrupt specification to the bindings to support the wait-queue feature on SM8450 SoCs. Signed-off-by: Guru Das Srinagesh Signed-off-by: Sibi Sankar Reviewed-by: Krzysztof Kozlowski --- The interrupt property for scm firmware from a binding perspective is completely optional i.e. not all tz fw running in the wild on sm8450 devices support this feature. The bootloader does the interrupt property addition on sm8450 devices with wait-queue support. v7 - Pick up R-b. v6: - Fix subject of bindings [Krzysztof] - Update commit message to include the SoC supporting the feature [Krzysztof] - Make the interrupt property valid on SM8450 SoC [Krzysztof] - Rebased on Krzysztof's narrow clocks and interconnect series. - Drop R-b v5: - Pick up R-b v4: - Qualify bindings [Krzysztoff] .../devicetree/bindings/firmware/qcom,scm.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml index 8e6e9ebb343d..01c861f36983 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml @@ -73,6 +73,12 @@ properties: '#reset-cells': const: 1 + interrupts: + description: + The wait-queue interrupt that firmware raises as part of handshake + protocol to handle sleeping SCM calls. + maxItems: 1 + qcom,dload-mode: $ref: /schemas/types.yaml#/definitions/phandle-array items: @@ -162,6 +168,18 @@ allOf: properties: interconnects: false + # Interrupts + - if: + not: + properties: + compatible: + contains: + enum: + - qcom,scm-sm8450 + then: + properties: + interrupts: false + required: - compatible From patchwork Wed Jan 11 10:17:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Sibi Sankar X-Patchwork-Id: 13096372 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4216BC5479D for ; Wed, 11 Jan 2023 10:18:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231839AbjAKKSp (ORCPT ); Wed, 11 Jan 2023 05:18:45 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44900 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232404AbjAKKSH (ORCPT ); Wed, 11 Jan 2023 05:18:07 -0500 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A632DBCC; Wed, 11 Jan 2023 02:18:05 -0800 (PST) Received: from pps.filterd (m0279863.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 30B8U0OL013635; Wed, 11 Jan 2023 10:17:58 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=quicinc.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type : content-transfer-encoding; s=qcppdkim1; bh=AqnttT8Uvk7RYuOLxJo8vSGfT73nYB2La7F/iGhZ/iQ=; b=jlIBMBGXjAjxatBgRy233hydN/jJ4KowxO3KwgtxL5Dz7tHLNopoQ2AvXUvxlS/JawDl K60ytlwH0Y5cSAtd/aHCW6R2M9+b4g9jJ+JVa2XFhN6DqL09IXOU7VDj/SSR+7kQpM62 jh+CRN4sWYiSSwhGzODY2fi5jgIIoLlW+tAwfscaQmY/BlPa6XfI09MYWtolEuWzdBAy eMn6b5fFvqKmaYN57jMlJKHmMIIth9OoOv6iWgqNCtdUzMIwPhK8rAdDhx89XDi0/10+ BffejiSUi1uuHczzRrsfZLY93udAUQHiXWw7W/aONJULxS/dqvjuYZ5TZdgAKNOrNZt/ Hg== Received: from nalasppmta01.qualcomm.com (Global_NAT1.qualcomm.com [129.46.96.20]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 3n1kxhgwe5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 11 Jan 2023 10:17:57 +0000 Received: from nalasex01a.na.qualcomm.com (nalasex01a.na.qualcomm.com [10.47.209.196]) by NALASPPMTA01.qualcomm.com (8.17.1.5/8.17.1.5) with ESMTPS id 30BAHusw020222 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 11 Jan 2023 10:17:56 GMT Received: from blr-ubuntu-87.ap.qualcomm.com (10.80.80.8) by nalasex01a.na.qualcomm.com (10.47.209.196) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.986.36; Wed, 11 Jan 2023 02:17:53 -0800 From: Sibi Sankar To: , CC: , , , , , , , , , Sibi Sankar Subject: [PATCH V8 2/2] firmware: qcom: scm: Add wait-queue handling logic Date: Wed, 11 Jan 2023 15:47:18 +0530 Message-ID: <20230111101718.9225-3-quic_sibis@quicinc.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20230111101718.9225-1-quic_sibis@quicinc.com> References: <20230111101718.9225-1-quic_sibis@quicinc.com> MIME-Version: 1.0 X-Originating-IP: [10.80.80.8] X-ClientProxiedBy: nasanex01b.na.qualcomm.com (10.46.141.250) To nalasex01a.na.qualcomm.com (10.47.209.196) X-QCInternal: smtphost X-Proofpoint-Virus-Version: vendor=nai engine=6200 definitions=5800 signatures=585085 X-Proofpoint-GUID: KszGqVJaItrlbckW1Z_TdM381zUr4BOh X-Proofpoint-ORIG-GUID: KszGqVJaItrlbckW1Z_TdM381zUr4BOh X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.219,Aquarius:18.0.923,Hydra:6.0.545,FMLib:17.11.122.1 definitions=2023-01-11_04,2023-01-11_01,2022-06-22_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 mlxscore=0 phishscore=0 priorityscore=1501 spamscore=0 bulkscore=0 adultscore=0 clxscore=1015 suspectscore=0 malwarescore=0 mlxlogscore=999 lowpriorityscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2212070000 definitions=main-2301110078 Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org From: Guru Das Srinagesh When the firmware (FW) supports multiple requests per VM, multiple requests from the same/different VM can reach the firmware at the same time. Since the firmware currently being used has limited resources, it guards them with a resource lock and puts requests on a wait-queue internally and signals to HLOS that it is doing so. It does this by returning a new return value in addition to success or error: SCM_WAITQ_SLEEP. A sleeping SCM call can be woken up by an interrupt that the FW raises. 1) SCM_WAITQ_SLEEP: When an SCM call receives this return value instead of success or error, FW has placed this call on a wait-queue and has signalled HLOS to put it to non-interruptible sleep. Along with this return value, FW also passes to HLOS `wq_ctx` - a unique number (UID) identifying the wait-queue that it has put the call on, internally. This is to help HLOS with its own bookkeeping to wake this sleeping call later. Additionally, FW also passes to HLOS `smc_call_ctx` - a UID identifying the SCM call thus being put to sleep. This is also for HLOS' bookkeeping to wake this call up later. These two additional values are passed via the a1 and a2 registers. N.B.: The "ctx" in the above UID names = "context". The handshake mechanism that HLOS uses to talk to FW about wait-queue operations involves two new SMC calls. 1) get_wq_ctx(): Arguments: None Returns: wq_ctx, flags, more_pending Get the wait-queue context, and wake up either one or all of the sleeping SCM calls associated with that wait-queue. Additionally, repeat this if there are more wait-queues that are ready to have their requests woken up (`more_pending`). 2) wq_resume(smc_call_ctx): Arguments: smc_call_ctx HLOS needs to issue this in response to receiving an IRQ, passing to FW the same smc_call_ctx that FW receives from HLOS via the get_wq_ctx() call. (The mechanism to wake a SMC call back up is described in detail below) VM_1 VM_2 Firmware │ │ │ │ │ │ │ │ │ │ │ │ │ REQUEST_1 │ │ ├────────────────────────┼─────────────────────────────────┤ │ │ │ │ │ ┌──┼──┐ │ │ │ │ │ │ │ REQUEST_2 │ │ │ │ ├──────────────────────────────┼──┤ │ │ │ │ │ │Resource │ │ │ │ │is busy │ │ {WQ_SLEEP} │ │ │ │ │◄─────────────────────────────┼──┤ │ │ │ wq_ctx, smc_call_ctx │ │ │ │ │ └──┼──┘ │ REQUEST_1 COMPLETE │ │ │◄───────────────────────┼─────────────────────────────────┤ │ │ │ │ │ IRQ │ │ │◄─-------------------------------│ │ │ │ │ │ get_wq_ctx() │ │ ├────────────────────────────────►│ │ │ │ │ │ │ │ │◄────────────────────────────────┤ │ │ wq_ctx, flags, and │ │ │ more_pending │ │ │ │ │ │ │ │ │ wq_resume(smc_call_ctx) │ │ ├────────────────────────────────►│ │ │ │ │ │ │ │ │ REQUEST_2 COMPLETE │ │ │◄────────────────────────────────┤ │ │ │ │ │ │ With the exception of get_wq_ctx(), the other SMC call wq_resume() can return WQ_SLEEP (these nested rounds of WQ_SLEEP are not shown in the above diagram for the sake of simplicity). Therefore, introduce a new do-while loop to handle multiple WQ_SLEEP return values for the same parent SCM call. Request Completion in the above diagram refers to either a success return value (zero) or error (and not SMC_WAITQ_SLEEP) Also add the interrupt handler that wakes up a sleeping SCM call. Signed-off-by: Guru Das Srinagesh Co-developed-by: Sibi Sankar Signed-off-by: Sibi Sankar --- v8: - Rename qcom_scm_lookup_wq to qcom_scm_assert_valid_wq_ctx [Bjorn] - Document wq_ctx limitations [Guru] - Drop dev check and add include completion header [Srini] - Rename qcom_scm_lookup_completion to qcom_scm_wait_for_wq_completion. v7: - Move lookup + wait_for_completion into a single function in qcom_scm [Bjorn] - Simplify completion retrieval [Bjorn] v6: - Fix misc. nits in the scm driver [Krzysztof] v5: - Handle the wake_one/wake_all flags [Guru] - Rename flag handler to qcom_scm_waitq_wakeup [Bjorn] - Resume scm call can return ebusy as well handle that scenario by retrying the original smc call and not the resume call v4: - platform_set_drvdata will be used by __scm_smc_do_quirk_handle_waitq to get access to scm struct from device so retain it - Use a single completion as it satisfies all of the current usecases [Bjorn] - Inline scm_get_wq_ctx [Bjorn] - Convert all pr_err to dev_err [Bjorn] - Handle idr_destroy in a thread safe manner [Bjorn] - Misc. Style fixes [Bjorn] v3: - Fixup irq handling so as not to affect SoCs without the interrupt. - Fix warnings reported by kernel test-bot. drivers/firmware/qcom_scm-smc.c | 87 +++++++++++++++++++++++++++--- drivers/firmware/qcom_scm.c | 93 ++++++++++++++++++++++++++++++++- drivers/firmware/qcom_scm.h | 8 +++ 3 files changed, 180 insertions(+), 8 deletions(-) diff --git a/drivers/firmware/qcom_scm-smc.c b/drivers/firmware/qcom_scm-smc.c index d111833364ba..726b9330155e 100644 --- a/drivers/firmware/qcom_scm-smc.c +++ b/drivers/firmware/qcom_scm-smc.c @@ -52,29 +52,98 @@ static void __scm_smc_do_quirk(const struct arm_smccc_args *smc, } while (res->a0 == QCOM_SCM_INTERRUPTED); } -static void __scm_smc_do(const struct arm_smccc_args *smc, - struct arm_smccc_res *res, bool atomic) +static void fill_wq_resume_args(struct arm_smccc_args *resume, u32 smc_call_ctx) { - int retry_count = 0; + memset(resume->args, 0, sizeof(resume->args[0]) * ARRAY_SIZE(resume->args)); + + resume->args[0] = ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, + ARM_SMCCC_SMC_64, ARM_SMCCC_OWNER_SIP, + SCM_SMC_FNID(QCOM_SCM_SVC_WAITQ, QCOM_SCM_WAITQ_RESUME)); + + resume->args[1] = QCOM_SCM_ARGS(1); + + resume->args[2] = smc_call_ctx; +} + +int scm_get_wq_ctx(u32 *wq_ctx, u32 *flags, u32 *more_pending) +{ + int ret; + struct arm_smccc_args get_wq_ctx = {0}; + struct arm_smccc_res get_wq_res; + + get_wq_ctx.args[0] = ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, + ARM_SMCCC_SMC_64, ARM_SMCCC_OWNER_SIP, + SCM_SMC_FNID(QCOM_SCM_SVC_WAITQ, QCOM_SCM_WAITQ_GET_WQ_CTX)); + + /* Guaranteed to return only success or error, no WAITQ_* */ + __scm_smc_do_quirk(&get_wq_ctx, &get_wq_res); + ret = get_wq_res.a0; + if (ret) + return ret; + + *wq_ctx = get_wq_res.a1; + *flags = get_wq_res.a2; + *more_pending = get_wq_res.a3; + + return 0; +} + +static int __scm_smc_do_quirk_handle_waitq(struct device *dev, struct arm_smccc_args *waitq, + struct arm_smccc_res *res) +{ + int ret; + struct arm_smccc_args resume; + u32 wq_ctx, smc_call_ctx, flags; + struct arm_smccc_args *smc = waitq; + + do { + __scm_smc_do_quirk(smc, res); + + if (res->a0 == QCOM_SCM_WAITQ_SLEEP) { + wq_ctx = res->a1; + smc_call_ctx = res->a2; + flags = res->a3; + + ret = qcom_scm_wait_for_wq_completion(wq_ctx); + if (ret) + return ret; + + fill_wq_resume_args(&resume, smc_call_ctx); + smc = &resume; + } + } while (res->a0 == QCOM_SCM_WAITQ_SLEEP); + + return 0; +} + +static int __scm_smc_do(struct device *dev, struct arm_smccc_args *smc, + struct arm_smccc_res *res, bool atomic) +{ + int ret, retry_count = 0; if (atomic) { __scm_smc_do_quirk(smc, res); - return; + return 0; } do { mutex_lock(&qcom_scm_lock); - __scm_smc_do_quirk(smc, res); + ret = __scm_smc_do_quirk_handle_waitq(dev, smc, res); mutex_unlock(&qcom_scm_lock); + if (ret) + return ret; + if (res->a0 == QCOM_SCM_V2_EBUSY) { if (retry_count++ > QCOM_SCM_EBUSY_MAX_RETRY) break; msleep(QCOM_SCM_EBUSY_WAIT_MS); } } while (res->a0 == QCOM_SCM_V2_EBUSY); + + return 0; } @@ -83,7 +152,7 @@ int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc, struct qcom_scm_res *res, bool atomic) { int arglen = desc->arginfo & 0xf; - int i; + int i, ret; dma_addr_t args_phys = 0; void *args_virt = NULL; size_t alloc_len; @@ -135,13 +204,17 @@ int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc, smc.args[SCM_SMC_LAST_REG_IDX] = args_phys; } - __scm_smc_do(&smc, &smc_res, atomic); + /* ret error check follows after args_virt cleanup*/ + ret = __scm_smc_do(dev, &smc, &smc_res, atomic); if (args_virt) { dma_unmap_single(dev, args_phys, alloc_len, DMA_TO_DEVICE); kfree(args_virt); } + if (ret) + return ret; + if (res) { res->result[0] = smc_res.a1; res->result[1] = smc_res.a2; diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index cdbfe54c8146..c7e48ecdbaf5 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -4,6 +4,8 @@ */ #include #include +#include +#include #include #include #include @@ -13,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +36,7 @@ struct qcom_scm { struct clk *iface_clk; struct clk *bus_clk; struct icc_path *path; + struct completion waitq_comp; struct reset_controller_dev reset; /* control access to the interconnect path */ @@ -63,6 +67,9 @@ static const u8 qcom_scm_cpu_warm_bits[QCOM_SCM_BOOT_MAX_CPUS] = { BIT(2), BIT(1), BIT(4), BIT(6) }; +#define QCOM_SMC_WAITQ_FLAG_WAKE_ONE BIT(0) +#define QCOM_SMC_WAITQ_FLAG_WAKE_ALL BIT(1) + static const char * const qcom_scm_convention_names[] = { [SMC_CONVENTION_UNKNOWN] = "unknown", [SMC_CONVENTION_ARM_32] = "smc arm 32", @@ -1325,11 +1332,82 @@ bool qcom_scm_is_available(void) } EXPORT_SYMBOL(qcom_scm_is_available); +static int qcom_scm_assert_valid_wq_ctx(u32 wq_ctx) +{ + /* FW currently only supports a single wq_ctx (zero). + * TODO: Update this logic to include dynamic allocation and lookup of + * completion structs when FW supports more wq_ctx values. + */ + if (wq_ctx != 0) { + dev_err(__scm->dev, "Firmware unexpectedly passed non-zero wq_ctx\n"); + return -EINVAL; + } + + return 0; +} + +int qcom_scm_wait_for_wq_completion(u32 wq_ctx) +{ + int ret; + + ret = qcom_scm_assert_valid_wq_ctx(wq_ctx); + if (ret) + return ret; + + wait_for_completion(&__scm->waitq_comp); + + return 0; +} + +static int qcom_scm_waitq_wakeup(struct qcom_scm *scm, unsigned int wq_ctx, bool wake_all) +{ + int ret; + + ret = qcom_scm_assert_valid_wq_ctx(wq_ctx); + if (ret) + return ret; + + if (wake_all) + complete_all(&__scm->waitq_comp); + else + complete(&__scm->waitq_comp); + + return 0; +} + +static irqreturn_t qcom_scm_irq_handler(int irq, void *data) +{ + int ret; + struct qcom_scm *scm = data; + u32 wq_ctx, flags, more_pending = 0; + + do { + ret = scm_get_wq_ctx(&wq_ctx, &flags, &more_pending); + if (ret) { + dev_err(scm->dev, "GET_WQ_CTX SMC call failed: %d\n", ret); + goto out; + } + + if (flags != QCOM_SMC_WAITQ_FLAG_WAKE_ONE && + flags != QCOM_SMC_WAITQ_FLAG_WAKE_ALL) { + dev_err(scm->dev, "Invalid flags found for wq_ctx: %u\n", flags); + goto out; + } + + ret = qcom_scm_waitq_wakeup(scm, wq_ctx, !!(flags & QCOM_SMC_WAITQ_FLAG_WAKE_ALL)); + if (ret) + goto out; + } while (more_pending); + +out: + return IRQ_HANDLED; +} + static int qcom_scm_probe(struct platform_device *pdev) { struct qcom_scm *scm; unsigned long clks; - int ret; + int irq, ret; scm = devm_kzalloc(&pdev->dev, sizeof(*scm), GFP_KERNEL); if (!scm) @@ -1402,6 +1480,19 @@ static int qcom_scm_probe(struct platform_device *pdev) __scm = scm; __scm->dev = &pdev->dev; + init_completion(&__scm->waitq_comp); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + if (irq != -ENXIO) + return irq; + } else { + ret = devm_request_threaded_irq(__scm->dev, irq, NULL, qcom_scm_irq_handler, + IRQF_ONESHOT, "qcom-scm", __scm); + if (ret < 0) + return dev_err_probe(scm->dev, ret, "Failed to request qcom-scm irq\n"); + } + __get_convention(); /* diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index db3d08a01209..e6e512bd57d1 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -60,6 +60,9 @@ struct qcom_scm_res { u64 result[MAX_QCOM_SCM_RETS]; }; +int qcom_scm_wait_for_wq_completion(u32 wq_ctx); +int scm_get_wq_ctx(u32 *wq_ctx, u32 *flags, u32 *more_pending); + #define SCM_SMC_FNID(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF)) extern int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc, enum qcom_scm_convention qcom_convention, @@ -129,6 +132,10 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc, #define QCOM_SCM_SMMU_CONFIG_ERRATA1 0x03 #define QCOM_SCM_SMMU_CONFIG_ERRATA1_CLIENT_ALL 0x02 +#define QCOM_SCM_SVC_WAITQ 0x24 +#define QCOM_SCM_WAITQ_RESUME 0x02 +#define QCOM_SCM_WAITQ_GET_WQ_CTX 0x03 + /* common error codes */ #define QCOM_SCM_V2_EBUSY -12 #define QCOM_SCM_ENOMEM -5 @@ -137,6 +144,7 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc, #define QCOM_SCM_EINVAL_ARG -2 #define QCOM_SCM_ERROR -1 #define QCOM_SCM_INTERRUPTED 1 +#define QCOM_SCM_WAITQ_SLEEP 2 static inline int qcom_scm_remap_error(int err) {