From patchwork Wed Nov 14 20:22:50 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Russ Dill X-Patchwork-Id: 1743741 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id C1E883FCF7 for ; Wed, 14 Nov 2012 20:25:23 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TYjUK-0008IZ-9L; Wed, 14 Nov 2012 20:23:08 +0000 Received: from mail-pa0-f49.google.com ([209.85.220.49]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1TYjUG-0008Hu-Cu for linux-arm-kernel@lists.infradead.org; Wed, 14 Nov 2012 20:23:06 +0000 Received: by mail-pa0-f49.google.com with SMTP id bi5so519742pad.36 for ; Wed, 14 Nov 2012 12:22:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:x-mailer; bh=Gj6paXrqQjBFWuH+ykZPi/+Fd1Y0UTWCdY/mJB09lCA=; b=yYa2U3PwNLlqUdp1BtYdnNngyzCEOq7meLCqcUeNXADnFJgJQBalzytLwcmrxrVKkg l2mGuBqFmwnvCeJOfVKbRvtEnGQBojMsCSA4Ku7K5SDblkAxkT1oxBXLDuQtnjdHGgvU vF/luc38hoazA29NaWlMTAheVY2MoWMw9KQ4SyXYmcdcP4ISPVv/WCJrKHRWlCcxCpXp HIeP1MM6yeE1aoUU4f44mvpuPCkobVzJ5M4qyL3oQWVGYIfrdhCiO/cDHB6vK0fBNmNK QX+muFecnD/Q4RC3E0Ec7wjiuxXcpSiiHjwn0A6G6U3ZtMxycqdUGFjmaxc224MdPse8 bGmA== Received: by 10.68.245.167 with SMTP id xp7mr82772584pbc.75.1352924579676; Wed, 14 Nov 2012 12:22:59 -0800 (PST) Received: from localhost (pool-74-100-57-85.lsanca.fios.verizon.net. [74.100.57.85]) by mx.google.com with ESMTPS id ni8sm8210500pbc.70.2012.11.14.12.22.57 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 14 Nov 2012 12:22:58 -0800 (PST) From: Russ Dill To: linux-arm-kernel@lists.infradead.org, tuxonice-devel@tuxonice.net, linux-pm@lists.linux-foundation.org, linux-omap@vger.kernel.org Subject: [RFC PATCH v7] ARM hibernation / suspend-to-disk Date: Wed, 14 Nov 2012 12:22:50 -0800 Message-Id: <1352924570-17194-1-git-send-email-Russ.Dill@ti.com> X-Mailer: git-send-email 1.8.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20121114_152304_665004_E65C4BA8 X-CRM114-Status: GOOD ( 22.83 ) X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.220.49 listed in list.dnswl.org] 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (russ.dill[at]gmail.com) -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: Russ Dill X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org This is a rebase/rework of Frank Hofmann's work, the most recent patchset being here: http://lists.infradead.org/pipermail/linux-arm-kernel/2011-June/053229.html The biggest gotcha right now: If there's any cpu-specific / SoC-specific state that needs (re)init over a suspend-to-disk/resume-from-disk cycle, this patch is incomplete because it provides no hooks/code for that. This is the case e.g. for "secure" SoCs that have different sets of control registers and/or different CR reg access patterns. It's also the case e.g. for SoCs with L2 caches as the activation sequence there is SoC-dependent; a full off-on cycle for L2 is not done by the hibernation support code. It's also the case if the SoC requires steps on wakeup _before_ the "generic" parts done by cpu_suspend / cpu_resume can work correctly. (OMAP is an example of such a SoC; the patch "works" on OMAP in the sense that it gets you a non-secure OMAP back from hibernation but as mentioned, your mileage may vary; I for example don't know what the consequences of not disabling / reenabling the L2 cache over cpu_reset are) I've only tested on Beagleboard xM, and it gets stuck trying to program some GPIOs since the interface clock isn't enabled. However, things generally look good. The work is built on Linux-3.7.0-rc5-00014-g9924a19. Signed-off-by: Russ Dill --- arch/arm/include/asm/memory.h | 1 + arch/arm/kernel/Makefile | 1 + arch/arm/kernel/hibernate.c | 117 ++++++++++++++++++++++++++++++++++++++++++ arch/arm/mm/Kconfig | 5 ++ 4 files changed, 124 insertions(+) create mode 100644 arch/arm/kernel/hibernate.c diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index 73cf03a..8376a39 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -230,6 +230,7 @@ static inline void *phys_to_virt(phys_addr_t x) */ #define __pa(x) __virt_to_phys((unsigned long)(x)) #define __va(x) ((void *)__phys_to_virt((unsigned long)(x))) +#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x),0)) #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) /* diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 5bbec7b..2971988 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_ARTHUR) += arthur.o obj-$(CONFIG_ISA_DMA) += dma-isa.o obj-$(CONFIG_PCI) += bios32.o isa.o obj-$(CONFIG_ARM_CPU_SUSPEND) += sleep.o suspend.o +obj-$(CONFIG_HIBERNATION) += hibernate.o obj-$(CONFIG_SMP) += smp.o smp_tlb.o obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o diff --git a/arch/arm/kernel/hibernate.c b/arch/arm/kernel/hibernate.c new file mode 100644 index 0000000..0b72e17 --- /dev/null +++ b/arch/arm/kernel/hibernate.c @@ -0,0 +1,117 @@ +/* + * Hibernation support specific for ARM + * + * Derived from work on ARM hibernation support by: + * + * Ubuntu project, hibernation support for mach-dove + * Copyright (C) 2010 Nokia Corporation (Hiroshi Doyu) + * Copyright (C) 2010 Texas Instruments, Inc. (Teerth Reddy et al.) + * https://lkml.org/lkml/2010/6/18/4 + * https://lists.linux-foundation.org/pipermail/linux-pm/2010-June/027422.html + * https://patchwork.kernel.org/patch/96442/ + * + * Copyright (C) 2006 Rafael J. Wysocki + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include +#include +#include + +extern const void __nosave_begin, __nosave_end; +extern void cpu_resume(void); + +int pfn_is_nosave(unsigned long pfn) +{ + unsigned long nosave_begin_pfn = + __pa_symbol(&__nosave_begin) >> PAGE_SHIFT; + unsigned long nosave_end_pfn = + PAGE_ALIGN(__pa_symbol(&__nosave_end)) >> PAGE_SHIFT; + + return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn); +} + +void notrace save_processor_state(void) +{ + WARN_ON(num_online_cpus() != 1); + flush_thread(); + local_fiq_disable(); +} + +void notrace restore_processor_state(void) +{ + local_fiq_enable(); +} + +/* + * Snapshot kernel memory and reset the system. + * After resume, the hibernation snapshot is written out. + */ +static int notrace __swsusp_arch_save_image(unsigned long unused) +{ + extern int swsusp_save(void); + int ret; + + ret = swsusp_save(); + if (ret == 0) + soft_restart(virt_to_phys(cpu_resume)); + return ret; +} + +/* + * Save the current CPU state before suspend / poweroff. + */ +int notrace swsusp_arch_suspend(void) +{ + return cpu_suspend(0, __swsusp_arch_save_image); +} + +/* + * The framework loads the hibernation image into a linked list anchored + * at restore_pblist, for swsusp_arch_resume() to copy back to the proper + * destinations. + * + * To make this work if resume is triggered from initramfs, the + * pagetables need to be switched to allow writes to kernel mem. + */ +static void notrace __swsusp_arch_restore_image(void *unused) +{ + extern struct pbe *restore_pblist; + phys_reset_t phys_reset; + struct pbe *pbe; + + cpu_switch_mm(idmap_pgd, &init_mm); + + for (pbe = restore_pblist; pbe; pbe = pbe->next) + copy_page(pbe->orig_address, pbe->address); + + cpu_proc_fin(); + flush_cache_all(); + + phys_reset = (phys_reset_t)(unsigned long)virt_to_phys(cpu_reset); + + /* Return from cpu_suspend/swsusp_arch_suspend */ + phys_reset((unsigned long)virt_to_phys(cpu_resume)); +} + +static u8 __swsusp_resume_stk[PAGE_SIZE/2] __nosavedata; + +/* + * Resume from the hibernation image. + * Due to the kernel heap / data restore, stack contents change underneath + * and that would make function calls impossible; switch to a temporary + * stack within the nosave region to avoid that problem. + */ +int __naked swsusp_arch_resume(void) +{ + extern void call_with_stack(void (*fn)(void *), void *arg, void *sp); + cpu_init(); /* get a clean PSR */ + call_with_stack(__swsusp_arch_restore_image, 0, + __swsusp_resume_stk + sizeof(__swsusp_resume_stk)); + return 0; +} diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 94186b6..e3bd891 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -583,6 +583,11 @@ config CPU_USE_DOMAINS config IO_36 bool +config ARCH_HIBERNATION_POSSIBLE + bool + depends on MMU + default y if CPU_ARM920T || CPU_ARM926T || CPU_SA1100 || CPU_XSCALE || CPU_XSC3 || CPU_V6 || CPU_V6K || CPU_V7 + comment "Processor Features" config ARM_LPAE