[PATCH 7/8] ARM: vexpress/dcscb: handle platform coherency exit/setup and CCI

Jon Medhurst (Tixy) tixy at linaro.org
Wed May 29 08:29:41 EDT 2013


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.


>  	node = of_find_compatible_node(NULL, NULL, "arm,rtsm,dcscb");
>  	if (!node)
>  		return -ENODEV;
> @@ -195,11 +232,15 @@ static int __init dcscb_init(void)
>  	dcscb_usage_count_init();
>  
>  	ret = mcpm_platform_register(&dcscb_power_ops);
> +	if (!ret)
> +		ret = mcpm_sync_init(dcscb_power_up_setup);
>  	if (ret) {
>  		iounmap(dcscb_base);
>  		return ret;
>  	}
>  
> +	pr_info("VExpress DCSCB support installed\n");
> +
>  	/*
>  	 * Future entries into the kernel can now go
>  	 * through the cluster entry vectors.
> diff --git a/arch/arm/mach-vexpress/dcscb_setup.S b/arch/arm/mach-vexpress/dcscb_setup.S
> new file mode 100644
> index 0000000000..4bb7fbe0f6
> --- /dev/null
> +++ b/arch/arm/mach-vexpress/dcscb_setup.S
> @@ -0,0 +1,38 @@
> +/*
> + * arch/arm/include/asm/dcscb_setup.S
> + *
> + * Created by:  Dave Martin, 2012-06-22
> + * Copyright:   (C) 2012-2013  Linaro Limited
> + *
> + * 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/linkage.h>
> +
> +
> +ENTRY(dcscb_power_up_setup)
> +
> +	cmp	r0, #0			@ check affinity level
> +	beq	2f
> +
> +/*
> + * Enable cluster-level coherency, in preparation for turning on the MMU.
> + * The ACTLR SMP bit does not need to be set here, because cpu_resume()
> + * already restores that.
> + *
> + * A15/A7 may not require explicit L2 invalidation on reset, dependent
> + * on hardware integration decisions.
> + * For now, this code assumes that L2 is either already invalidated,
> + * or invalidation is not required.
> + */
> +
> +	b	cci_enable_port_for_self
> +
> +2:	@ Implementation-specific local CPU setup operations should go here,
> +	@ if any.  In this case, there is nothing to do.
> +
> +	bx	lr
> +
> +ENDPROC(dcscb_power_up_setup)

-- 
Tixy





More information about the linux-arm-kernel mailing list