Commit 19f47051 authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'mvebu-soc-4.4-1' of git://git.infradead.org/linux-mvebu into next/soc

Merge "mvebu soc for 4.4 (part 1)" from Gregory CLEMENT:

L2 caches optimization for Armada XP

* tag 'mvebu-soc-4.4-1' of git://git.infradead.org/linux-mvebu:
  ARM: mvebu: add support to clear shared L2 bit on Armada XP
parents 55fa3ee0 d492ccca
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
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>;
	};
+60 −0
Original line number Diff line number Diff line
@@ -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();
	}