[PATCH 3/9] ARM: MB86S7X: Add MCPM support
Nicolas Pitre
nicolas.pitre at linaro.org
Tue Nov 25 10:59:17 PST 2014
On Tue, 25 Nov 2014, Lorenzo Pieralisi wrote:
> On Tue, Nov 25, 2014 at 05:42:32PM +0000, Nicolas Pitre wrote:
> > On Thu, 20 Nov 2014, Vincent Yang wrote:
> >
> > > The remote firmware(SCB) owns the SMP control. This MCPM driver gets
> > > CPU/CLUSTER power up/down done by SCB over mailbox.
> > >
> > > Signed-off-by: Andy Green <andy.green at linaro.org>
> > > Signed-off-by: Jassi Brar <jaswinder.singh at linaro.org>
> > > Signed-off-by: Vincent Yang <Vincent.Yang at tw.fujitsu.com>
> > > Signed-off-by: Tetsuya Nuriya <nuriya.tetsuya at jp.fujitsu.com>
> > > ---
> > > arch/arm/mach-mb86s7x/Makefile | 2 +-
> > > arch/arm/mach-mb86s7x/mcpm.c | 360 +++++++++++++++++++++++++++++++++++++++++
> > > arch/arm/mach-mb86s7x/smc.S | 27 ++++
> > > 3 files changed, 388 insertions(+), 1 deletion(-)
> > > create mode 100644 arch/arm/mach-mb86s7x/mcpm.c
> > > create mode 100644 arch/arm/mach-mb86s7x/smc.S
> > >
> > > diff --git a/arch/arm/mach-mb86s7x/Makefile b/arch/arm/mach-mb86s7x/Makefile
> > > index 97640b6..b0fa34b 100644
> > > --- a/arch/arm/mach-mb86s7x/Makefile
> > > +++ b/arch/arm/mach-mb86s7x/Makefile
> > > @@ -1 +1 @@
> > > -obj-$(CONFIG_ARCH_MB86S7X) += board.o
> > > +obj-$(CONFIG_ARCH_MB86S7X) += board.o mcpm.o smc.o
> > > diff --git a/arch/arm/mach-mb86s7x/mcpm.c b/arch/arm/mach-mb86s7x/mcpm.c
> > > new file mode 100644
> > > index 0000000..bf1b50a
> > > --- /dev/null
> > > +++ b/arch/arm/mach-mb86s7x/mcpm.c
> > > @@ -0,0 +1,360 @@
> > > +/*
> > > + * arch/arm/mach-mb86s7x/mcpm.c
> > > + * Copyright: (C) 2013-2014 Fujitsu Semiconductor Limited
> > > + * Copyright: (C) 2014 Linaro Ltd.
> > > + *
> > > + * This program is free software; you can redistribute it and/or modify
> > > + * it under the terms of the GNU General Public License version 2 as
> > > + * published by the Free Software Foundation.
> > > + */
> > > +
> > > +#include <linux/io.h>
> > > +#include <linux/pm.h>
> > > +#include <linux/delay.h>
> > > +#include <linux/cpu_pm.h>
> > > +#include <linux/kernel.h>
> > > +#include <linux/module.h>
> > > +#include <linux/arm-cci.h>
> > > +#include <linux/spinlock.h>
> > > +#include <linux/suspend.h>
> > > +#include <linux/of_device.h>
> > > +#include <linux/irqchip/arm-gic.h>
> > > +#include <linux/platform_device.h>
> > > +
> > > +#include <soc/mb86s7x/scb_mhu.h>
> > > +
> > > +#include <asm/mcpm.h>
> > > +#include <asm/cp15.h>
> > > +#include <asm/cputype.h>
> > > +#include <asm/suspend.h>
> > > +#include <asm/idmap.h>
> > > +
> > > +#define S7X_MAX_CLUSTER 2
> > > +#define S7X_MAX_CPU 2
> > > +
> > > +#define MHU_SHM_OFFSET 0x3800
> > > +#define WFI_COLOR_OFFSET 0x3f00
> > > +#define TRAMPOLINE_OFFSET 0x3c00
> > > +#define RESET_OFFSET (TRAMPOLINE_OFFSET + 0x3fc)
> > > +
> > > +static arch_spinlock_t mb86s7x_pm_lock = __ARCH_SPIN_LOCK_UNLOCKED;
> > > +static int mb86s7x_pm_use_count[S7X_MAX_CLUSTER][S7X_MAX_CPU];
> > > +extern void __iomem *mb86s7x_shm_base;
> > > +
> > > +#define AT_WFI_DO_NOTHING 0x0
> > > +#define AT_WFI_DO_SUSPEND 0x1
> > > +#define AT_WFI_DO_POWEROFF 0x2
> > > +#define AT_WFI_COLOR_MASK 0x3
> > > +
> > > +struct mb86s7x_cpu_gate {
> > > + u32 payload_size;
> > > + u32 cluster_class;
> > > + u32 cluster_id;
> > > + u32 cpu_id;
> > > +#define SCB_CPU_STATE_OFF 0x0
> > > +#define SCB_CPU_STATE_ON 0x1
> > > +#define SCB_CPU_STATE_SUSP 0x2
> > > + u32 cpu_state;
> > > +};
> > > +
> > > +asmlinkage void mb86s70evb_outer_flush_all(void)
> > > +{
> > > + outer_flush_all();
> > > +}
> > > +
> > > +#define mb86s70evb_exit_coherency_flush(level) { \
> > > + asm volatile( \
> > > + "stmfd sp!, {fp, ip}\n\t" \
> > > + "mrc p15, 0, r0, c1, c0, 0 @ get SCTLR\n\t" \
> > > + "bic r0, r0, #"__stringify(CR_C)"\n\t" \
> > > + "mcr p15, 0, r0, c1, c0, 0 @ set SCTLR\n\t" \
> > > + "isb\n\t" \
> > > + "bl v7_flush_dcache_"__stringify(level)"\n\t" \
> > > + "bl mb86s70evb_outer_flush_all\n\t" \
> >
> > This is wrong. As mentioned already, this unconditionally flushes L2 in
> > all cases which shouldn't be necessary in the "louis" case.
>
> Is this a bL system with unified and architected L2s ? I think so, so
> what's the outercache for ?
>
> > Furthermore, the safety of this macro is ensured by not having any
> > memory writes in the middle of the whole sequence. By calling
> > mb86s70evb_outer_flush_all() there could be the return address pushed
> > onto the stack before calling outer_flush_all() if some tail call
> > optimization is not applied. And this is without saying what
> > outer_flush_all() actually does.
> >
> > Why can't you simply do this instead:
> >
> > v7_exit_coherency_flush(all);
> > outer_flush_all();
> >
> > Of course you'll have to audit everything in the outer_flush_all() path
> > to make sure no atomic instructions such as LDREX/STREX are invoked.
> > Those have undefined behavior after CR_C is cleared.
>
> What you are saying is correct but first of all I would like to
> understand what outercache we are talking about here.
>
> Code snippet above is fragile, as you said, and I'd rather disable
> the outercache before executing the power down sequence (which implies
> cache is cleaned/invalidated and quiescent before we clear the C bit)
> if there is an outercache to be managed.
Good question. That opens the potential for an even simpler fix! ;-)
Nicolas
More information about the linux-arm-kernel
mailing list