[PATCH 7/8] ARM: vexpress/dcscb: handle platform coherency exit/setup and CCI
Javi Merino
javi.merino at arm.com
Wed May 29 10:25:42 EDT 2013
On Wed, May 29, 2013 at 01:29:41PM +0100, Jon Medhurst (Tixy) wrote:
> On Fri, 2013-05-24 at 01:45 -0400, Nicolas Pitre wrote:
> > From: Dave Martin <dave.martin at linaro.org>
> >
> > Add the required code to properly handle race free platform coherency exit
> > to the DCSCB power down method.
> >
> > The power_up_setup callback is used to enable the CCI interface for
> > the cluster being brought up. This must be done in assembly before
> > the kernel environment is entered.
> >
> > Thanks to Achin Gupta and Nicolas Pitre for their help and
> > contributions.
> >
> > Signed-off-by: Dave Martin <dave.martin at linaro.org>
> > Signed-off-by: Nicolas Pitre <nico at linaro.org>
> > Reviewed-by: Santosh Shilimkar <santosh.shilimkar at ti.com>
> > Acked-by: Pawel Moll <pawel.moll at arm.com>
> > ---
> > arch/arm/mach-vexpress/Kconfig | 1 +
> > arch/arm/mach-vexpress/Makefile | 2 +-
> > arch/arm/mach-vexpress/dcscb.c | 79 +++++++++++++++++++++++++++---------
> > arch/arm/mach-vexpress/dcscb_setup.S | 38 +++++++++++++++++
> > 4 files changed, 100 insertions(+), 20 deletions(-)
> > create mode 100644 arch/arm/mach-vexpress/dcscb_setup.S
> >
> > diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig
> > index 2f46385c28..b8bbabec63 100644
> > --- a/arch/arm/mach-vexpress/Kconfig
> > +++ b/arch/arm/mach-vexpress/Kconfig
> > @@ -60,6 +60,7 @@ config ARCH_VEXPRESS_CA9X4
> > config ARCH_VEXPRESS_DCSCB
> > bool "Dual Cluster System Control Block (DCSCB) support"
> > depends on MCPM
> > + select ARM_CCI
> > help
> > Support for the Dual Cluster System Configuration Block (DCSCB).
> > This is needed to provide CPU and cluster power management
> > diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile
> > index 518519f57a..48ba89a814 100644
> > --- a/arch/arm/mach-vexpress/Makefile
> > +++ b/arch/arm/mach-vexpress/Makefile
> > @@ -6,6 +6,6 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
> >
> > obj-y := v2m.o
> > obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o
> > -obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o
> > +obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o dcscb_setup.o
> > obj-$(CONFIG_SMP) += platsmp.o
> > obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
> > diff --git a/arch/arm/mach-vexpress/dcscb.c b/arch/arm/mach-vexpress/dcscb.c
> > index b928b1f5eb..1acc975360 100644
> > --- a/arch/arm/mach-vexpress/dcscb.c
> > +++ b/arch/arm/mach-vexpress/dcscb.c
> > @@ -16,6 +16,7 @@
> > #include <linux/errno.h>
> > #include <linux/of_address.h>
> > #include <linux/vexpress.h>
> > +#include <linux/arm-cci.h>
> >
> > #include <asm/mcpm.h>
> > #include <asm/proc-fns.h>
> > @@ -105,7 +106,10 @@ static void dcscb_power_down(void)
> > pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> > BUG_ON(cpu >= 4 || cluster >= 2);
> >
> > + __mcpm_cpu_going_down(cpu, cluster);
> > +
> > arch_spin_lock(&dcscb_lock);
> > + BUG_ON(__mcpm_cluster_state(cluster) != CLUSTER_UP);
> > dcscb_use_count[cpu][cluster]--;
> > if (dcscb_use_count[cpu][cluster] == 0) {
> > rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4);
> > @@ -125,31 +129,59 @@ static void dcscb_power_down(void)
> > skip_wfi = true;
> > } else
> > BUG();
> > - arch_spin_unlock(&dcscb_lock);
> > -
> > - /*
> > - * Now let's clean our L1 cache and shut ourself down.
> > - * If we're the last CPU in this cluster then clean L2 too.
> > - */
> >
> > - /*
> > - * A15/A7 can hit in the cache with SCTLR.C=0, so we don't need
> > - * a preliminary flush here for those CPUs. At least, that's
> > - * the theory -- without the extra flush, Linux explodes on
> > - * RTSM (to be investigated)..
> > - */
> > - flush_cache_louis();
> > - set_cr(get_cr() & ~CR_C);
> > + if (last_man && __mcpm_outbound_enter_critical(cpu, cluster)) {
> > + arch_spin_unlock(&dcscb_lock);
> >
> > - if (!last_man) {
> > - flush_cache_louis();
> > - } else {
> > + /*
> > + * Flush all cache levels for this cluster.
> > + *
> > + * A15/A7 can hit in the cache with SCTLR.C=0, so we don't need
> > + * a preliminary flush here for those CPUs. At least, that's
> > + * the theory -- without the extra flush, Linux explodes on
> > + * RTSM (to be investigated).
> > + */
> > + flush_cache_all();
> > + set_cr(get_cr() & ~CR_C);
> > flush_cache_all();
> > +
> > + /*
> > + * This is a harmless no-op. On platforms with a real
> > + * outer cache this might either be needed or not,
> > + * depending on where the outer cache sits.
> > + */
> > outer_flush_all();
> > +
> > + /* Disable local coherency by clearing the ACTLR "SMP" bit: */
> > + set_auxcr(get_auxcr() & ~(1 << 6));
> > +
> > + /*
> > + * Disable cluster-level coherency by masking
> > + * incoming snoops and DVM messages:
> > + */
> > + cci_disable_port_by_cpu(mpidr);
> > +
> > + __mcpm_outbound_leave_critical(cluster, CLUSTER_DOWN);
> > + } else {
> > + arch_spin_unlock(&dcscb_lock);
> > +
> > + /*
> > + * Flush the local CPU cache.
> > + *
> > + * A15/A7 can hit in the cache with SCTLR.C=0, so we don't need
> > + * a preliminary flush here for those CPUs. At least, that's
> > + * the theory -- without the extra flush, Linux explodes on
> > + * RTSM (to be investigated).
> > + */
> > + flush_cache_louis();
> > + set_cr(get_cr() & ~CR_C);
> > + flush_cache_louis();
> > +
> > + /* Disable local coherency by clearing the ACTLR "SMP" bit: */
> > + set_auxcr(get_auxcr() & ~(1 << 6));
> > }
> >
> > - /* Disable local coherency by clearing the ACTLR "SMP" bit: */
> > - set_auxcr(get_auxcr() & ~(1 << 6));
> > + __mcpm_cpu_down(cpu, cluster);
> >
> > /* Now we are prepared for power-down, do it: */
> > dsb();
> > @@ -177,12 +209,17 @@ static void __init dcscb_usage_count_init(void)
> > dcscb_use_count[cpu][cluster] = 1;
> > }
> >
> > +extern void dcscb_power_up_setup(unsigned int affinity_level);
> > +
> > static int __init dcscb_init(void)
> > {
> > struct device_node *node;
> > unsigned int cfg;
> > int ret;
> >
> > + if (!cci_probed())
> > + return -ENODEV;
> > +
>
> I can't see where cci_probed() is defined, this seems to be the only
> occurrence in this patch set.
cci_probed() is defined in patch 1 of these series, in
include/linux/arm-cci.h and drivers/bus/arm-cci.c
Cheers,
Javi
More information about the linux-arm-kernel
mailing list