Received: by 2002:a25:8b91:0:0:0:0:0 with SMTP id j17csp3047233ybl; Fri, 20 Dec 2019 03:05:52 -0800 (PST) X-Google-Smtp-Source: APXvYqzZB+H5MmuZCjFnW1cjgrUeH03p86o8wnphF4f53wgusze1k0mufpll6FGoBqyToyMHN6k8 X-Received: by 2002:a9d:66ca:: with SMTP id t10mr14260030otm.352.1576839952619; Fri, 20 Dec 2019 03:05:52 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1576839952; cv=none; d=google.com; s=arc-20160816; b=uy6IlFQzE4zEbJnwKlxWc/IWtVRvVuPaX9L0Kq3+rtk1b7W2Kt0jLgoLge+CIwLDF0 OOO1iSRduFnyIfZ8s/X0SVXjh9telwqUqO7i88DysQ4Ots0e/fHPBFBQrRpd3+9WlvQ4 dWG/a5VPYU8jcgpn3IkmSiVwpGhW9R4SgliNnD5FIAICQ+NTRk4syonf7LkdEEFxxiUv yWdTPDw1vBIsmfKyBZIops+7cBR/RYG4mFWAfYkZOmIw89IZLrVmBdrXBKE5v+qsta0U i/vmOVx9KTnR5xrANlTwo+PsVJ32VLovJBQR2xhDF2/T0Gh+i9w8Ur1UCOZ6iqJ/L1Sv uvew== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding :content-language:in-reply-to:mime-version:user-agent:date :message-id:from:references:cc:to:subject:dkim-signature; bh=j6UQ3O/Hv+Kt21sxYVJUZOij1dDw57JSv0/4dcSA7KI=; b=qsfe8UgSy2MwRmVndR3aaJnbifEddvkGpe0wJLT1w70SSELX6nNAh/Tqs9wyI0pXM0 Q7etSAfsmK8tyzKrAUbASj1qdbifRPnkg3j5MRcNGuCdCTjvlHAjFXdz/3YAk14LdQ+V rG3IriizZjo5rn7YIeL3zpW6o4BhsKW8S9F6ABqpGseI3J5bsQ/pfeXqDTJWiMPHvFtx HSHSDlcnSjorRnYmPlRxl0y+YMW397rgHPPiP5UCfKHf8zp2W2Rx3K8itYXHAamii8t6 gxYgagEy1Xi2Aj3351skjtEt2jjx2lLDyLHSxO50uEBoXRuybrQo7PZUzVkbZHnDcnCr Quyw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=WzyyWbRc; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id h7si707844otk.86.2019.12.20.03.05.38; Fri, 20 Dec 2019 03:05:52 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@ti.com header.s=ti-com-17Q1 header.b=WzyyWbRc; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=NONE dis=NONE) header.from=ti.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727269AbfLTLEk (ORCPT + 99 others); Fri, 20 Dec 2019 06:04:40 -0500 Received: from lelv0142.ext.ti.com ([198.47.23.249]:53166 "EHLO lelv0142.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727177AbfLTLEj (ORCPT ); Fri, 20 Dec 2019 06:04:39 -0500 Received: from fllv0034.itg.ti.com ([10.64.40.246]) by lelv0142.ext.ti.com (8.15.2/8.15.2) with ESMTP id xBKB4bjr068540; Fri, 20 Dec 2019 05:04:37 -0600 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ti.com; s=ti-com-17Q1; t=1576839877; bh=j6UQ3O/Hv+Kt21sxYVJUZOij1dDw57JSv0/4dcSA7KI=; h=Subject:To:CC:References:From:Date:In-Reply-To; b=WzyyWbRcR3bT/iXwGMdheMqCjKAJEmaVAk0NwacJCRA6eWN94u0sOSvmI8HsTBhNF 92slqPea8ovxTqP3Pz/Je43sq2Rkbjgbo5uIXQ+tLNilpbPHScsg2x2fm2aGSCd/9l nB9CrhiLOy6HByQk197eqA0pEAGJbIseRaLVk/ks= Received: from DFLE115.ent.ti.com (dfle115.ent.ti.com [10.64.6.36]) by fllv0034.itg.ti.com (8.15.2/8.15.2) with ESMTPS id xBKB4b0u005961 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 20 Dec 2019 05:04:37 -0600 Received: from DFLE114.ent.ti.com (10.64.6.35) by DFLE115.ent.ti.com (10.64.6.36) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1847.3; Fri, 20 Dec 2019 05:04:35 -0600 Received: from lelv0326.itg.ti.com (10.180.67.84) by DFLE114.ent.ti.com (10.64.6.35) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.1.1847.3 via Frontend Transport; Fri, 20 Dec 2019 05:04:35 -0600 Received: from [127.0.0.1] (ileax41-snat.itg.ti.com [10.172.224.153]) by lelv0326.itg.ti.com (8.15.2/8.15.2) with ESMTP id xBKB4XsK032367; Fri, 20 Dec 2019 05:04:33 -0600 Subject: Re: [PATCHv3 12/15] remoteproc/omap: add support for system suspend/resume To: Suman Anna , Mathieu Poirier CC: , , , , References: <20191213125537.11509-1-t-kristo@ti.com> <20191213125537.11509-13-t-kristo@ti.com> <20191219214603.GA32574@xps15> From: Tero Kristo Message-ID: <313f37c3-e3fb-aae6-d0fa-8a3de90b7b2e@ti.com> Date: Fri, 20 Dec 2019 13:04:32 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.2.2 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset="utf-8"; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit X-EXCLAIMER-MD-CONFIG: e1e8a2fd-e40a-4ac6-ac9b-f7e9cc9ee180 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 20/12/2019 05:11, Suman Anna wrote: > Hi Mathieu, Tero, > > On 12/19/19 3:46 PM, Mathieu Poirier wrote: >> On Fri, Dec 13, 2019 at 02:55:34PM +0200, Tero Kristo wrote: >>> From: Suman Anna >>> >>> This patch adds the support for system suspend/resume to the >>> OMAP remoteproc driver so that the OMAP remoteproc devices can >>> be suspended/resumed during a system suspend/resume. The support >>> is added through the driver PM .suspend/.resume callbacks, and >>> requires appropriate support from the OS running on the remote >>> processors. >>> >>> The IPU & DSP remote processors typically have their own private >>> modules like registers, internal memories, caches etc. The context >>> of these modules need to be saved and restored properly for a >>> suspend/resume to work. These are in general not accessible from >>> the MPU, so the remote processors themselves have to implement >>> the logic for the context save & restore of these modules. >>> >>> The OMAP remoteproc driver initiates a suspend by sending a mailbox >>> message requesting the remote processor to save its context and >>> enter into an idle/standby state. The remote processor should >>> usually stop whatever processing it is doing to switch to a context >>> save mode. The OMAP remoteproc driver detects the completion of >>> the context save by checking the module standby status for the >>> remoteproc device. It also stops any resources used by the remote >>> processors like the timers. The timers need to be running only >>> when the processor is active and executing, and need to be stopped >>> otherwise to allow the timer driver to reach low-power states. The >>> IOMMUs are automatically suspended by the PM core during the late >>> suspend stage, after the remoteproc suspend process is completed by >>> putting the remote processor cores into reset. Thereafter, the Linux >>> kernel can put the domain into further lower power states as possible. >>> >>> The resume sequence undoes the operations performed in the PM suspend >>> callback, by starting the timers and finally releasing the processors >>> from reset. This requires that the remote processor side OS be able to >>> distinguish a power-resume boot from a power-on/cold boot, restore the >>> context of its private modules saved during the suspend phase, and >>> resume executing code from where it was suspended. The IOMMUs would >>> have been resumed by the PM core during early resume, so they are >>> already enabled by the time remoteproc resume callback gets invoked. >>> >>> The remote processors should save their context into System RAM (DDR), >>> as any internal memories are not guaranteed to retain context as it >>> depends on the lowest power domain that the remote processor device >>> is put into. The management of the DDR contents will be managed by >>> the Linux kernel. >>> >>> Signed-off-by: Suman Anna >>> [t-kristo@ti.com: converted to use ti-sysc instead of hwmod] >>> Signed-off-by: Tero Kristo >>> --- >>> drivers/remoteproc/omap_remoteproc.c | 179 +++++++++++++++++++++++++++ >>> drivers/remoteproc/omap_remoteproc.h | 18 ++- >>> 2 files changed, 195 insertions(+), 2 deletions(-) >>> >>> diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c >>> index 9c750c2ab29d..0a9b9f7d20da 100644 >>> --- a/drivers/remoteproc/omap_remoteproc.c >>> +++ b/drivers/remoteproc/omap_remoteproc.c >>> @@ -16,6 +16,7 @@ >>> #include >>> #include >>> #include >>> +#include >>> #include >>> #include >>> #include >>> @@ -23,10 +24,13 @@ >>> #include >>> #include >>> #include >>> +#include >> >> Please move this up by one line. >> >>> #include >>> #include >>> #include >>> #include >>> +#include >>> +#include >> >> Unless there is a dependency with timer-ti-dm.h, these should go just above linux/err.h > > No depencencies, can be reordered. Will fix these. > >> >>> >>> #include >>> >>> @@ -81,6 +85,9 @@ struct omap_rproc_timer { >>> * @timers: timer(s) info used by rproc >>> * @rproc: rproc handle >>> * @reset: reset handle >>> + * @pm_comp: completion primitive to sync for suspend response >>> + * @fck: functional clock for the remoteproc >>> + * @suspend_acked: state machine flag to store the suspend request ack >>> */ >>> struct omap_rproc { >>> struct mbox_chan *mbox; >>> @@ -92,6 +99,9 @@ struct omap_rproc { >>> struct omap_rproc_timer *timers; >>> struct rproc *rproc; >>> struct reset_control *reset; >>> + struct completion pm_comp; >>> + struct clk *fck; >>> + bool suspend_acked; >>> }; >>> >>> /** >>> @@ -349,6 +359,11 @@ static void omap_rproc_mbox_callback(struct mbox_client *client, void *data) >>> case RP_MBOX_ECHO_REPLY: >>> dev_info(dev, "received echo reply from %s\n", name); >>> break; >>> + case RP_MBOX_SUSPEND_ACK: >> >> We can't get away with implicit fallthroughs anymore - please add /* Fall through */" Ok, will do. >> >>> + case RP_MBOX_SUSPEND_CANCEL: >>> + oproc->suspend_acked = msg == RP_MBOX_SUSPEND_ACK; >>> + complete(&oproc->pm_comp); >>> + break; >>> default: >>> if (msg >= RP_MBOX_READY && msg < RP_MBOX_END_MSG) >>> return; >>> @@ -529,6 +544,157 @@ static const struct rproc_ops omap_rproc_ops = { >>> .da_to_va = omap_rproc_da_to_va, >>> }; >>> >>> +#ifdef CONFIG_PM >>> +static bool _is_rproc_in_standby(struct omap_rproc *oproc) >>> +{ >>> + return ti_clk_is_in_standby(oproc->fck); >>> +} >>> + >>> +/* 1 sec is long enough time to let the remoteproc side suspend the device */ >>> +#define DEF_SUSPEND_TIMEOUT 1000 >>> +static int _omap_rproc_suspend(struct rproc *rproc) >>> +{ >>> + struct device *dev = rproc->dev.parent; >>> + struct omap_rproc *oproc = rproc->priv; >>> + unsigned long to = msecs_to_jiffies(DEF_SUSPEND_TIMEOUT); >>> + unsigned long ta = jiffies + to; >>> + int ret; >>> + >>> + reinit_completion(&oproc->pm_comp); >>> + oproc->suspend_acked = false; >>> + ret = mbox_send_message(oproc->mbox, (void *)RP_MBOX_SUSPEND_SYSTEM); >>> + if (ret < 0) { >>> + dev_err(dev, "PM mbox_send_message failed: %d\n", ret); >>> + return ret; >>> + } >>> + >>> + ret = wait_for_completion_timeout(&oproc->pm_comp, to); >>> + if (!oproc->suspend_acked) >>> + return -EBUSY; >>> + >>> + /* >>> + * The remoteproc side is returning the ACK message before saving the >>> + * context, because the context saving is performed within a SYS/BIOS >>> + * function, and it cannot have any inter-dependencies against the IPC >>> + * layer. Also, as the SYS/BIOS needs to preserve properly the processor >>> + * register set, sending this ACK or signalling the completion of the >>> + * context save through a shared memory variable can never be the >>> + * absolute last thing to be executed on the remoteproc side, and the >>> + * MPU cannot use the ACK message as a sync point to put the remoteproc >>> + * into reset. The only way to ensure that the remote processor has >>> + * completed saving the context is to check that the module has reached >>> + * STANDBY state (after saving the context, the SYS/BIOS executes the >>> + * appropriate target-specific WFI instruction causing the module to >>> + * enter STANDBY). >>> + */ >>> + while (!_is_rproc_in_standby(oproc)) { >>> + if (time_after(jiffies, ta)) >>> + return -ETIME; >>> + schedule(); >>> + } >>> + >>> + reset_control_assert(oproc->reset); >>> + >>> + ret = omap_rproc_disable_timers(rproc, false); >>> + if (ret) { >>> + dev_err(dev, "disabling timers during suspend failed %d\n", >>> + ret); >>> + goto enable_device; >>> + } >>> + >>> + return 0; >>> + >>> +enable_device: >>> + reset_control_deassert(oproc->reset); >>> + return ret; >>> +} >>> + >>> +static int _omap_rproc_resume(struct rproc *rproc) >>> +{ >>> + struct device *dev = rproc->dev.parent; >>> + struct omap_rproc *oproc = rproc->priv; >>> + int ret; >>> + >>> + /* boot address could be lost after suspend, so restore it */ >>> + if (oproc->boot_data) { >>> + ret = omap_rproc_write_dsp_boot_addr(rproc); >>> + if (ret) { >>> + dev_err(dev, "boot address restore failed %d\n", ret); >>> + goto out; >>> + } >>> + } >>> + >>> + ret = omap_rproc_enable_timers(rproc, false); >>> + if (ret) { >>> + dev_err(dev, "enabling timers during resume failed %d\n", >>> + ret); >> >> The "ret);" fits on the live above. Ok, will fix. >> >>> + goto out; >>> + } >>> + >>> + reset_control_deassert(oproc->reset); >>> + >>> +out: >>> + return ret; >>> +} >>> + >>> +static int __maybe_unused omap_rproc_suspend(struct device *dev) >> >> The "__maybe_unused" can be dropped because this is within the #ifdef CONFIG_PM >> block. > > These are suspend/resume callbacks, so are actually controlled by > CONFIG_PM_SLEEP which can be disabled independently from runtime > suspend, and hence the annotation. I'll add these two behind CONFIG_PM_SLEEP, in addition to the whole lot being behind CONFIG_PM. > >> >>> +{ >>> + struct platform_device *pdev = to_platform_device(dev); >>> + struct rproc *rproc = platform_get_drvdata(pdev); >>> + int ret = 0; >>> + >>> + mutex_lock(&rproc->lock); >>> + if (rproc->state == RPROC_OFFLINE) >>> + goto out; >>> + >>> + if (rproc->state == RPROC_SUSPENDED) >>> + goto out; >>> + >>> + if (rproc->state != RPROC_RUNNING) { >>> + ret = -EBUSY; >>> + goto out; >>> + } >>> + >>> + ret = _omap_rproc_suspend(rproc); >>> + if (ret) { >>> + dev_err(dev, "suspend failed %d\n", ret); >>> + goto out; >>> + } >>> + >>> + rproc->state = RPROC_SUSPENDED; >>> +out: >>> + mutex_unlock(&rproc->lock); >>> + return ret; >>> +} >>> + >>> +static int __maybe_unused omap_rproc_resume(struct device *dev) >> >> Same comment as above. >> >>> +{ >>> + struct platform_device *pdev = to_platform_device(dev); >>> + struct rproc *rproc = platform_get_drvdata(pdev); >>> + int ret = 0; >>> + >>> + mutex_lock(&rproc->lock); >>> + if (rproc->state == RPROC_OFFLINE) >>> + goto out; >>> + >>> + if (rproc->state != RPROC_SUSPENDED) { >>> + ret = -EBUSY; >>> + goto out; >>> + } >>> + >>> + ret = _omap_rproc_resume(rproc); >>> + if (ret) { >>> + dev_err(dev, "resume failed %d\n", ret); >>> + goto out; >>> + } >>> + >>> + rproc->state = RPROC_RUNNING; >>> +out: >>> + mutex_unlock(&rproc->lock); >>> + return ret; >>> +} >>> +#endif /* CONFIG_PM */ >>> + >>> static const char * const ipu_mem_names[] = { >>> "l2ram", NULL >>> }; >>> @@ -786,6 +952,14 @@ static int omap_rproc_probe(struct platform_device *pdev) >>> oproc->num_timers); >>> } >>> >>> + init_completion(&oproc->pm_comp); >>> + >>> + oproc->fck = devm_clk_get(&pdev->dev, 0); >>> + if (IS_ERR(oproc->fck)) { >>> + ret = PTR_ERR(oproc->fck); >>> + goto free_rproc; >>> + } >>> + >> >> oproc->fck is not released if an error occurs in of_reserved_mem_device_init() >> and rproc_add(). > > We are using a devres managed API, so why do we need to release it > specifically? Yea I don't think this is needed. > >> >>> ret = of_reserved_mem_device_init(&pdev->dev); >>> if (ret) { >>> dev_err(&pdev->dev, "device does not have specific CMA pool\n"); >>> @@ -818,11 +992,16 @@ static int omap_rproc_remove(struct platform_device *pdev) >>> return 0; >>> } >>> >>> +static const struct dev_pm_ops omap_rproc_pm_ops = { >>> + SET_SYSTEM_SLEEP_PM_OPS(omap_rproc_suspend, omap_rproc_resume) >>> +}; >>> + >>> static struct platform_driver omap_rproc_driver = { >>> .probe = omap_rproc_probe, >>> .remove = omap_rproc_remove, >>> .driver = { >>> .name = "omap-rproc", >>> + .pm = &omap_rproc_pm_ops, >>> .of_match_table = omap_rproc_of_match, >>> }, >>> }; >>> diff --git a/drivers/remoteproc/omap_remoteproc.h b/drivers/remoteproc/omap_remoteproc.h >>> index 72f656c93caa..c73383e707c7 100644 >>> --- a/drivers/remoteproc/omap_remoteproc.h >>> +++ b/drivers/remoteproc/omap_remoteproc.h >>> @@ -1,7 +1,7 @@ >>> /* >>> * Remote processor messaging >>> * >>> - * Copyright (C) 2011 Texas Instruments, Inc. >>> + * Copyright (C) 2011-2018 Texas Instruments, Inc. > > %s/2018/2019/ Yep, will fix. -Tero > > regards > Suman > >>> * Copyright (C) 2011 Google, Inc. >>> * All rights reserved. >>> * >>> @@ -57,6 +57,16 @@ >>> * @RP_MBOX_ABORT_REQUEST: a "please crash" request, used for testing the >>> * recovery mechanism (to some extent). >>> * >>> + * @RP_MBOX_SUSPEND_AUTO: auto suspend request for the remote processor >>> + * >>> + * @RP_MBOX_SUSPEND_SYSTEM: system suspend request for the remote processor >>> + * >>> + * @RP_MBOX_SUSPEND_ACK: successful response from remote processor for a >>> + * suspend request >>> + * >>> + * @RP_MBOX_SUSPEND_CANCEL: a cancel suspend response from a remote processor >>> + * on a suspend request >>> + * >>> * Introduce new message definitions if any here. >>> * >>> * @RP_MBOX_END_MSG: Indicates end of known/defined messages from remote core >>> @@ -70,7 +80,11 @@ enum omap_rp_mbox_messages { >>> RP_MBOX_ECHO_REQUEST = 0xFFFFFF03, >>> RP_MBOX_ECHO_REPLY = 0xFFFFFF04, >>> RP_MBOX_ABORT_REQUEST = 0xFFFFFF05, >>> - RP_MBOX_END_MSG = 0xFFFFFF06, >>> + RP_MBOX_SUSPEND_AUTO = 0xFFFFFF10, >>> + RP_MBOX_SUSPEND_SYSTEM = 0xFFFFFF11, >>> + RP_MBOX_SUSPEND_ACK = 0xFFFFFF12, >>> + RP_MBOX_SUSPEND_CANCEL = 0xFFFFFF13, >>> + RP_MBOX_END_MSG = 0xFFFFFF14, >>> }; >>> >>> #endif /* _OMAP_RPMSG_H */ >>> -- >>> 2.17.1 >>> >>> -- > -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki