Commit d492ccca authored by Thomas Petazzoni's avatar Thomas Petazzoni Committed by Gregory CLEMENT

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: default avatarThomas Petazzoni <thomas.petazzoni@free-electrons.com>
Signed-off-by: default avatarGregory CLEMENT <gregory.clement@free-electrons.com>
parent 6ff33f39
MVEBU CPU Config registers
--------------------------
MVEBU (Marvell SOCs: Armada 370/XP)
Required properties:
- compatible: one of:
- "marvell,armada-370-cpu-config"
- "marvell,armada-xp-cpu-config"
- reg: Should contain CPU config registers location and length, in
their per-CPU variant
Example:
cpu-config@21000 {
compatible = "marvell,armada-xp-cpu-config";
reg = <0x21000 0x8>;
};
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
unsigned long coherency_phys_base; unsigned long coherency_phys_base;
void __iomem *coherency_base; void __iomem *coherency_base;
static void __iomem *coherency_cpu_base; static void __iomem *coherency_cpu_base;
static void __iomem *cpu_config_base;
/* Coherency fabric registers */ /* Coherency fabric registers */
#define IO_SYNC_BARRIER_CTL_OFFSET 0x0 #define IO_SYNC_BARRIER_CTL_OFFSET 0x0
...@@ -65,6 +66,31 @@ static const struct of_device_id of_coherency_table[] = { ...@@ -65,6 +66,31 @@ static const struct of_device_id of_coherency_table[] = {
int ll_enable_coherency(void); int ll_enable_coherency(void);
void ll_add_cpu_to_smp_group(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, static int mvebu_hwcc_notifier(struct notifier_block *nb,
unsigned long event, void *__dev) unsigned long event, void *__dev)
{ {
...@@ -85,9 +111,24 @@ static struct notifier_block mvebu_hwcc_pci_nb = { ...@@ -85,9 +111,24 @@ static struct notifier_block mvebu_hwcc_pci_nb = {
.notifier_call = mvebu_hwcc_notifier, .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) static void __init armada_370_coherency_init(struct device_node *np)
{ {
struct resource res; struct resource res;
struct device_node *cpu_config_np;
of_address_to_resource(np, 0, &res); of_address_to_resource(np, 0, &res);
coherency_phys_base = res.start; coherency_phys_base = res.start;
...@@ -100,6 +141,23 @@ static void __init armada_370_coherency_init(struct device_node *np) ...@@ -100,6 +141,23 @@ static void __init armada_370_coherency_init(struct device_node *np)
sync_cache_w(&coherency_phys_base); sync_cache_w(&coherency_phys_base);
coherency_base = of_iomap(np, 0); coherency_base = of_iomap(np, 0);
coherency_cpu_base = of_iomap(np, 1); 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(); set_cpu_coherent();
} }
...@@ -204,6 +262,8 @@ int set_cpu_coherent(void) ...@@ -204,6 +262,8 @@ int set_cpu_coherent(void)
pr_warn("Coherency fabric is not initialized\n"); pr_warn("Coherency fabric is not initialized\n");
return 1; return 1;
} }
armada_xp_clear_shared_l2();
ll_add_cpu_to_smp_group(); ll_add_cpu_to_smp_group();
return ll_enable_coherency(); return ll_enable_coherency();
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment