From d492cccac28493f26bb70038385a9ef4df19bdee Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 8 Jul 2015 16:09:20 +0200 Subject: ARM: mvebu: add support to clear shared L2 bit on Armada XP For optimal performance, in a HW I/O coherency context such as the one used on Armada XP, the shared L2 bit of the CPU configuration register should be cleared. This commit adjusts the coherency fabric code used by Marvell EBU processors to clear this bit on Armada XP. Since it's a per-CPU register, it's cleared in set_cpu_coherent() for the boot CPU, and through a CPU notifier for the non-boot CPUs. [gregory.clement@free-electrons.com: rebasd on 4.3-rc1] Signed-off-by: Thomas Petazzoni Signed-off-by: Gregory CLEMENT --- arch/arm/mach-mvebu/coherency.c | 60 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'arch/arm/mach-mvebu') diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index 44eedf331ae7..55348ee5a352 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c @@ -40,6 +40,7 @@ unsigned long coherency_phys_base; void __iomem *coherency_base; static void __iomem *coherency_cpu_base; +static void __iomem *cpu_config_base; /* Coherency fabric registers */ #define IO_SYNC_BARRIER_CTL_OFFSET 0x0 @@ -65,6 +66,31 @@ static const struct of_device_id of_coherency_table[] = { int ll_enable_coherency(void); void ll_add_cpu_to_smp_group(void); +#define CPU_CONFIG_SHARED_L2 BIT(16) + +/* + * Disable the "Shared L2 Present" bit in CPU Configuration register + * on Armada XP. + * + * The "Shared L2 Present" bit affects the "level of coherence" value + * in the clidr CP15 register. Cache operation functions such as + * "flush all" and "invalidate all" operate on all the cache levels + * that included in the defined level of coherence. When HW I/O + * coherency is used, this bit causes unnecessary flushes of the L2 + * cache. + */ +static void armada_xp_clear_shared_l2(void) +{ + u32 reg; + + if (!cpu_config_base) + return; + + reg = readl(cpu_config_base); + reg &= ~CPU_CONFIG_SHARED_L2; + writel(reg, cpu_config_base); +} + static int mvebu_hwcc_notifier(struct notifier_block *nb, unsigned long event, void *__dev) { @@ -85,9 +111,24 @@ static struct notifier_block mvebu_hwcc_pci_nb = { .notifier_call = mvebu_hwcc_notifier, }; +static int armada_xp_clear_shared_l2_notifier_func(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) + armada_xp_clear_shared_l2(); + + return NOTIFY_OK; +} + +static struct notifier_block armada_xp_clear_shared_l2_notifier = { + .notifier_call = armada_xp_clear_shared_l2_notifier_func, + .priority = 100, +}; + static void __init armada_370_coherency_init(struct device_node *np) { struct resource res; + struct device_node *cpu_config_np; of_address_to_resource(np, 0, &res); coherency_phys_base = res.start; @@ -100,6 +141,23 @@ static void __init armada_370_coherency_init(struct device_node *np) sync_cache_w(&coherency_phys_base); coherency_base = of_iomap(np, 0); coherency_cpu_base = of_iomap(np, 1); + + cpu_config_np = of_find_compatible_node(NULL, NULL, + "marvell,armada-xp-cpu-config"); + if (!cpu_config_np) + goto exit; + + cpu_config_base = of_iomap(cpu_config_np, 0); + if (!cpu_config_base) { + of_node_put(cpu_config_np); + goto exit; + } + + of_node_put(cpu_config_np); + + register_cpu_notifier(&armada_xp_clear_shared_l2_notifier); + +exit: set_cpu_coherent(); } @@ -204,6 +262,8 @@ int set_cpu_coherent(void) pr_warn("Coherency fabric is not initialized\n"); return 1; } + + armada_xp_clear_shared_l2(); ll_add_cpu_to_smp_group(); return ll_enable_coherency(); } -- cgit v1.2.3-58-ga151 From 9d2ea95a599a80b08cc802f044626ea2701aade9 Mon Sep 17 00:00:00 2001 From: Vincent Donnefort Date: Fri, 23 Oct 2015 12:59:58 +0200 Subject: ARM: mvebu: add broken-idle option The broken-idle option can be activated from the coherency-fabric DT node. This property allows to disable the idle capability, when the hardware doesn't support it, like the Seagate Personal Cloud boards. Signed-off-by: Vincent Donnefort Signed-off-by: Gregory CLEMENT --- .../devicetree/bindings/arm/coherency-fabric.txt | 5 ++++ arch/arm/mach-mvebu/pmsu.c | 29 +++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) (limited to 'arch/arm/mach-mvebu') diff --git a/Documentation/devicetree/bindings/arm/coherency-fabric.txt b/Documentation/devicetree/bindings/arm/coherency-fabric.txt index 8dd46617c889..9b5c3f620e65 100644 --- a/Documentation/devicetree/bindings/arm/coherency-fabric.txt +++ b/Documentation/devicetree/bindings/arm/coherency-fabric.txt @@ -27,6 +27,11 @@ Required properties: * For "marvell,armada-380-coherency-fabric", only one pair is needed for the per-CPU fabric registers. +Optional properties: + +- broken-idle: boolean to set when the Idle mode is not supported by the + hardware. + Examples: coherency-fabric@d0020200 { diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c index e8fdb9ceedf0..867ec3385eb5 100644 --- a/arch/arm/mach-mvebu/pmsu.c +++ b/arch/arm/mach-mvebu/pmsu.c @@ -379,6 +379,16 @@ static struct notifier_block mvebu_v7_cpu_pm_notifier = { static struct platform_device mvebu_v7_cpuidle_device; +static int broken_idle(struct device_node *np) +{ + if (of_property_read_bool(np, "broken-idle")) { + pr_warn("CPU idle is currently broken: disabling\n"); + return 1; + } + + return 0; +} + static __init int armada_370_cpuidle_init(void) { struct device_node *np; @@ -387,7 +397,9 @@ static __init int armada_370_cpuidle_init(void) np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"); if (!np) return -ENODEV; - of_node_put(np); + + if (broken_idle(np)) + goto end; /* * On Armada 370, there is "a slow exit process from the deep @@ -406,6 +418,8 @@ static __init int armada_370_cpuidle_init(void) mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; mvebu_v7_cpuidle_device.name = "cpuidle-armada-370"; +end: + of_node_put(np); return 0; } @@ -422,6 +436,10 @@ static __init int armada_38x_cpuidle_init(void) "marvell,armada-380-coherency-fabric"); if (!np) return -ENODEV; + + if (broken_idle(np)) + goto end; + of_node_put(np); np = of_find_compatible_node(NULL, NULL, @@ -430,7 +448,6 @@ static __init int armada_38x_cpuidle_init(void) return -ENODEV; mpsoc_base = of_iomap(np, 0); BUG_ON(!mpsoc_base); - of_node_put(np); /* Set up reset mask when powering down the cpus */ reg = readl(mpsoc_base + MPCORE_RESET_CTL); @@ -450,6 +467,8 @@ static __init int armada_38x_cpuidle_init(void) mvebu_v7_cpuidle_device.dev.platform_data = armada_38x_cpu_suspend; mvebu_v7_cpuidle_device.name = "cpuidle-armada-38x"; +end: + of_node_put(np); return 0; } @@ -460,12 +479,16 @@ static __init int armada_xp_cpuidle_init(void) np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric"); if (!np) return -ENODEV; - of_node_put(np); + + if (broken_idle(np)) + goto end; mvebu_cpu_resume = armada_370_xp_cpu_resume; mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend; mvebu_v7_cpuidle_device.name = "cpuidle-armada-xp"; +end: + of_node_put(np); return 0; } -- cgit v1.2.3-58-ga151