Re: [PATCH v5 3/5] powerpc/85xx: add sleep and deep sleep support
On Mon, Jun 04, 2012 at 05:58:38PM -0500, Scott Wood wrote: On 06/04/2012 06:12 AM, Zhao Chenhui wrote: On Fri, Jun 01, 2012 at 04:54:35PM -0500, Scott Wood wrote: On 05/11/2012 06:53 AM, Zhao Chenhui wrote: diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h index 94ec20a..baa000c 100644 --- a/arch/powerpc/include/asm/cacheflush.h +++ b/arch/powerpc/include/asm/cacheflush.h @@ -33,6 +33,11 @@ extern void flush_dcache_page(struct page *page); #if defined(CONFIG_FSL_BOOKE) || defined(CONFIG_6xx) extern void __flush_disable_L1(void); #endif +#if defined(CONFIG_FSL_BOOKE) +extern void flush_dcache_L1(void); +#else +#define flush_dcache_L1()do { } while (0) +#endif It doesn't seem right to no-op this on other platforms. The pmc_suspend_enter() in fsl_pmc.c used by mpc85xx and mpc86xx, but flush_dcache_L1() have no definition in mpc86xx platform. I will write flush_dcache_L1() for mpc86xx platform. How about only calling the function when it's needed? If we didn't need an L1 flush here on 86xx before, why do we need it now? How about using CONFIG_PPC_85xx to gard it, like this. case PM_SUSPEND_STANDBY: local_irq_disable(); #ifdef CONFIG_PPC_85xx flush_dcache_L1(); #endif setbits32(pmc_regs-powmgtcsr, POWMGTCSR_SLP); extern void __flush_icache_range(unsigned long, unsigned long); static inline void flush_icache_range(unsigned long start, unsigned long stop) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index f5808a3..cb70dba 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -64,6 +64,9 @@ obj-$(CONFIG_FA_DUMP) += fadump.o ifeq ($(CONFIG_PPC32),y) obj-$(CONFIG_E500) += idle_e500.o endif +ifneq ($(CONFIG_PPC_E500MC),y) +obj-$(CONFIG_PPC_85xx) += l2cache_85xx.o +endif Can we introduce a symbol that specifically means pre-e500mc e500, rather than using negative logic? I think something like CONFIG_PPC_E500_V1_V2 has been proposed before. Agree. But CONFIG_PPC_E500_V1_V2 haven't been merged. Has the concept been NACKed, or just forgotten? If the latter, you could include it in this patchset. -Scott In patchwork, it's state is Superseded. http://patchwork.ozlabs.org/patch/124284/ -Chenhui ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH v5 3/5] powerpc/85xx: add sleep and deep sleep support
On 06/05/2012 06:35 AM, Zhao Chenhui wrote: On Mon, Jun 04, 2012 at 05:58:38PM -0500, Scott Wood wrote: On 06/04/2012 06:12 AM, Zhao Chenhui wrote: On Fri, Jun 01, 2012 at 04:54:35PM -0500, Scott Wood wrote: On 05/11/2012 06:53 AM, Zhao Chenhui wrote: diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h index 94ec20a..baa000c 100644 --- a/arch/powerpc/include/asm/cacheflush.h +++ b/arch/powerpc/include/asm/cacheflush.h @@ -33,6 +33,11 @@ extern void flush_dcache_page(struct page *page); #if defined(CONFIG_FSL_BOOKE) || defined(CONFIG_6xx) extern void __flush_disable_L1(void); #endif +#if defined(CONFIG_FSL_BOOKE) +extern void flush_dcache_L1(void); +#else +#define flush_dcache_L1()do { } while (0) +#endif It doesn't seem right to no-op this on other platforms. The pmc_suspend_enter() in fsl_pmc.c used by mpc85xx and mpc86xx, but flush_dcache_L1() have no definition in mpc86xx platform. I will write flush_dcache_L1() for mpc86xx platform. How about only calling the function when it's needed? If we didn't need an L1 flush here on 86xx before, why do we need it now? How about using CONFIG_PPC_85xx to gard it, like this. case PM_SUSPEND_STANDBY: local_irq_disable(); #ifdef CONFIG_PPC_85xx flush_dcache_L1(); #endif setbits32(pmc_regs-powmgtcsr, POWMGTCSR_SLP); We don't support building 85xx/86xx in the same kernel and likely never will, so this is OK. Can we introduce a symbol that specifically means pre-e500mc e500, rather than using negative logic? I think something like CONFIG_PPC_E500_V1_V2 has been proposed before. Agree. But CONFIG_PPC_E500_V1_V2 haven't been merged. Has the concept been NACKed, or just forgotten? If the latter, you could include it in this patchset. -Scott In patchwork, it's state is Superseded. http://patchwork.ozlabs.org/patch/124284/ I still think there's value in adding such a symbol. -Scott ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH v5 3/5] powerpc/85xx: add sleep and deep sleep support
On Fri, Jun 01, 2012 at 04:54:35PM -0500, Scott Wood wrote: On 05/11/2012 06:53 AM, Zhao Chenhui wrote: From: Li Yang le...@freescale.com In sleep PM mode, the clocks of e500 core and unused IP blocks is turned off. IP blocks which are allowed to wake up the processor are still running. Some Freescale chips like MPC8536 and P1022 has deep sleep PM mode in addtion to the sleep PM mode. While in deep sleep PM mode, additionally, the power supply is removed from e500 core and most IP blocks. Only the blocks needed to wake up the chip out of deep sleep are ON. This patch supports 32-bit and 36-bit address space. The sleep mode is equal to the Standby state in Linux. The deep sleep mode is equal to the Suspend-to-RAM state of Linux Power Management. Command to enter sleep mode. echo standby /sys/power/state Command to enter deep sleep mode. echo mem /sys/power/state Signed-off-by: Dave Liu dave...@freescale.com Signed-off-by: Li Yang le...@freescale.com Signed-off-by: Jin Qing b24...@freescale.com Signed-off-by: Jerry Huang chang-ming.hu...@freescale.com Cc: Scott Wood scottw...@freescale.com Signed-off-by: Zhao Chenhui chenhui.z...@freescale.com --- Changes for v5: * Rename flush_disable_L1 to __flush_disable_L1. arch/powerpc/Kconfig |2 +- arch/powerpc/include/asm/cacheflush.h |5 + arch/powerpc/kernel/Makefile |3 + arch/powerpc/kernel/l2cache_85xx.S| 53 +++ arch/powerpc/platforms/85xx/Makefile |3 + arch/powerpc/platforms/85xx/sleep.S | 609 + arch/powerpc/sysdev/fsl_pmc.c | 91 - arch/powerpc/sysdev/fsl_soc.h |5 + 8 files changed, 752 insertions(+), 19 deletions(-) create mode 100644 arch/powerpc/kernel/l2cache_85xx.S create mode 100644 arch/powerpc/platforms/85xx/sleep.S diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h index 94ec20a..baa000c 100644 --- a/arch/powerpc/include/asm/cacheflush.h +++ b/arch/powerpc/include/asm/cacheflush.h @@ -33,6 +33,11 @@ extern void flush_dcache_page(struct page *page); #if defined(CONFIG_FSL_BOOKE) || defined(CONFIG_6xx) extern void __flush_disable_L1(void); #endif +#if defined(CONFIG_FSL_BOOKE) +extern void flush_dcache_L1(void); +#else +#define flush_dcache_L1() do { } while (0) +#endif It doesn't seem right to no-op this on other platforms. The pmc_suspend_enter() in fsl_pmc.c used by mpc85xx and mpc86xx, but flush_dcache_L1() have no definition in mpc86xx platform. I will write flush_dcache_L1() for mpc86xx platform. extern void __flush_icache_range(unsigned long, unsigned long); static inline void flush_icache_range(unsigned long start, unsigned long stop) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index f5808a3..cb70dba 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -64,6 +64,9 @@ obj-$(CONFIG_FA_DUMP) += fadump.o ifeq ($(CONFIG_PPC32),y) obj-$(CONFIG_E500) += idle_e500.o endif +ifneq ($(CONFIG_PPC_E500MC),y) +obj-$(CONFIG_PPC_85xx) += l2cache_85xx.o +endif Can we introduce a symbol that specifically means pre-e500mc e500, rather than using negative logic? I think something like CONFIG_PPC_E500_V1_V2 has been proposed before. Agree. But CONFIG_PPC_E500_V1_V2 haven't been merged. -static int pmc_probe(struct platform_device *ofdev) +static int pmc_probe(struct platform_device *pdev) { - pmc_regs = of_iomap(ofdev-dev.of_node, 0); + struct device_node *np = pdev-dev.of_node; + + pmc_regs = of_iomap(np, 0); if (!pmc_regs) return -ENOMEM; - pmc_dev = ofdev-dev; + pmc_flag = PMC_SLEEP; + if (of_device_is_compatible(np, fsl,mpc8536-pmc)) + pmc_flag |= PMC_DEEP_SLEEP; + + if (of_device_is_compatible(np, fsl,p1022-pmc)) + pmc_flag |= PMC_DEEP_SLEEP; + suspend_set_ops(pmc_suspend_ops); + + pr_info(Freescale PMC driver\n); If you're going to be noisy on probe, at least provide some useful info like whether deep sleep or jog are supported. return 0; } diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h index c6d0073..949377d 100644 --- a/arch/powerpc/sysdev/fsl_soc.h +++ b/arch/powerpc/sysdev/fsl_soc.h @@ -48,5 +48,10 @@ extern struct platform_diu_data_ops diu_ops; void fsl_hv_restart(char *cmd); void fsl_hv_halt(void); +/* + * Cast the ccsrbar to 64-bit parameter so that the assembly + * code can be compatible with both 32-bit 36-bit. + */ +extern void mpc85xx_enter_deep_sleep(u64 ccsrbar, u32 powmgtreq); s/Cast the ccsrbar to 64-bit parameter/ccsrbar is u64 rather than phys_addr_t/ -Scott OK. Thanks. -Chenhui ___
Re: [PATCH v5 3/5] powerpc/85xx: add sleep and deep sleep support
On 06/04/2012 06:12 AM, Zhao Chenhui wrote: On Fri, Jun 01, 2012 at 04:54:35PM -0500, Scott Wood wrote: On 05/11/2012 06:53 AM, Zhao Chenhui wrote: diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h index 94ec20a..baa000c 100644 --- a/arch/powerpc/include/asm/cacheflush.h +++ b/arch/powerpc/include/asm/cacheflush.h @@ -33,6 +33,11 @@ extern void flush_dcache_page(struct page *page); #if defined(CONFIG_FSL_BOOKE) || defined(CONFIG_6xx) extern void __flush_disable_L1(void); #endif +#if defined(CONFIG_FSL_BOOKE) +extern void flush_dcache_L1(void); +#else +#define flush_dcache_L1() do { } while (0) +#endif It doesn't seem right to no-op this on other platforms. The pmc_suspend_enter() in fsl_pmc.c used by mpc85xx and mpc86xx, but flush_dcache_L1() have no definition in mpc86xx platform. I will write flush_dcache_L1() for mpc86xx platform. How about only calling the function when it's needed? If we didn't need an L1 flush here on 86xx before, why do we need it now? extern void __flush_icache_range(unsigned long, unsigned long); static inline void flush_icache_range(unsigned long start, unsigned long stop) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index f5808a3..cb70dba 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -64,6 +64,9 @@ obj-$(CONFIG_FA_DUMP) += fadump.o ifeq ($(CONFIG_PPC32),y) obj-$(CONFIG_E500) += idle_e500.o endif +ifneq ($(CONFIG_PPC_E500MC),y) +obj-$(CONFIG_PPC_85xx) += l2cache_85xx.o +endif Can we introduce a symbol that specifically means pre-e500mc e500, rather than using negative logic? I think something like CONFIG_PPC_E500_V1_V2 has been proposed before. Agree. But CONFIG_PPC_E500_V1_V2 haven't been merged. Has the concept been NACKed, or just forgotten? If the latter, you could include it in this patchset. -Scott ___ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev
Re: [PATCH v5 3/5] powerpc/85xx: add sleep and deep sleep support
On 05/11/2012 06:53 AM, Zhao Chenhui wrote: From: Li Yang le...@freescale.com In sleep PM mode, the clocks of e500 core and unused IP blocks is turned off. IP blocks which are allowed to wake up the processor are still running. Some Freescale chips like MPC8536 and P1022 has deep sleep PM mode in addtion to the sleep PM mode. While in deep sleep PM mode, additionally, the power supply is removed from e500 core and most IP blocks. Only the blocks needed to wake up the chip out of deep sleep are ON. This patch supports 32-bit and 36-bit address space. The sleep mode is equal to the Standby state in Linux. The deep sleep mode is equal to the Suspend-to-RAM state of Linux Power Management. Command to enter sleep mode. echo standby /sys/power/state Command to enter deep sleep mode. echo mem /sys/power/state Signed-off-by: Dave Liu dave...@freescale.com Signed-off-by: Li Yang le...@freescale.com Signed-off-by: Jin Qing b24...@freescale.com Signed-off-by: Jerry Huang chang-ming.hu...@freescale.com Cc: Scott Wood scottw...@freescale.com Signed-off-by: Zhao Chenhui chenhui.z...@freescale.com --- Changes for v5: * Rename flush_disable_L1 to __flush_disable_L1. arch/powerpc/Kconfig |2 +- arch/powerpc/include/asm/cacheflush.h |5 + arch/powerpc/kernel/Makefile |3 + arch/powerpc/kernel/l2cache_85xx.S| 53 +++ arch/powerpc/platforms/85xx/Makefile |3 + arch/powerpc/platforms/85xx/sleep.S | 609 + arch/powerpc/sysdev/fsl_pmc.c | 91 - arch/powerpc/sysdev/fsl_soc.h |5 + 8 files changed, 752 insertions(+), 19 deletions(-) create mode 100644 arch/powerpc/kernel/l2cache_85xx.S create mode 100644 arch/powerpc/platforms/85xx/sleep.S diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index d65ae35..039f0a6 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -673,7 +673,7 @@ config FSL_PCI config FSL_PMC bool default y - depends on SUSPEND (PPC_85xx || PPC_86xx) + depends on SUSPEND (PPC_85xx || PPC_86xx) !PPC_E500MC help Freescale MPC85xx/MPC86xx power management controller support (suspend/resume). For MPC83xx see platforms/83xx/suspend.c diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h index 94ec20a..baa000c 100644 --- a/arch/powerpc/include/asm/cacheflush.h +++ b/arch/powerpc/include/asm/cacheflush.h @@ -33,6 +33,11 @@ extern void flush_dcache_page(struct page *page); #if defined(CONFIG_FSL_BOOKE) || defined(CONFIG_6xx) extern void __flush_disable_L1(void); #endif +#if defined(CONFIG_FSL_BOOKE) +extern void flush_dcache_L1(void); +#else +#define flush_dcache_L1()do { } while (0) +#endif It doesn't seem right to no-op this on other platforms. extern void __flush_icache_range(unsigned long, unsigned long); static inline void flush_icache_range(unsigned long start, unsigned long stop) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index f5808a3..cb70dba 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -64,6 +64,9 @@ obj-$(CONFIG_FA_DUMP) += fadump.o ifeq ($(CONFIG_PPC32),y) obj-$(CONFIG_E500) += idle_e500.o endif +ifneq ($(CONFIG_PPC_E500MC),y) +obj-$(CONFIG_PPC_85xx) += l2cache_85xx.o +endif Can we introduce a symbol that specifically means pre-e500mc e500, rather than using negative logic? I think something like CONFIG_PPC_E500_V1_V2 has been proposed before. -static int pmc_probe(struct platform_device *ofdev) +static int pmc_probe(struct platform_device *pdev) { - pmc_regs = of_iomap(ofdev-dev.of_node, 0); + struct device_node *np = pdev-dev.of_node; + + pmc_regs = of_iomap(np, 0); if (!pmc_regs) return -ENOMEM; - pmc_dev = ofdev-dev; + pmc_flag = PMC_SLEEP; + if (of_device_is_compatible(np, fsl,mpc8536-pmc)) + pmc_flag |= PMC_DEEP_SLEEP; + + if (of_device_is_compatible(np, fsl,p1022-pmc)) + pmc_flag |= PMC_DEEP_SLEEP; + suspend_set_ops(pmc_suspend_ops); + + pr_info(Freescale PMC driver\n); If you're going to be noisy on probe, at least provide some useful info like whether deep sleep or jog are supported. return 0; } diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h index c6d0073..949377d 100644 --- a/arch/powerpc/sysdev/fsl_soc.h +++ b/arch/powerpc/sysdev/fsl_soc.h @@ -48,5 +48,10 @@ extern struct platform_diu_data_ops diu_ops; void fsl_hv_restart(char *cmd); void fsl_hv_halt(void); +/* + * Cast the ccsrbar to 64-bit parameter so that the assembly + * code can be compatible with both 32-bit 36-bit. + */ +extern void mpc85xx_enter_deep_sleep(u64 ccsrbar, u32 powmgtreq); s/Cast the ccsrbar to 64-bit parameter/ccsrbar is u64 rather
[PATCH v5 3/5] powerpc/85xx: add sleep and deep sleep support
From: Li Yang le...@freescale.com In sleep PM mode, the clocks of e500 core and unused IP blocks is turned off. IP blocks which are allowed to wake up the processor are still running. Some Freescale chips like MPC8536 and P1022 has deep sleep PM mode in addtion to the sleep PM mode. While in deep sleep PM mode, additionally, the power supply is removed from e500 core and most IP blocks. Only the blocks needed to wake up the chip out of deep sleep are ON. This patch supports 32-bit and 36-bit address space. The sleep mode is equal to the Standby state in Linux. The deep sleep mode is equal to the Suspend-to-RAM state of Linux Power Management. Command to enter sleep mode. echo standby /sys/power/state Command to enter deep sleep mode. echo mem /sys/power/state Signed-off-by: Dave Liu dave...@freescale.com Signed-off-by: Li Yang le...@freescale.com Signed-off-by: Jin Qing b24...@freescale.com Signed-off-by: Jerry Huang chang-ming.hu...@freescale.com Cc: Scott Wood scottw...@freescale.com Signed-off-by: Zhao Chenhui chenhui.z...@freescale.com --- Changes for v5: * Rename flush_disable_L1 to __flush_disable_L1. arch/powerpc/Kconfig |2 +- arch/powerpc/include/asm/cacheflush.h |5 + arch/powerpc/kernel/Makefile |3 + arch/powerpc/kernel/l2cache_85xx.S| 53 +++ arch/powerpc/platforms/85xx/Makefile |3 + arch/powerpc/platforms/85xx/sleep.S | 609 + arch/powerpc/sysdev/fsl_pmc.c | 91 - arch/powerpc/sysdev/fsl_soc.h |5 + 8 files changed, 752 insertions(+), 19 deletions(-) create mode 100644 arch/powerpc/kernel/l2cache_85xx.S create mode 100644 arch/powerpc/platforms/85xx/sleep.S diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index d65ae35..039f0a6 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -673,7 +673,7 @@ config FSL_PCI config FSL_PMC bool default y - depends on SUSPEND (PPC_85xx || PPC_86xx) + depends on SUSPEND (PPC_85xx || PPC_86xx) !PPC_E500MC help Freescale MPC85xx/MPC86xx power management controller support (suspend/resume). For MPC83xx see platforms/83xx/suspend.c diff --git a/arch/powerpc/include/asm/cacheflush.h b/arch/powerpc/include/asm/cacheflush.h index 94ec20a..baa000c 100644 --- a/arch/powerpc/include/asm/cacheflush.h +++ b/arch/powerpc/include/asm/cacheflush.h @@ -33,6 +33,11 @@ extern void flush_dcache_page(struct page *page); #if defined(CONFIG_FSL_BOOKE) || defined(CONFIG_6xx) extern void __flush_disable_L1(void); #endif +#if defined(CONFIG_FSL_BOOKE) +extern void flush_dcache_L1(void); +#else +#define flush_dcache_L1() do { } while (0) +#endif extern void __flush_icache_range(unsigned long, unsigned long); static inline void flush_icache_range(unsigned long start, unsigned long stop) diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index f5808a3..cb70dba 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -64,6 +64,9 @@ obj-$(CONFIG_FA_DUMP) += fadump.o ifeq ($(CONFIG_PPC32),y) obj-$(CONFIG_E500) += idle_e500.o endif +ifneq ($(CONFIG_PPC_E500MC),y) +obj-$(CONFIG_PPC_85xx) += l2cache_85xx.o +endif obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o obj-$(CONFIG_TAU) += tau_6xx.o obj-$(CONFIG_HIBERNATION) += swsusp.o suspend.o diff --git a/arch/powerpc/kernel/l2cache_85xx.S b/arch/powerpc/kernel/l2cache_85xx.S new file mode 100644 index 000..b0b7d1c --- /dev/null +++ b/arch/powerpc/kernel/l2cache_85xx.S @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2009-2012 Freescale Semiconductor, Inc. All rights reserved. + * Scott Wood scottw...@freescale.com + * Dave Liu dave...@freescale.com + * implement the L2 cache operations of e500 based L2 controller + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include asm/reg.h +#include asm/cputable.h +#include asm/ppc_asm.h +#include asm/asm-offsets.h + + .section .text + + /* r3 = virtual address of L2 controller, WIMG = 01xx */ +_GLOBAL(flush_disable_L2) + /* It's a write-through cache, so only invalidation is needed. */ + mbar + isync + lwz r4, 0(r3) + li r5, 1 + rlwimi r4, r5, 30, 0xc000 + stw r4, 0(r3) + + /* Wait for the invalidate to finish */ +1: lwz r4, 0(r3) + andis. r4, r4, 0x4000 + bne 1b + mbar + + blr + + /* r3 = virtual address of L2 controller, WIMG = 01xx */ +_GLOBAL(invalidate_enable_L2) + mbar + isync + lwz r4, 0(r3) + li r5, 3 + rlwimi r4, r5, 30, 0xc000 + stw r4, 0(r3) + + /* Wait for the