All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC] ARM: BCM5301X: Implement SMP support
@ 2015-02-10 20:32 Rafał Miłecki
  2015-02-13 11:54 ` Hauke Mehrtens
                   ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Rafał Miłecki @ 2015-02-10 20:32 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Rafa? Mi?ecki <zajec5@gmail.com>
---
 arch/arm/boot/dts/bcm4708.dtsi       |   1 +
 arch/arm/mach-bcm/Makefile           |   3 +
 arch/arm/mach-bcm/bcm5301x_headsmp.S | 108 ++++++++++++++++++++
 arch/arm/mach-bcm/bcm5301x_smp.c     | 185 +++++++++++++++++++++++++++++++++++
 4 files changed, 297 insertions(+)
 create mode 100644 arch/arm/mach-bcm/bcm5301x_headsmp.S
 create mode 100644 arch/arm/mach-bcm/bcm5301x_smp.c

diff --git a/arch/arm/boot/dts/bcm4708.dtsi b/arch/arm/boot/dts/bcm4708.dtsi
index 31141e8..ed4ddba 100644
--- a/arch/arm/boot/dts/bcm4708.dtsi
+++ b/arch/arm/boot/dts/bcm4708.dtsi
@@ -15,6 +15,7 @@
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
+		enable-method = "brcm,bcm4708-smp";
 
 		cpu at 0 {
 			device_type = "cpu";
diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
index 4c38674..ca12727 100644
--- a/arch/arm/mach-bcm/Makefile
+++ b/arch/arm/mach-bcm/Makefile
@@ -36,6 +36,9 @@ obj-$(CONFIG_ARCH_BCM2835)	+= board_bcm2835.o
 
 # BCM5301X
 obj-$(CONFIG_ARCH_BCM_5301X)	+= bcm_5301x.o
+ifeq ($(CONFIG_SMP),y)
+obj-$(CONFIG_ARCH_BCM_5301X)	+= bcm5301x_smp.o bcm5301x_headsmp.o
+endif
 
 # BCM63XXx
 obj-$(CONFIG_ARCH_BCM_63XX)	:= bcm63xx.o
diff --git a/arch/arm/mach-bcm/bcm5301x_headsmp.S b/arch/arm/mach-bcm/bcm5301x_headsmp.S
new file mode 100644
index 0000000..e8df65f
--- /dev/null
+++ b/arch/arm/mach-bcm/bcm5301x_headsmp.S
@@ -0,0 +1,108 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ *
+ * Copyright 2003 - 2008 Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <asm/memory.h>
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+#define __virt_to_phys(x)	((x) - PAGE_OFFSET)
+
+/*
+ * v7_l1_cache_invalidate
+ *
+ * Invalidate contents of L1 cache without flushing its contents
+ * into outer cache and memory. This is needed when the contents
+ * of the cache are unpredictable after power-up.
+ *
+ * corrupts r0-r6
+ */
+ENTRY(v7_l1_cache_invalidate)
+	mov	r0, #0
+	mcr	p15, 2, r0, c0, c0, 0	@ set cache level to 1
+	mrc	p15, 1, r0, c0, c0, 0	@ read CLIDR
+
+	ldr	r1, =0x7fff
+	and	r2, r1, r0, lsr #13	@ get max # of index size
+
+	ldr	r1, =0x3ff
+	and	r3, r1, r0, lsr #3	@ NumWays - 1
+	add	r2, r2, #1		@ NumSets
+
+	and	r0, r0, #0x7
+	add	r0, r0, #4		@ SetShift
+
+	clz	r1, r3			@ WayShift
+	add	r4, r3, #1		@ NumWays
+1:	sub	r2, r2, #1		@ NumSets--
+	mov	r3, r4			@ Temp = NumWays
+2:	subs	r3, r3, #1		@ Temp--
+	mov	r5, r3, lsl r1
+	mov	r6, r2, lsl r0
+	orr	r5, r5, r6		@ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
+	mcr	p15, 0, r5, c7, c6, 2	@ Invalidate line
+	bgt	2b
+	cmp	r2, #0
+	bgt	1b
+	dsb
+	mov	r0,#0
+	mcr	p15,0,r0,c7,c5,0	/* Invalidate icache */
+	isb
+	mov	pc, lr
+ENDPROC(v7_l1_cache_invalidate)
+
+/*
+ * Platform specific entry point for secondary CPUs.  This
+ * provides a "holding pen" into which all secondary cores are held
+ * until we're ready for them to initialise.
+ */
+	__CPUINIT
+ENTRY(bcm5301x_secondary_startup)
+	/*
+	 * Get hardware CPU id of ours
+	 */
+	mrc	p15, 0, r0, c0, c0, 5
+	and	r0, r0, #15
+	/*
+	 * Wait on <pen_release> variable by physical address
+	 * to contain our hardware CPU id
+	 */
+#ifdef CONFIG_SPARSEMEM
+	ldr	r2, =(PAGE_OFFSET+SZ_128M)
+	ldr	r1, =pen_release
+	cmp	r1, r2
+	bge	1f
+	ldr	r2, =PAGE_OFFSET
+	sub	r6, r1, r2
+	b	2f
+1:
+	sub	r1, r1, r2
+	ldr	r2, =PHYS_OFFSET2
+	add	r6, r1, r2
+2:
+#else
+	ldr	r6, =__virt_to_phys(pen_release)
+#endif
+pen:	ldr	r7, [r6]
+	cmp	r7, r0
+	bne	pen
+	nop
+	/*
+	 * In case L1 cache has unpredictable contents at power-up
+	 * clean its contents without flushing.
+	 */
+	bl	v7_l1_cache_invalidate
+	nop
+	/*
+	 * we've been released from the holding pen: secondary_stack
+	 * should now contain the SVC stack for this core
+	 */
+	b	secondary_startup
+
+ENDPROC(bcm5301x_secondary_startup)
+	.ltorg
diff --git a/arch/arm/mach-bcm/bcm5301x_smp.c b/arch/arm/mach-bcm/bcm5301x_smp.c
new file mode 100644
index 0000000..1a173ec
--- /dev/null
+++ b/arch/arm/mach-bcm/bcm5301x_smp.c
@@ -0,0 +1,185 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ *
+ * Copyright (C) 2002 ARM Ltd.
+ * Copyright (C) 2015 Rafa? Mi?ecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <asm/cacheflush.h>
+#include <asm/delay.h>
+#include <asm/smp_scu.h>
+
+#include <linux/clockchips.h>
+
+/*
+ * There is a 1KB LUT located at 0xFFFF0400-0xFFFFFFFF, and its first entry
+ * is where the secondary entry point needs to be written
+*/
+#define SOC_ROM_BASE_PA		0xffff0000
+#define SOC_ROM_LUT_OFF		0x400
+
+/* ENTRY in bcm5301x_headsmp.S */
+extern void bcm5301x_secondary_startup(void);
+
+static DEFINE_SPINLOCK(boot_lock);
+
+static void __cpuinit write_pen_release(int val)
+{
+	pen_release = val;
+	/* Make sure this store is visible to other CPUs */
+	smp_wmb();
+	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
+	outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
+}
+
+static void __init bcm5301x_smp_secondary_set_entry(void (*entry_point)(void))
+{
+	void __iomem *rombase = NULL;
+	phys_addr_t lut_pa;
+	u32 offset, mask;
+	u32 val;
+
+	mask = (1UL << PAGE_SHIFT) - 1;
+
+	lut_pa = SOC_ROM_BASE_PA & ~mask;
+	offset = SOC_ROM_BASE_PA &  mask;
+	offset += SOC_ROM_LUT_OFF;
+
+	rombase = ioremap(lut_pa, PAGE_SIZE);
+	if (!rombase)
+		return;
+	val = virt_to_phys(entry_point);
+
+	writel(val, rombase + offset);
+
+	smp_wmb();	/* probably not needed - io regs are not cached */
+	dsb_sev();	/* Exit WFI */
+	mb();
+
+	iounmap(rombase);
+}
+
+static void __init bcm5301x_smp_prepare_cpus(unsigned int max_cpus)
+{
+	void __iomem *scu_base;
+	unsigned int ncores;
+
+	if (!scu_a9_has_base()) {
+		pr_warn("Unknown SCU base\n");
+		return;
+	}
+
+	scu_base = ioremap((phys_addr_t)scu_a9_get_base(), SZ_256);
+	if (!scu_base) {
+		pr_err("Failed to remap SCU\n");
+		return;
+	}
+
+	ncores = scu_get_core_count(scu_base);
+	if (max_cpus > ncores) {
+		unsigned int i;
+
+		pr_warn("Possible CPU mask exceeds available cores, reducing to %u\n",
+			ncores);
+		for (i = ncores - 1; i < max_cpus; i++)
+			set_cpu_present(i, false);
+		max_cpus = ncores;
+	}
+
+	if (max_cpus > 1) {
+		/* nobody is to be released from the pen yet */
+		pen_release = -1;
+
+		/* Initialise the SCU */
+		scu_enable(scu_base);
+
+		/* Let CPUs know where to start */
+		bcm5301x_smp_secondary_set_entry(bcm5301x_secondary_startup);
+	}
+
+	iounmap(scu_base);
+}
+
+static void __cpuinit bcm5301x_smp_secondary_init(unsigned int cpu)
+{
+	trace_hardirqs_off();
+
+	/*
+	 * let the primary processor know we're out of the
+	 * pen, then head off into the C entry point
+	 */
+	write_pen_release(-1);
+
+	/*
+	 * Synchronise with the boot thread.
+	 */
+	spin_lock(&boot_lock);
+	spin_unlock(&boot_lock);
+}
+
+static int __cpuinit bcm5301x_smp_boot_secondary(unsigned int cpu,
+						 struct task_struct *idle)
+{
+	unsigned long timeout;
+
+	/*
+	 * set synchronisation state between this boot processor
+	 * and the secondary one
+	 */
+	spin_lock(&boot_lock);
+
+	/*
+	 * The secondary processor is waiting to be released from
+	 * the holding pen - release it, then wait for it to flag
+	 * that it has been released by resetting pen_release.
+	 *
+	 * Note that "pen_release" is the hardware CPU ID, whereas
+	 * "cpu" is Linux's internal ID.
+	 */
+	write_pen_release(cpu);
+
+	dsb_sev();
+
+	/*
+	 * Timeout set on purpose in jiffies so that on slow processors
+	 * that must also have low HZ it will wait longer.
+	 */
+	timeout = jiffies + (HZ * 10);
+
+	udelay(100);
+
+	/*
+	 * If the secondary CPU was waiting on WFE, it should
+	 * be already watching <pen_release>, or it could be
+	 * waiting in WFI, send it an IPI to be sure it wakes.
+	 */
+	if (pen_release != -1)
+		tick_broadcast(cpumask_of(cpu));
+
+	while (time_before(jiffies, timeout)) {
+		smp_rmb();
+		if (pen_release == -1)
+			break;
+
+		udelay(10);
+	}
+
+	/*
+	 * now the secondary core is starting up let it run its
+	 * calibrations, then wait for it to finish
+	 */
+	spin_unlock(&boot_lock);
+
+	return pen_release != -1 ? -ENOSYS : 0;
+}
+
+static struct smp_operations bcm5301x_smp_ops __initdata = {
+	.smp_prepare_cpus	= bcm5301x_smp_prepare_cpus,
+	.smp_secondary_init	= bcm5301x_smp_secondary_init,
+	.smp_boot_secondary	= bcm5301x_smp_boot_secondary,
+};
+
+CPU_METHOD_OF_DECLARE(bcm5301x_smp, "brcm,bcm4708-smp",
+		      &bcm5301x_smp_ops);
-- 
1.8.4.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH RFC] ARM: BCM5301X: Implement SMP support
  2015-02-10 20:32 [PATCH RFC] ARM: BCM5301X: Implement SMP support Rafał Miłecki
@ 2015-02-13 11:54 ` Hauke Mehrtens
  2015-02-13 12:29 ` Mark Rutland
  2015-02-19 22:32 ` [PATCH] " Rafał Miłecki
  2 siblings, 0 replies; 16+ messages in thread
From: Hauke Mehrtens @ 2015-02-13 11:54 UTC (permalink / raw)
  To: linux-arm-kernel

Thanks for working on this.

Someone else with more knowledge about arm cortex A9 SMP stuff should
look at this patch.

Did you had a look at mach-rockchip/platsmp.c ? While I was looking at
SMP stuff this code looked clean to me and they are also using a Cortex A9.

There are some comments in the code.

Hauke

On 02/10/2015 09:32 PM, Rafa? Mi?ecki wrote:
> Signed-off-by: Rafa? Mi?ecki <zajec5@gmail.com>
> ---
>  arch/arm/boot/dts/bcm4708.dtsi       |   1 +
>  arch/arm/mach-bcm/Makefile           |   3 +
>  arch/arm/mach-bcm/bcm5301x_headsmp.S | 108 ++++++++++++++++++++
>  arch/arm/mach-bcm/bcm5301x_smp.c     | 185 +++++++++++++++++++++++++++++++++++
>  4 files changed, 297 insertions(+)
>  create mode 100644 arch/arm/mach-bcm/bcm5301x_headsmp.S
>  create mode 100644 arch/arm/mach-bcm/bcm5301x_smp.c
> 
> diff --git a/arch/arm/boot/dts/bcm4708.dtsi b/arch/arm/boot/dts/bcm4708.dtsi
> index 31141e8..ed4ddba 100644
> --- a/arch/arm/boot/dts/bcm4708.dtsi
> +++ b/arch/arm/boot/dts/bcm4708.dtsi
> @@ -15,6 +15,7 @@
>  	cpus {
>  		#address-cells = <1>;
>  		#size-cells = <0>;
> +		enable-method = "brcm,bcm4708-smp";
>  
>  		cpu at 0 {
>  			device_type = "cpu";
> diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
> index 4c38674..ca12727 100644
> --- a/arch/arm/mach-bcm/Makefile
> +++ b/arch/arm/mach-bcm/Makefile
> @@ -36,6 +36,9 @@ obj-$(CONFIG_ARCH_BCM2835)	+= board_bcm2835.o
>  
>  # BCM5301X
>  obj-$(CONFIG_ARCH_BCM_5301X)	+= bcm_5301x.o
> +ifeq ($(CONFIG_SMP),y)
> +obj-$(CONFIG_ARCH_BCM_5301X)	+= bcm5301x_smp.o bcm5301x_headsmp.o
> +endif
>  
>  # BCM63XXx
>  obj-$(CONFIG_ARCH_BCM_63XX)	:= bcm63xx.o
> diff --git a/arch/arm/mach-bcm/bcm5301x_headsmp.S b/arch/arm/mach-bcm/bcm5301x_headsmp.S
> new file mode 100644
> index 0000000..e8df65f
> --- /dev/null
> +++ b/arch/arm/mach-bcm/bcm5301x_headsmp.S
> @@ -0,0 +1,108 @@
> +/*
> + * Broadcom BCM470X / BCM5301X ARM platform code.
> + *
> + * Copyright 2003 - 2008 Broadcom Corporation
> + *
> + * Licensed under the GNU/GPL. See COPYING for details.
> + */
> +
> +#include <asm/memory.h>
> +
> +#include <linux/linkage.h>
> +#include <linux/init.h>
> +
> +#define __virt_to_phys(x)	((x) - PAGE_OFFSET)
> +
> +/*
> + * v7_l1_cache_invalidate
> + *
> + * Invalidate contents of L1 cache without flushing its contents
> + * into outer cache and memory. This is needed when the contents
> + * of the cache are unpredictable after power-up.
> + *
> + * corrupts r0-r6
> + */
> +ENTRY(v7_l1_cache_invalidate)
> +	mov	r0, #0
> +	mcr	p15, 2, r0, c0, c0, 0	@ set cache level to 1
> +	mrc	p15, 1, r0, c0, c0, 0	@ read CLIDR
> +
> +	ldr	r1, =0x7fff
> +	and	r2, r1, r0, lsr #13	@ get max # of index size
> +
> +	ldr	r1, =0x3ff
> +	and	r3, r1, r0, lsr #3	@ NumWays - 1
> +	add	r2, r2, #1		@ NumSets
> +
> +	and	r0, r0, #0x7
> +	add	r0, r0, #4		@ SetShift
> +
> +	clz	r1, r3			@ WayShift
> +	add	r4, r3, #1		@ NumWays
> +1:	sub	r2, r2, #1		@ NumSets--
> +	mov	r3, r4			@ Temp = NumWays
> +2:	subs	r3, r3, #1		@ Temp--
> +	mov	r5, r3, lsl r1
> +	mov	r6, r2, lsl r0
> +	orr	r5, r5, r6		@ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
> +	mcr	p15, 0, r5, c7, c6, 2	@ Invalidate line
> +	bgt	2b
> +	cmp	r2, #0
> +	bgt	1b
> +	dsb
> +	mov	r0,#0
> +	mcr	p15,0,r0,c7,c5,0	/* Invalidate icache */
> +	isb
> +	mov	pc, lr
> +ENDPROC(v7_l1_cache_invalidate)

This function looks similar to v7_invalidate_l1 and v7_flush_icache_all
in arch/arm/mm/cache-v7.S if it is different and it is intended could
you please point it out in the comment.

> +/*
> + * Platform specific entry point for secondary CPUs.  This
> + * provides a "holding pen" into which all secondary cores are held
> + * until we're ready for them to initialise.
> + */
> +	__CPUINIT
> +ENTRY(bcm5301x_secondary_startup)
> +	/*
> +	 * Get hardware CPU id of ours
> +	 */
> +	mrc	p15, 0, r0, c0, c0, 5
> +	and	r0, r0, #15
> +	/*
> +	 * Wait on <pen_release> variable by physical address
> +	 * to contain our hardware CPU id
> +	 */
> +#ifdef CONFIG_SPARSEMEM
> +	ldr	r2, =(PAGE_OFFSET+SZ_128M)
> +	ldr	r1, =pen_release
> +	cmp	r1, r2
> +	bge	1f
> +	ldr	r2, =PAGE_OFFSET
> +	sub	r6, r1, r2
> +	b	2f
> +1:
> +	sub	r1, r1, r2
> +	ldr	r2, =PHYS_OFFSET2
> +	add	r6, r1, r2
> +2:
> +#else
> +	ldr	r6, =__virt_to_phys(pen_release)
> +#endif
> +pen:	ldr	r7, [r6]
> +	cmp	r7, r0
> +	bne	pen
> +	nop
> +	/*
> +	 * In case L1 cache has unpredictable contents at power-up
> +	 * clean its contents without flushing.
> +	 */
> +	bl	v7_l1_cache_invalidate
> +	nop
> +	/*
> +	 * we've been released from the holding pen: secondary_stack
> +	 * should now contain the SVC stack for this core
> +	 */
> +	b	secondary_startup
> +
> +ENDPROC(bcm5301x_secondary_startup)
> +	.ltorg
> diff --git a/arch/arm/mach-bcm/bcm5301x_smp.c b/arch/arm/mach-bcm/bcm5301x_smp.c
> new file mode 100644
> index 0000000..1a173ec
> --- /dev/null
> +++ b/arch/arm/mach-bcm/bcm5301x_smp.c
> @@ -0,0 +1,185 @@
> +/*
> + * Broadcom BCM470X / BCM5301X ARM platform code.
> + *
> + * Copyright (C) 2002 ARM Ltd.
> + * Copyright (C) 2015 Rafa? Mi?ecki <zajec5@gmail.com>
> + *
> + * Licensed under the GNU/GPL. See COPYING for details.
> + */
> +
> +#include <asm/cacheflush.h>
> +#include <asm/delay.h>
> +#include <asm/smp_scu.h>
> +
> +#include <linux/clockchips.h>
> +
> +/*
> + * There is a 1KB LUT located at 0xFFFF0400-0xFFFFFFFF, and its first entry
> + * is where the secondary entry point needs to be written
> +*/
> +#define SOC_ROM_BASE_PA		0xffff0000
> +#define SOC_ROM_LUT_OFF		0x400

Shouldn't this be given through device tree?

> +
> +/* ENTRY in bcm5301x_headsmp.S */
> +extern void bcm5301x_secondary_startup(void);

Shouldn't this go into some common header? I think we do not have such a
header so it is not that of a problem for now.

> +
> +static DEFINE_SPINLOCK(boot_lock);
> +
> +static void __cpuinit write_pen_release(int val)
> +{
> +	pen_release = val;
> +	/* Make sure this store is visible to other CPUs */
> +	smp_wmb();
> +	__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
> +	outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
> +}
> +
> +static void __init bcm5301x_smp_secondary_set_entry(void (*entry_point)(void))
> +{
> +	void __iomem *rombase = NULL;
> +	phys_addr_t lut_pa;
> +	u32 offset, mask;
> +	u32 val;
> +
> +	mask = (1UL << PAGE_SHIFT) - 1;
> +
> +	lut_pa = SOC_ROM_BASE_PA & ~mask;
> +	offset = SOC_ROM_BASE_PA &  mask;
> +	offset += SOC_ROM_LUT_OFF;
> +
> +	rombase = ioremap(lut_pa, PAGE_SIZE);
> +	if (!rombase)
> +		return;
> +	val = virt_to_phys(entry_point);
> +
> +	writel(val, rombase + offset);
> +
> +	smp_wmb();	/* probably not needed - io regs are not cached */
> +	dsb_sev();	/* Exit WFI */
> +	mb();
> +
> +	iounmap(rombase);
> +}
> +
> +static void __init bcm5301x_smp_prepare_cpus(unsigned int max_cpus)
> +{
> +	void __iomem *scu_base;
> +	unsigned int ncores;
> +
> +	if (!scu_a9_has_base()) {
> +		pr_warn("Unknown SCU base\n");
> +		return;
> +	}
> +
> +	scu_base = ioremap((phys_addr_t)scu_a9_get_base(), SZ_256);
> +	if (!scu_base) {
> +		pr_err("Failed to remap SCU\n");
> +		return;
> +	}
> +
> +	ncores = scu_get_core_count(scu_base);
> +	if (max_cpus > ncores) {
> +		unsigned int i;
> +
> +		pr_warn("Possible CPU mask exceeds available cores, reducing to %u\n",
> +			ncores);
> +		for (i = ncores - 1; i < max_cpus; i++)
> +			set_cpu_present(i, false);
> +		max_cpus = ncores;
> +	}
> +
> +	if (max_cpus > 1) {
> +		/* nobody is to be released from the pen yet */
> +		pen_release = -1;
> +
> +		/* Initialise the SCU */
> +		scu_enable(scu_base);
> +
> +		/* Let CPUs know where to start */
> +		bcm5301x_smp_secondary_set_entry(bcm5301x_secondary_startup);
> +	}
> +
> +	iounmap(scu_base);
> +}
> +
> +static void __cpuinit bcm5301x_smp_secondary_init(unsigned int cpu)
> +{
> +	trace_hardirqs_off();
> +
> +	/*
> +	 * let the primary processor know we're out of the
> +	 * pen, then head off into the C entry point
> +	 */
> +	write_pen_release(-1);
> +
> +	/*
> +	 * Synchronise with the boot thread.
> +	 */
> +	spin_lock(&boot_lock);
> +	spin_unlock(&boot_lock);
> +}
> +
> +static int __cpuinit bcm5301x_smp_boot_secondary(unsigned int cpu,
> +						 struct task_struct *idle)
> +{
> +	unsigned long timeout;
> +
> +	/*
> +	 * set synchronisation state between this boot processor
> +	 * and the secondary one
> +	 */
> +	spin_lock(&boot_lock);
> +
> +	/*
> +	 * The secondary processor is waiting to be released from
> +	 * the holding pen - release it, then wait for it to flag
> +	 * that it has been released by resetting pen_release.
> +	 *
> +	 * Note that "pen_release" is the hardware CPU ID, whereas
> +	 * "cpu" is Linux's internal ID.
> +	 */
> +	write_pen_release(cpu);
> +
> +	dsb_sev();
> +
> +	/*
> +	 * Timeout set on purpose in jiffies so that on slow processors
> +	 * that must also have low HZ it will wait longer.
> +	 */
> +	timeout = jiffies + (HZ * 10);
> +
> +	udelay(100);
> +
> +	/*
> +	 * If the secondary CPU was waiting on WFE, it should
> +	 * be already watching <pen_release>, or it could be
> +	 * waiting in WFI, send it an IPI to be sure it wakes.
> +	 */
> +	if (pen_release != -1)
> +		tick_broadcast(cpumask_of(cpu));
> +
> +	while (time_before(jiffies, timeout)) {
> +		smp_rmb();
> +		if (pen_release == -1)
> +			break;
> +
> +		udelay(10);
> +	}
> +
> +	/*
> +	 * now the secondary core is starting up let it run its
> +	 * calibrations, then wait for it to finish
> +	 */
> +	spin_unlock(&boot_lock);
> +
> +	return pen_release != -1 ? -ENOSYS : 0;
> +}
> +
> +static struct smp_operations bcm5301x_smp_ops __initdata = {
> +	.smp_prepare_cpus	= bcm5301x_smp_prepare_cpus,
> +	.smp_secondary_init	= bcm5301x_smp_secondary_init,
> +	.smp_boot_secondary	= bcm5301x_smp_boot_secondary,
> +};
> +
> +CPU_METHOD_OF_DECLARE(bcm5301x_smp, "brcm,bcm4708-smp",
> +		      &bcm5301x_smp_ops);
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH RFC] ARM: BCM5301X: Implement SMP support
  2015-02-10 20:32 [PATCH RFC] ARM: BCM5301X: Implement SMP support Rafał Miłecki
  2015-02-13 11:54 ` Hauke Mehrtens
@ 2015-02-13 12:29 ` Mark Rutland
  2015-02-19 22:32 ` [PATCH] " Rafał Miłecki
  2 siblings, 0 replies; 16+ messages in thread
From: Mark Rutland @ 2015-02-13 12:29 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Feb 10, 2015 at 08:32:55PM +0000, Rafa? Mi?ecki wrote:
> Signed-off-by: Rafa? Mi?ecki <zajec5@gmail.com>
> ---
>  arch/arm/boot/dts/bcm4708.dtsi       |   1 +
>  arch/arm/mach-bcm/Makefile           |   3 +
>  arch/arm/mach-bcm/bcm5301x_headsmp.S | 108 ++++++++++++++++++++
>  arch/arm/mach-bcm/bcm5301x_smp.c     | 185 +++++++++++++++++++++++++++++++++++
>  4 files changed, 297 insertions(+)
>  create mode 100644 arch/arm/mach-bcm/bcm5301x_headsmp.S
>  create mode 100644 arch/arm/mach-bcm/bcm5301x_smp.c
> 
> diff --git a/arch/arm/boot/dts/bcm4708.dtsi b/arch/arm/boot/dts/bcm4708.dtsi
> index 31141e8..ed4ddba 100644
> --- a/arch/arm/boot/dts/bcm4708.dtsi
> +++ b/arch/arm/boot/dts/bcm4708.dtsi
> @@ -15,6 +15,7 @@
>         cpus {
>                 #address-cells = <1>;
>                 #size-cells = <0>;
> +               enable-method = "brcm,bcm4708-smp";

This must be documented.

We really should be getting to the point where we have a small number of
standard(ish) enable methods rather than just adding a load of new IMP
DEF methods with pointless differences.

> 
>                 cpu at 0 {
>                         device_type = "cpu";
> diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
> index 4c38674..ca12727 100644
> --- a/arch/arm/mach-bcm/Makefile
> +++ b/arch/arm/mach-bcm/Makefile
> @@ -36,6 +36,9 @@ obj-$(CONFIG_ARCH_BCM2835)    += board_bcm2835.o
> 
>  # BCM5301X
>  obj-$(CONFIG_ARCH_BCM_5301X)   += bcm_5301x.o
> +ifeq ($(CONFIG_SMP),y)
> +obj-$(CONFIG_ARCH_BCM_5301X)   += bcm5301x_smp.o bcm5301x_headsmp.o
> +endif
> 
>  # BCM63XXx
>  obj-$(CONFIG_ARCH_BCM_63XX)    := bcm63xx.o
> diff --git a/arch/arm/mach-bcm/bcm5301x_headsmp.S b/arch/arm/mach-bcm/bcm5301x_headsmp.S
> new file mode 100644
> index 0000000..e8df65f
> --- /dev/null
> +++ b/arch/arm/mach-bcm/bcm5301x_headsmp.S
> @@ -0,0 +1,108 @@
> +/*
> + * Broadcom BCM470X / BCM5301X ARM platform code.
> + *
> + * Copyright 2003 - 2008 Broadcom Corporation
> + *
> + * Licensed under the GNU/GPL. See COPYING for details.
> + */
> +
> +#include <asm/memory.h>
> +
> +#include <linux/linkage.h>
> +#include <linux/init.h>
> +
> +#define __virt_to_phys(x)      ((x) - PAGE_OFFSET)

This does not looks like something there should be a custom
implementation of.

> +
> +/*
> + * v7_l1_cache_invalidate
> + *
> + * Invalidate contents of L1 cache without flushing its contents
> + * into outer cache and memory. This is needed when the contents
> + * of the cache are unpredictable after power-up.
> + *
> + * corrupts r0-r6
> + */
> +ENTRY(v7_l1_cache_invalidate)
> +       mov     r0, #0
> +       mcr     p15, 2, r0, c0, c0, 0   @ set cache level to 1
> +       mrc     p15, 1, r0, c0, c0, 0   @ read CLIDR

Isn't that the CCSIDR, not the CLIDR?

You need an ISB between CSSELR writes and CCSIDR reads.

> +
> +       ldr     r1, =0x7fff
> +       and     r2, r1, r0, lsr #13     @ get max # of index size
> +
> +       ldr     r1, =0x3ff
> +       and     r3, r1, r0, lsr #3      @ NumWays - 1
> +       add     r2, r2, #1              @ NumSets
> +
> +       and     r0, r0, #0x7
> +       add     r0, r0, #4              @ SetShift
> +
> +       clz     r1, r3                  @ WayShift
> +       add     r4, r3, #1              @ NumWays
> +1:     sub     r2, r2, #1              @ NumSets--
> +       mov     r3, r4                  @ Temp = NumWays
> +2:     subs    r3, r3, #1              @ Temp--
> +       mov     r5, r3, lsl r1
> +       mov     r6, r2, lsl r0
> +       orr     r5, r5, r6              @ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
> +       mcr     p15, 0, r5, c7, c6, 2   @ Invalidate line
> +       bgt     2b
> +       cmp     r2, #0
> +       bgt     1b
> +       dsb
> +       mov     r0,#0
> +       mcr     p15,0,r0,c7,c5,0        /* Invalidate icache */
> +       isb

SUrely you're missing a dsb after the i-cache maintenance?

> +       mov     pc, lr
> +ENDPROC(v7_l1_cache_invalidate)

This looks like a total mess. If you _really_ need this, factor it out
of the existing cache flush infrastructure. We don't need more broken
copies.

Do you have a guarantee that the CPU won't write back any of this
naturally before the invalidate is complete?

Is the CPU coherent at this point?

> +
> +/*
> + * Platform specific entry point for secondary CPUs.  This
> + * provides a "holding pen" into which all secondary cores are held
> + * until we're ready for them to initialise.
> + */
> +       __CPUINIT
> +ENTRY(bcm5301x_secondary_startup)
> +       /*
> +        * Get hardware CPU id of ours
> +        */
> +       mrc     p15, 0, r0, c0, c0, 5
> +       and     r0, r0, #15

Test all of the MPIDR.Aff* bits, please.

> +       /*
> +        * Wait on <pen_release> variable by physical address
> +        * to contain our hardware CPU id
> +        */
> +#ifdef CONFIG_SPARSEMEM
> +       ldr     r2, =(PAGE_OFFSET+SZ_128M)
> +       ldr     r1, =pen_release
> +       cmp     r1, r2
> +       bge     1f
> +       ldr     r2, =PAGE_OFFSET
> +       sub     r6, r1, r2
> +       b       2f
> +1:
> +       sub     r1, r1, r2
> +       ldr     r2, =PHYS_OFFSET2
> +       add     r6, r1, r2
> +2:

Huh? We really shouldn't have to care about SPARSEMEM in this kind of
code. I assume the fundamental issue here is your custom __virt_to_phys
implementation.

> +#else
> +       ldr     r6, =__virt_to_phys(pen_release)
> +#endif
> +pen:   ldr     r7, [r6]
> +       cmp     r7, r0
> +       bne     pen
> +       nop

Pointless nop?

> +       /*
> +        * In case L1 cache has unpredictable contents at power-up
> +        * clean its contents without flushing.
> +        */
> +       bl      v7_l1_cache_invalidate
> +       nop

Another pointless nop?

> +       /*
> +        * we've been released from the holding pen: secondary_stack
> +        * should now contain the SVC stack for this core
> +        */
> +       b       secondary_startup
> +
> +ENDPROC(bcm5301x_secondary_startup)
> +       .ltorg
> diff --git a/arch/arm/mach-bcm/bcm5301x_smp.c b/arch/arm/mach-bcm/bcm5301x_smp.c
> new file mode 100644
> index 0000000..1a173ec
> --- /dev/null
> +++ b/arch/arm/mach-bcm/bcm5301x_smp.c
> @@ -0,0 +1,185 @@
> +/*
> + * Broadcom BCM470X / BCM5301X ARM platform code.
> + *
> + * Copyright (C) 2002 ARM Ltd.
> + * Copyright (C) 2015 Rafa? Mi?ecki <zajec5@gmail.com>
> + *
> + * Licensed under the GNU/GPL. See COPYING for details.
> + */
> +
> +#include <asm/cacheflush.h>
> +#include <asm/delay.h>
> +#include <asm/smp_scu.h>
> +
> +#include <linux/clockchips.h>
> +
> +/*
> + * There is a 1KB LUT located at 0xFFFF0400-0xFFFFFFFF, and its first entry
> + * is where the secondary entry point needs to be written
> +*/
> +#define SOC_ROM_BASE_PA                0xffff0000
> +#define SOC_ROM_LUT_OFF                0x400

We shouldn't be hard-coding physical addresses; those should come from
the DT.

> +
> +/* ENTRY in bcm5301x_headsmp.S */
> +extern void bcm5301x_secondary_startup(void);
> +
> +static DEFINE_SPINLOCK(boot_lock);
> +
> +static void __cpuinit write_pen_release(int val)
> +{
> +       pen_release = val;
> +       /* Make sure this store is visible to other CPUs */
> +       smp_wmb();
> +       __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
> +       outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));

Surely we have some common infrastructure to perform this sort of
maintenance?

> +}
> +
> +static void __init bcm5301x_smp_secondary_set_entry(void (*entry_point)(void))
> +{
> +       void __iomem *rombase = NULL;
> +       phys_addr_t lut_pa;
> +       u32 offset, mask;
> +       u32 val;
> +
> +       mask = (1UL << PAGE_SHIFT) - 1;
> +
> +       lut_pa = SOC_ROM_BASE_PA & ~mask;
> +       offset = SOC_ROM_BASE_PA &  mask;
> +       offset += SOC_ROM_LUT_OFF;
> +
> +       rombase = ioremap(lut_pa, PAGE_SIZE);
> +       if (!rombase)
> +               return;
> +       val = virt_to_phys(entry_point);
> +
> +       writel(val, rombase + offset);
> +
> +       smp_wmb();      /* probably not needed - io regs are not cached */

Surely the following DSB is sufficient?

> +       dsb_sev();      /* Exit WFI */
> +       mb();

What's the mb for?

> +
> +       iounmap(rombase);
> +}
> +
> +static void __init bcm5301x_smp_prepare_cpus(unsigned int max_cpus)
> +{
> +       void __iomem *scu_base;
> +       unsigned int ncores;
> +
> +       if (!scu_a9_has_base()) {
> +               pr_warn("Unknown SCU base\n");
> +               return;
> +       }
> +
> +       scu_base = ioremap((phys_addr_t)scu_a9_get_base(), SZ_256);
> +       if (!scu_base) {
> +               pr_err("Failed to remap SCU\n");
> +               return;
> +       }
> +
> +       ncores = scu_get_core_count(scu_base);

Just read this from the DT as we do elsewhere.

> +       if (max_cpus > ncores) {
> +               unsigned int i;
> +
> +               pr_warn("Possible CPU mask exceeds available cores, reducing to %u\n",
> +                       ncores);
> +               for (i = ncores - 1; i < max_cpus; i++)
> +                       set_cpu_present(i, false);
> +               max_cpus = ncores;
> +       }
> +
> +       if (max_cpus > 1) {
> +               /* nobody is to be released from the pen yet */
> +               pen_release = -1;
> +
> +               /* Initialise the SCU */
> +               scu_enable(scu_base);
> +
> +               /* Let CPUs know where to start */
> +               bcm5301x_smp_secondary_set_entry(bcm5301x_secondary_startup);
> +       }
> +
> +       iounmap(scu_base);
> +}

[...]

> +static int __cpuinit bcm5301x_smp_boot_secondary(unsigned int cpu,
> +                                                struct task_struct *idle)
> +{
> +       unsigned long timeout;
> +
> +       /*
> +        * set synchronisation state between this boot processor
> +        * and the secondary one
> +        */
> +       spin_lock(&boot_lock);
> +
> +       /*
> +        * The secondary processor is waiting to be released from
> +        * the holding pen - release it, then wait for it to flag
> +        * that it has been released by resetting pen_release.
> +        *
> +        * Note that "pen_release" is the hardware CPU ID, whereas
> +        * "cpu" is Linux's internal ID.
> +        */
> +       write_pen_release(cpu);

As far as I can tell you're relying on the logical ID being equivalent
to MPDR.Aff0, which isn't necessarily true. Either use the physical ID
or use the actual logical ID.

> +
> +       dsb_sev();
> +
> +       /*
> +        * Timeout set on purpose in jiffies so that on slow processors
> +        * that must also have low HZ it will wait longer.
> +        */
> +       timeout = jiffies + (HZ * 10);
> +
> +       udelay(100);
> +
> +       /*
> +        * If the secondary CPU was waiting on WFE, it should
> +        * be already watching <pen_release>, or it could be
> +        * waiting in WFI, send it an IPI to be sure it wakes.
> +        */
> +       if (pen_release != -1)
> +               tick_broadcast(cpumask_of(cpu));

NAK. This is not what tick_broadcast is intended for.

If you need an IPI then send an IPI, don't piggyback on the timekeeping
infrastructure.

Mark.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH] ARM: BCM5301X: Implement SMP support
  2015-02-10 20:32 [PATCH RFC] ARM: BCM5301X: Implement SMP support Rafał Miłecki
  2015-02-13 11:54 ` Hauke Mehrtens
  2015-02-13 12:29 ` Mark Rutland
@ 2015-02-19 22:32 ` Rafał Miłecki
  2015-03-11 21:23   ` Rafał Miłecki
                     ` (2 more replies)
  2 siblings, 3 replies; 16+ messages in thread
From: Rafał Miłecki @ 2015-02-19 22:32 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Rafa? Mi?ecki <zajec5@gmail.com>
---
 Documentation/devicetree/bindings/arm/bcm4708.txt |  17 +++
 Documentation/devicetree/bindings/arm/cpus.txt    |   1 +
 arch/arm/boot/dts/bcm4708.dtsi                    |   5 +
 arch/arm/mach-bcm/Makefile                        |   3 +
 arch/arm/mach-bcm/bcm5301x_headsmp.S              |  46 +++++++
 arch/arm/mach-bcm/bcm5301x_smp.c                  | 160 ++++++++++++++++++++++
 6 files changed, 232 insertions(+)
 create mode 100644 arch/arm/mach-bcm/bcm5301x_headsmp.S
 create mode 100644 arch/arm/mach-bcm/bcm5301x_smp.c

diff --git a/Documentation/devicetree/bindings/arm/bcm4708.txt b/Documentation/devicetree/bindings/arm/bcm4708.txt
index 6b0f49f..be5abc0 100644
--- a/Documentation/devicetree/bindings/arm/bcm4708.txt
+++ b/Documentation/devicetree/bindings/arm/bcm4708.txt
@@ -6,3 +6,20 @@ Boards with the BCM4708 SoC shall have the following properties:
 Required root node property:
 
 compatible = "brcm,bcm4708";
+
+Optional sub-node properties:
+
+compatible = "brcm,bcm4708-sysram" SYSRAM for SMP bringup.
+		SMP-capable SoCs use part of the SYSRAM for storing
+		location of code to be executed by the extra cores.
+
+Example:
+
+	{
+		compatible = "brcm,bcm4708";
+
+		smp-sysram {
+			compatible = "brcm,bcm4708-sysram";
+			reg = <0xffff0000 0x1000>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
index b2aacbe..abeba52 100644
--- a/Documentation/devicetree/bindings/arm/cpus.txt
+++ b/Documentation/devicetree/bindings/arm/cpus.txt
@@ -188,6 +188,7 @@ nodes to be present and contain the properties described below.
 			  can be one of:
 			    "allwinner,sun6i-a31"
 			    "arm,psci"
+			    "brcm,bcm4708-smp"
 			    "brcm,brahma-b15"
 			    "marvell,armada-375-smp"
 			    "marvell,armada-380-smp"
diff --git a/arch/arm/boot/dts/bcm4708.dtsi b/arch/arm/boot/dts/bcm4708.dtsi
index 31141e8..9cf699d 100644
--- a/arch/arm/boot/dts/bcm4708.dtsi
+++ b/arch/arm/boot/dts/bcm4708.dtsi
@@ -15,6 +15,7 @@
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
+		enable-method = "brcm,bcm4708-smp";
 
 		cpu at 0 {
 			device_type = "cpu";
@@ -31,4 +32,8 @@
 		};
 	};
 
+	smp-sysram {
+		compatible = "brcm,bcm4708-sysram";
+		reg = <0xffff0000 0x1000>;
+	};
 };
diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
index 4c38674..ca12727 100644
--- a/arch/arm/mach-bcm/Makefile
+++ b/arch/arm/mach-bcm/Makefile
@@ -36,6 +36,9 @@ obj-$(CONFIG_ARCH_BCM2835)	+= board_bcm2835.o
 
 # BCM5301X
 obj-$(CONFIG_ARCH_BCM_5301X)	+= bcm_5301x.o
+ifeq ($(CONFIG_SMP),y)
+obj-$(CONFIG_ARCH_BCM_5301X)	+= bcm5301x_smp.o bcm5301x_headsmp.o
+endif
 
 # BCM63XXx
 obj-$(CONFIG_ARCH_BCM_63XX)	:= bcm63xx.o
diff --git a/arch/arm/mach-bcm/bcm5301x_headsmp.S b/arch/arm/mach-bcm/bcm5301x_headsmp.S
new file mode 100644
index 0000000..162d25a
--- /dev/null
+++ b/arch/arm/mach-bcm/bcm5301x_headsmp.S
@@ -0,0 +1,46 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ *
+ * Copyright (c) 2003 ARM Limited
+ * All Rights Reserved
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/linkage.h>
+
+/*
+ * BCM5301X specific entry point for secondary CPUs.
+ */
+ENTRY(bcm5301x_secondary_startup)
+	mrc	p15, 0, r0, c0, c0, 5
+	and	r0, r0, #15
+	adr	r4, 1f
+	ldmia	r4, {r5, r6}
+	sub	r4, r4, r5
+	add	r6, r6, r4
+pen:	ldr	r7, [r6]
+	cmp	r7, r0
+	bne	pen
+
+	/*
+	 * In case L1 cache has unpredictable contents at power-up
+	 * clean its contents without flushing.
+	 */
+	/* bl	v7_l1_cache_invalidate */
+	bl      v7_invalidate_l1
+
+	mov	r0,#0
+	mcr	p15,0,r0,c7,c5,0	/* Invalidate icache */
+	dsb
+	isb
+
+	/*
+	 * we've been released from the holding pen: secondary_stack
+	 * should now contain the SVC stack for this core
+	 */
+	b	secondary_startup
+ENDPROC(bcm5301x_secondary_startup)
+
+	.align 2
+1:	.long	.
+	.long	pen_release
diff --git a/arch/arm/mach-bcm/bcm5301x_smp.c b/arch/arm/mach-bcm/bcm5301x_smp.c
new file mode 100644
index 0000000..903cc0d
--- /dev/null
+++ b/arch/arm/mach-bcm/bcm5301x_smp.c
@@ -0,0 +1,160 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ *
+ * Copyright (C) 2002 ARM Ltd.
+ * Copyright (C) 2015 Rafa? Mi?ecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <asm/cacheflush.h>
+#include <asm/delay.h>
+#include <asm/smp_plat.h>
+#include <asm/smp_scu.h>
+
+#include <linux/clockchips.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#define SOC_ROM_LUT_OFF		0x400
+
+extern void bcm5301x_secondary_startup(void);
+
+static void __cpuinit write_pen_release(int val)
+{
+	pen_release = val;
+	smp_wmb();
+	sync_cache_w(&pen_release);
+}
+
+static DEFINE_SPINLOCK(boot_lock);
+
+static void __init bcm5301x_smp_secondary_set_entry(void (*entry_point)(void))
+{
+	void __iomem *sysram_base_addr = NULL;
+	struct device_node *node;
+
+	for_each_compatible_node(node, NULL, "brcm,bcm4708-sysram") {
+		if (!of_device_is_available(node))
+			continue;
+		sysram_base_addr = of_iomap(node, 0);
+		break;
+	}
+
+	if (!sysram_base_addr) {
+		pr_warn("Failed to map sysram\n");
+		return;
+	}
+
+	writel(virt_to_phys(entry_point), sysram_base_addr + SOC_ROM_LUT_OFF);
+
+	dsb_sev();	/* Exit WFI */
+	mb();		/* make sure write buffer is drained */
+
+	iounmap(sysram_base_addr);
+}
+
+static void __init bcm5301x_smp_prepare_cpus(unsigned int max_cpus)
+{
+	void __iomem *scu_base;
+
+	if (!scu_a9_has_base()) {
+		pr_warn("Unknown SCU base\n");
+		return;
+	}
+
+	scu_base = ioremap((phys_addr_t)scu_a9_get_base(), SZ_256);
+	if (!scu_base) {
+		pr_err("Failed to remap SCU\n");
+		return;
+	}
+
+	/* Initialise the SCU */
+	scu_enable(scu_base);
+
+	/* Let CPUs know where to start */
+	bcm5301x_smp_secondary_set_entry(bcm5301x_secondary_startup);
+
+	iounmap(scu_base);
+}
+
+static void __cpuinit bcm5301x_smp_secondary_init(unsigned int cpu)
+{
+	trace_hardirqs_off();
+
+	/*
+	 * let the primary processor know we're out of the
+	 * pen, then head off into the C entry point
+	 */
+	write_pen_release(-1);
+
+	/*
+	 * Synchronise with the boot thread.
+	 */
+	spin_lock(&boot_lock);
+	spin_unlock(&boot_lock);
+}
+
+static int __cpuinit bcm5301x_smp_boot_secondary(unsigned int cpu,
+						 struct task_struct *idle)
+{
+	unsigned long timeout;
+
+	/*
+	 * set synchronisation state between this boot processor
+	 * and the secondary one
+	 */
+	spin_lock(&boot_lock);
+
+	/*
+	 * The secondary processor is waiting to be released from
+	 * the holding pen - release it, then wait for it to flag
+	 * that it has been released by resetting pen_release.
+	 *
+	 * Note that "pen_release" is the hardware CPU ID, whereas
+	 * "cpu" is Linux's internal ID.
+	 */
+	write_pen_release(cpu_logical_map(cpu));
+
+	 /* Send the secondary CPU SEV */
+	dsb_sev();
+
+	udelay(100);
+
+	/*
+	 * Send the secondary CPU a soft interrupt, thereby causing
+	 * the boot monitor to read the system wide flags register,
+	 * and branch to the address found there.
+	 */
+	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+
+	/*
+	 * Timeout set on purpose in jiffies so that on slow processors
+	 * that must also have low HZ it will wait longer.
+	 */
+	timeout = jiffies + (HZ * 10);
+	while (time_before(jiffies, timeout)) {
+		smp_rmb();
+		if (pen_release == -1)
+			break;
+
+		udelay(10);
+	}
+
+	/*
+	 * now the secondary core is starting up let it run its
+	 * calibrations, then wait for it to finish
+	 */
+	spin_unlock(&boot_lock);
+
+	return pen_release != -1 ? -ENOSYS : 0;
+}
+
+static struct smp_operations bcm5301x_smp_ops __initdata = {
+	.smp_prepare_cpus	= bcm5301x_smp_prepare_cpus,
+	.smp_secondary_init	= bcm5301x_smp_secondary_init,
+	.smp_boot_secondary	= bcm5301x_smp_boot_secondary,
+};
+
+CPU_METHOD_OF_DECLARE(bcm5301x_smp, "brcm,bcm4708-smp",
+		      &bcm5301x_smp_ops);
-- 
1.8.4.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH] ARM: BCM5301X: Implement SMP support
  2015-02-19 22:32 ` [PATCH] " Rafał Miłecki
@ 2015-03-11 21:23   ` Rafał Miłecki
  2015-03-16 16:52   ` Florian Fainelli
  2015-03-22 13:20   ` [PATCH V2] " Rafał Miłecki
  2 siblings, 0 replies; 16+ messages in thread
From: Rafał Miłecki @ 2015-03-11 21:23 UTC (permalink / raw)
  To: linux-arm-kernel

On 19 February 2015 at 23:32, Rafa? Mi?ecki <zajec5@gmail.com> wrote:
> Signed-off-by: Rafa? Mi?ecki <zajec5@gmail.com>

So does it look good enough to send it in pull request? :)

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH] ARM: BCM5301X: Implement SMP support
  2015-02-19 22:32 ` [PATCH] " Rafał Miłecki
  2015-03-11 21:23   ` Rafał Miłecki
@ 2015-03-16 16:52   ` Florian Fainelli
  2015-03-22 13:20   ` [PATCH V2] " Rafał Miłecki
  2 siblings, 0 replies; 16+ messages in thread
From: Florian Fainelli @ 2015-03-16 16:52 UTC (permalink / raw)
  To: linux-arm-kernel

On 19/02/15 14:32, Rafa? Mi?ecki wrote:
> Signed-off-by: Rafa? Mi?ecki <zajec5@gmail.com>
> ---

[snip]

> +Optional sub-node properties:
> +
> +compatible = "brcm,bcm4708-sysram" SYSRAM for SMP bringup.
> +		SMP-capable SoCs use part of the SYSRAM for storing
> +		location of code to be executed by the extra cores.

Is this a regular kind of SRAM? If so, can you use "mmio-sram" as a
compatible fallback?

[snip]

> +
> +	/*
> +	 * In case L1 cache has unpredictable contents at power-up
> +	 * clean its contents without flushing.
> +	 */
> +	/* bl	v7_l1_cache_invalidate */

You can remove that comment now

> +	bl      v7_invalidate_l1
> +
> +	mov	r0,#0
> +	mcr	p15,0,r0,c7,c5,0	/* Invalidate icache */

For consistency with the previous lines, you would want to space operands.

> +	dsb
> +	isb
> +
> +	/*
> +	 * we've been released from the holding pen: secondary_stack
> +	 * should now contain the SVC stack for this core
> +	 */
> +	b	secondary_startup
> +ENDPROC(bcm5301x_secondary_startup)
> +
> +	.align 2
> +1:	.long	.
> +	.long	pen_release
> diff --git a/arch/arm/mach-bcm/bcm5301x_smp.c b/arch/arm/mach-bcm/bcm5301x_smp.c
> new file mode 100644
> index 0000000..903cc0d
> --- /dev/null
> +++ b/arch/arm/mach-bcm/bcm5301x_smp.c
> @@ -0,0 +1,160 @@
> +/*
> + * Broadcom BCM470X / BCM5301X ARM platform code.
> + *
> + * Copyright (C) 2002 ARM Ltd.
> + * Copyright (C) 2015 Rafa? Mi?ecki <zajec5@gmail.com>
> + *
> + * Licensed under the GNU/GPL. See COPYING for details.
> + */
> +
> +#include <asm/cacheflush.h>
> +#include <asm/delay.h>
> +#include <asm/smp_plat.h>
> +#include <asm/smp_scu.h>
> +
> +#include <linux/clockchips.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +
> +#define SOC_ROM_LUT_OFF		0x400
> +
> +extern void bcm5301x_secondary_startup(void);
> +
> +static void __cpuinit write_pen_release(int val)
> +{
> +	pen_release = val;
> +	smp_wmb();
> +	sync_cache_w(&pen_release);
> +}
> +
> +static DEFINE_SPINLOCK(boot_lock);
> +
> +static void __init bcm5301x_smp_secondary_set_entry(void (*entry_point)(void))
> +{
> +	void __iomem *sysram_base_addr = NULL;
> +	struct device_node *node;
> +
> +	for_each_compatible_node(node, NULL, "brcm,bcm4708-sysram") {
> +		if (!of_device_is_available(node))
> +			continue;
> +		sysram_base_addr = of_iomap(node, 0);
> +		break;
> +	}

How about of_find_compatible()? Do you expect more than one sysram node
in a DTS?
-- 
Florian

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH V2] ARM: BCM5301X: Implement SMP support
  2015-02-19 22:32 ` [PATCH] " Rafał Miłecki
  2015-03-11 21:23   ` Rafał Miłecki
  2015-03-16 16:52   ` Florian Fainelli
@ 2015-03-22 13:20   ` Rafał Miłecki
  2015-03-26 12:00     ` Russell King - ARM Linux
  2 siblings, 1 reply; 16+ messages in thread
From: Rafał Miłecki @ 2015-03-22 13:20 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Rafa? Mi?ecki <zajec5@gmail.com>
---
V2: Change code after receiving Florian's comments:
    1) Use "mmio-sram"
    2) Remove commented out ASM call
    3) Fix coding style in ASM
    4) Simplify finding OF node
---
 Documentation/devicetree/bindings/arm/bcm4708.txt |  24 ++++
 Documentation/devicetree/bindings/arm/cpus.txt    |   1 +
 arch/arm/boot/dts/bcm4708.dtsi                    |  13 ++
 arch/arm/mach-bcm/Makefile                        |   3 +
 arch/arm/mach-bcm/bcm5301x_headsmp.S              |  45 ++++++
 arch/arm/mach-bcm/bcm5301x_smp.c                  | 158 ++++++++++++++++++++++
 6 files changed, 244 insertions(+)
 create mode 100644 arch/arm/mach-bcm/bcm5301x_headsmp.S
 create mode 100644 arch/arm/mach-bcm/bcm5301x_smp.c

diff --git a/Documentation/devicetree/bindings/arm/bcm4708.txt b/Documentation/devicetree/bindings/arm/bcm4708.txt
index 6b0f49f..3dd0e9d 100644
--- a/Documentation/devicetree/bindings/arm/bcm4708.txt
+++ b/Documentation/devicetree/bindings/arm/bcm4708.txt
@@ -6,3 +6,27 @@ Boards with the BCM4708 SoC shall have the following properties:
 Required root node property:
 
 compatible = "brcm,bcm4708";
+
+Optional sub-node properties:
+
+compatible = "mmio-sram" for SRAM access with IO memory region
+		This is needed for SMP-capable SoCs which use part of
+		SRAM for storing location of code to be executed by the
+		extra cores.
+		SMP support requires another sub-node with compatible
+		property "brcm,bcm4708-sysram".
+
+Example:
+
+	sysram at ffff0000 {
+		compatible = "mmio-sram";
+		reg = <0xffff0000 0x10000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0 0xffff0000 0x10000>;
+
+		smp-sysram at 0 {
+			compatible = "brcm,bcm4708-sysram";
+			reg = <0x0 0x1000>;
+		};
+	};
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
index 6aa331d..3507ae3 100644
--- a/Documentation/devicetree/bindings/arm/cpus.txt
+++ b/Documentation/devicetree/bindings/arm/cpus.txt
@@ -189,6 +189,7 @@ nodes to be present and contain the properties described below.
 			  can be one of:
 			    "allwinner,sun6i-a31"
 			    "arm,psci"
+			    "brcm,bcm4708-smp"
 			    "brcm,brahma-b15"
 			    "marvell,armada-375-smp"
 			    "marvell,armada-380-smp"
diff --git a/arch/arm/boot/dts/bcm4708.dtsi b/arch/arm/boot/dts/bcm4708.dtsi
index 31141e8..c0af5cc 100644
--- a/arch/arm/boot/dts/bcm4708.dtsi
+++ b/arch/arm/boot/dts/bcm4708.dtsi
@@ -15,6 +15,7 @@
 	cpus {
 		#address-cells = <1>;
 		#size-cells = <0>;
+		enable-method = "brcm,bcm4708-smp";
 
 		cpu at 0 {
 			device_type = "cpu";
@@ -31,4 +32,16 @@
 		};
 	};
 
+	sysram at ffff0000 {
+		compatible = "mmio-sram";
+		reg = <0xffff0000 0x10000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0 0xffff0000 0x10000>;
+
+		smp-sysram at 0 {
+			compatible = "brcm,bcm4708-sysram";
+			reg = <0x0 0x1000>;
+		};
+	};
 };
diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
index 4c38674..ca12727 100644
--- a/arch/arm/mach-bcm/Makefile
+++ b/arch/arm/mach-bcm/Makefile
@@ -36,6 +36,9 @@ obj-$(CONFIG_ARCH_BCM2835)	+= board_bcm2835.o
 
 # BCM5301X
 obj-$(CONFIG_ARCH_BCM_5301X)	+= bcm_5301x.o
+ifeq ($(CONFIG_SMP),y)
+obj-$(CONFIG_ARCH_BCM_5301X)	+= bcm5301x_smp.o bcm5301x_headsmp.o
+endif
 
 # BCM63XXx
 obj-$(CONFIG_ARCH_BCM_63XX)	:= bcm63xx.o
diff --git a/arch/arm/mach-bcm/bcm5301x_headsmp.S b/arch/arm/mach-bcm/bcm5301x_headsmp.S
new file mode 100644
index 0000000..9ca8d20
--- /dev/null
+++ b/arch/arm/mach-bcm/bcm5301x_headsmp.S
@@ -0,0 +1,45 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ *
+ * Copyright (c) 2003 ARM Limited
+ * All Rights Reserved
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/linkage.h>
+
+/*
+ * BCM5301X specific entry point for secondary CPUs.
+ */
+ENTRY(bcm5301x_secondary_startup)
+	mrc	p15, 0, r0, c0, c0, 5
+	and	r0, r0, #15
+	adr	r4, 1f
+	ldmia	r4, {r5, r6}
+	sub	r4, r4, r5
+	add	r6, r6, r4
+pen:	ldr	r7, [r6]
+	cmp	r7, r0
+	bne	pen
+
+	/*
+	 * In case L1 cache has unpredictable contents at power-up
+	 * clean its contents without flushing.
+	 */
+	bl      v7_invalidate_l1
+
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c5, 0	/* Invalidate icache */
+	dsb
+	isb
+
+	/*
+	 * we've been released from the holding pen: secondary_stack
+	 * should now contain the SVC stack for this core
+	 */
+	b	secondary_startup
+ENDPROC(bcm5301x_secondary_startup)
+
+	.align 2
+1:	.long	.
+	.long	pen_release
diff --git a/arch/arm/mach-bcm/bcm5301x_smp.c b/arch/arm/mach-bcm/bcm5301x_smp.c
new file mode 100644
index 0000000..45d7089
--- /dev/null
+++ b/arch/arm/mach-bcm/bcm5301x_smp.c
@@ -0,0 +1,158 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ *
+ * Copyright (C) 2002 ARM Ltd.
+ * Copyright (C) 2015 Rafa? Mi?ecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <asm/cacheflush.h>
+#include <asm/delay.h>
+#include <asm/smp_plat.h>
+#include <asm/smp_scu.h>
+
+#include <linux/clockchips.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#define SOC_ROM_LUT_OFF		0x400
+
+extern void bcm5301x_secondary_startup(void);
+
+static void __cpuinit write_pen_release(int val)
+{
+	pen_release = val;
+	smp_wmb();
+	sync_cache_w(&pen_release);
+}
+
+static DEFINE_SPINLOCK(boot_lock);
+
+static void __init bcm5301x_smp_secondary_set_entry(void (*entry_point)(void))
+{
+	void __iomem *sysram_base_addr = NULL;
+	struct device_node *node;
+
+	node = of_find_compatible_node(NULL, NULL, "brcm,bcm4708-sysram");
+	if (!of_device_is_available(node))
+		return;
+
+	sysram_base_addr = of_iomap(node, 0);
+	if (!sysram_base_addr) {
+		pr_warn("Failed to map sysram\n");
+		return;
+	}
+
+	writel(virt_to_phys(entry_point), sysram_base_addr + SOC_ROM_LUT_OFF);
+
+	dsb_sev();	/* Exit WFI */
+	mb();		/* make sure write buffer is drained */
+
+	iounmap(sysram_base_addr);
+}
+
+static void __init bcm5301x_smp_prepare_cpus(unsigned int max_cpus)
+{
+	void __iomem *scu_base;
+
+	if (!scu_a9_has_base()) {
+		pr_warn("Unknown SCU base\n");
+		return;
+	}
+
+	scu_base = ioremap((phys_addr_t)scu_a9_get_base(), SZ_256);
+	if (!scu_base) {
+		pr_err("Failed to remap SCU\n");
+		return;
+	}
+
+	/* Initialise the SCU */
+	scu_enable(scu_base);
+
+	/* Let CPUs know where to start */
+	bcm5301x_smp_secondary_set_entry(bcm5301x_secondary_startup);
+
+	iounmap(scu_base);
+}
+
+static void __cpuinit bcm5301x_smp_secondary_init(unsigned int cpu)
+{
+	trace_hardirqs_off();
+
+	/*
+	 * let the primary processor know we're out of the
+	 * pen, then head off into the C entry point
+	 */
+	write_pen_release(-1);
+
+	/*
+	 * Synchronise with the boot thread.
+	 */
+	spin_lock(&boot_lock);
+	spin_unlock(&boot_lock);
+}
+
+static int __cpuinit bcm5301x_smp_boot_secondary(unsigned int cpu,
+						 struct task_struct *idle)
+{
+	unsigned long timeout;
+
+	/*
+	 * set synchronisation state between this boot processor
+	 * and the secondary one
+	 */
+	spin_lock(&boot_lock);
+
+	/*
+	 * The secondary processor is waiting to be released from
+	 * the holding pen - release it, then wait for it to flag
+	 * that it has been released by resetting pen_release.
+	 *
+	 * Note that "pen_release" is the hardware CPU ID, whereas
+	 * "cpu" is Linux's internal ID.
+	 */
+	write_pen_release(cpu_logical_map(cpu));
+
+	 /* Send the secondary CPU SEV */
+	dsb_sev();
+
+	udelay(100);
+
+	/*
+	 * Send the secondary CPU a soft interrupt, thereby causing
+	 * the boot monitor to read the system wide flags register,
+	 * and branch to the address found there.
+	 */
+	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+
+	/*
+	 * Timeout set on purpose in jiffies so that on slow processors
+	 * that must also have low HZ it will wait longer.
+	 */
+	timeout = jiffies + (HZ * 10);
+	while (time_before(jiffies, timeout)) {
+		smp_rmb();
+		if (pen_release == -1)
+			break;
+
+		udelay(10);
+	}
+
+	/*
+	 * now the secondary core is starting up let it run its
+	 * calibrations, then wait for it to finish
+	 */
+	spin_unlock(&boot_lock);
+
+	return pen_release != -1 ? -ENOSYS : 0;
+}
+
+static struct smp_operations bcm5301x_smp_ops __initdata = {
+	.smp_prepare_cpus	= bcm5301x_smp_prepare_cpus,
+	.smp_secondary_init	= bcm5301x_smp_secondary_init,
+	.smp_boot_secondary	= bcm5301x_smp_boot_secondary,
+};
+
+CPU_METHOD_OF_DECLARE(bcm5301x_smp, "brcm,bcm4708-smp",
+		      &bcm5301x_smp_ops);
-- 
1.8.4.5

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH V2] ARM: BCM5301X: Implement SMP support
  2015-03-22 13:20   ` [PATCH V2] " Rafał Miłecki
@ 2015-03-26 12:00     ` Russell King - ARM Linux
  2015-10-13 22:29       ` Hauke Mehrtens
  0 siblings, 1 reply; 16+ messages in thread
From: Russell King - ARM Linux @ 2015-03-26 12:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Mar 22, 2015 at 02:20:15PM +0100, Rafa? Mi?ecki wrote:
> +/*
> + * BCM5301X specific entry point for secondary CPUs.
> + */
> +ENTRY(bcm5301x_secondary_startup)
> +	mrc	p15, 0, r0, c0, c0, 5
> +	and	r0, r0, #15
> +	adr	r4, 1f
> +	ldmia	r4, {r5, r6}
> +	sub	r4, r4, r5
> +	add	r6, r6, r4
> +pen:	ldr	r7, [r6]
> +	cmp	r7, r0
> +	bne	pen
> +
> +	/*
> +	 * In case L1 cache has unpredictable contents at power-up
> +	 * clean its contents without flushing.
> +	 */
> +	bl      v7_invalidate_l1
> +
> +	mov	r0, #0
> +	mcr	p15, 0, r0, c7, c5, 0	/* Invalidate icache */
> +	dsb
> +	isb

So if your I-cache contains unpredictable contents, how do you execute
the code to this point?  Shouldn't the I-cache invalidate be the very
first instruction you execute followed by the dsb and isb (oh, and iirc
it ignores the value in the register).

In the case where a CPU has unpredictable contents at power up, the
ARM ARM requires that an implementation specific sequence is followed
to initialise the caches.  I doubt that such a sequence includes testing
a pen value.

> +	sysram_base_addr = of_iomap(node, 0);
> +	if (!sysram_base_addr) {
> +		pr_warn("Failed to map sysram\n");
> +		return;
> +	}
> +
> +	writel(virt_to_phys(entry_point), sysram_base_addr + SOC_ROM_LUT_OFF);
> +
> +	dsb_sev();	/* Exit WFI */

Which WFI?  This seems to imply that you have some kind of initial
firmware.  If so, that should be taking care of the cache initialisation,
not the kernel.

> +	mb();		/* make sure write buffer is drained */

writel() already ensures that.

> +	/*
> +	 * The secondary processor is waiting to be released from
> +	 * the holding pen - release it, then wait for it to flag
> +	 * that it has been released by resetting pen_release.
> +	 *
> +	 * Note that "pen_release" is the hardware CPU ID, whereas
> +	 * "cpu" is Linux's internal ID.
> +	 */
> +	write_pen_release(cpu_logical_map(cpu));
> +
> +	 /* Send the secondary CPU SEV */
> +	dsb_sev();

If you even need any of the pen code, if you're having to send a SEV here,
wouldn't having a WFE in the pen assembly loop above be a good idea?

-- 
FTTC broadband for 0.8mile line: currently at 10.5Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH V2] ARM: BCM5301X: Implement SMP support
  2015-03-26 12:00     ` Russell King - ARM Linux
@ 2015-10-13 22:29       ` Hauke Mehrtens
  2015-10-13 22:48         ` Ray Jui
  2015-10-15  8:17         ` Russell King - ARM Linux
  0 siblings, 2 replies; 16+ messages in thread
From: Hauke Mehrtens @ 2015-10-13 22:29 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

I tested this patch on my device now.

What does the loader do before Linux gets started on the second CPU and
what is ensured?

On 03/26/2015 01:00 PM, Russell King - ARM Linux wrote:
> On Sun, Mar 22, 2015 at 02:20:15PM +0100, Rafa? Mi?ecki wrote:
>> +/*
>> + * BCM5301X specific entry point for secondary CPUs.
>> + */
>> +ENTRY(bcm5301x_secondary_startup)
>> +	mrc	p15, 0, r0, c0, c0, 5
>> +	and	r0, r0, #15
>> +	adr	r4, 1f
>> +	ldmia	r4, {r5, r6}
>> +	sub	r4, r4, r5
>> +	add	r6, r6, r4
>> +pen:	ldr	r7, [r6]
>> +	cmp	r7, r0
>> +	bne	pen
>> +
>> +	/*
>> +	 * In case L1 cache has unpredictable contents at power-up
>> +	 * clean its contents without flushing.
>> +	 */
>> +	bl      v7_invalidate_l1
>> +
>> +	mov	r0, #0
>> +	mcr	p15, 0, r0, c7, c5, 0	/* Invalidate icache */
>> +	dsb
>> +	isb
> 
> So if your I-cache contains unpredictable contents, how do you execute
> the code to this point?  Shouldn't the I-cache invalidate be the very
> first instruction you execute followed by the dsb and isb (oh, and iirc
> it ignores the value in the register).
> 
> In the case where a CPU has unpredictable contents at power up, the
> ARM ARM requires that an implementation specific sequence is followed
> to initialise the caches.  I doubt that such a sequence includes testing
> a pen value.

When I remove the test for the pen value the CPU does not come up any
more, I get this log output:

[ 0.132292] CPU: Testing write buffer coherency: ok
[ 0.137635] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
[ 0.143675] Setting up static identity map for 0x82a0 - 0x82d4
[ 10.149786] CPU1: failed to boot: -38
[ 10.153651] Brought up 1 CPUs


This was caused just by removing the "cmp r7, r0" and "bne pen"
instructions.

With these instructions are added it works and I get this:

[    0.132329] CPU: Testing write buffer coherency: ok
[    0.137682] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
[    0.143708] Setting up static identity map for 0x82a0 - 0x82d4
[    0.189788] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
[    0.189892] Brought up 2 CPUs
[    0.198889] SMP: Total of 2 processors activated (3188.32 BogoMIPS).

Currently this is 100% reproducible.

Could it be that the second CPU needs some time till it is synchronised
correctly?

I do not know if and why the cache clearing is needed, I do not have
access to the SoC documentation or the ASIC/firmware developer.

> 
>> +	sysram_base_addr = of_iomap(node, 0);
>> +	if (!sysram_base_addr) {
>> +		pr_warn("Failed to map sysram\n");
>> +		return;
>> +	}
>> +
>> +	writel(virt_to_phys(entry_point), sysram_base_addr + SOC_ROM_LUT_OFF);
>> +
>> +	dsb_sev();	/* Exit WFI */
> 
> Which WFI?  This seems to imply that you have some kind of initial
> firmware.  If so, that should be taking care of the cache initialisation,
> not the kernel.
> 
>> +	mb();		/* make sure write buffer is drained */
> 
> writel() already ensures that.
> 
>> +	/*
>> +	 * The secondary processor is waiting to be released from
>> +	 * the holding pen - release it, then wait for it to flag
>> +	 * that it has been released by resetting pen_release.
>> +	 *
>> +	 * Note that "pen_release" is the hardware CPU ID, whereas
>> +	 * "cpu" is Linux's internal ID.
>> +	 */
>> +	write_pen_release(cpu_logical_map(cpu));
>> +
>> +	 /* Send the secondary CPU SEV */
>> +	dsb_sev();
> 
> If you even need any of the pen code, if you're having to send a SEV here,
> wouldn't having a WFE in the pen assembly loop above be a good idea?
> 


I have to read more on how WFE and co works.

Hauke

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH V2] ARM: BCM5301X: Implement SMP support
  2015-10-13 22:29       ` Hauke Mehrtens
@ 2015-10-13 22:48         ` Ray Jui
  2015-10-14 13:42           ` Kapil Hali
  2015-10-15  8:17         ` Russell King - ARM Linux
  1 sibling, 1 reply; 16+ messages in thread
From: Ray Jui @ 2015-10-13 22:48 UTC (permalink / raw)
  To: linux-arm-kernel

+ bcm-kernel-feedback-list.

Kapil, you might want to take a look at this. Not sure how this is
related to your SMP patches for NSP.

On 10/13/2015 3:29 PM, Hauke Mehrtens wrote:
> Hi,
> 
> I tested this patch on my device now.
> 
> What does the loader do before Linux gets started on the second CPU and
> what is ensured?
> 
> On 03/26/2015 01:00 PM, Russell King - ARM Linux wrote:
>> On Sun, Mar 22, 2015 at 02:20:15PM +0100, Rafa? Mi?ecki wrote:
>>> +/*
>>> + * BCM5301X specific entry point for secondary CPUs.
>>> + */
>>> +ENTRY(bcm5301x_secondary_startup)
>>> +	mrc	p15, 0, r0, c0, c0, 5
>>> +	and	r0, r0, #15
>>> +	adr	r4, 1f
>>> +	ldmia	r4, {r5, r6}
>>> +	sub	r4, r4, r5
>>> +	add	r6, r6, r4
>>> +pen:	ldr	r7, [r6]
>>> +	cmp	r7, r0
>>> +	bne	pen
>>> +
>>> +	/*
>>> +	 * In case L1 cache has unpredictable contents at power-up
>>> +	 * clean its contents without flushing.
>>> +	 */
>>> +	bl      v7_invalidate_l1
>>> +
>>> +	mov	r0, #0
>>> +	mcr	p15, 0, r0, c7, c5, 0	/* Invalidate icache */
>>> +	dsb
>>> +	isb
>>
>> So if your I-cache contains unpredictable contents, how do you execute
>> the code to this point?  Shouldn't the I-cache invalidate be the very
>> first instruction you execute followed by the dsb and isb (oh, and iirc
>> it ignores the value in the register).
>>
>> In the case where a CPU has unpredictable contents at power up, the
>> ARM ARM requires that an implementation specific sequence is followed
>> to initialise the caches.  I doubt that such a sequence includes testing
>> a pen value.
> 
> When I remove the test for the pen value the CPU does not come up any
> more, I get this log output:
> 
> [ 0.132292] CPU: Testing write buffer coherency: ok
> [ 0.137635] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
> [ 0.143675] Setting up static identity map for 0x82a0 - 0x82d4
> [ 10.149786] CPU1: failed to boot: -38
> [ 10.153651] Brought up 1 CPUs
> 
> 
> This was caused just by removing the "cmp r7, r0" and "bne pen"
> instructions.
> 
> With these instructions are added it works and I get this:
> 
> [    0.132329] CPU: Testing write buffer coherency: ok
> [    0.137682] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
> [    0.143708] Setting up static identity map for 0x82a0 - 0x82d4
> [    0.189788] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
> [    0.189892] Brought up 2 CPUs
> [    0.198889] SMP: Total of 2 processors activated (3188.32 BogoMIPS).
> 
> Currently this is 100% reproducible.
> 
> Could it be that the second CPU needs some time till it is synchronised
> correctly?
> 
> I do not know if and why the cache clearing is needed, I do not have
> access to the SoC documentation or the ASIC/firmware developer.
> 
>>
>>> +	sysram_base_addr = of_iomap(node, 0);
>>> +	if (!sysram_base_addr) {
>>> +		pr_warn("Failed to map sysram\n");
>>> +		return;
>>> +	}
>>> +
>>> +	writel(virt_to_phys(entry_point), sysram_base_addr + SOC_ROM_LUT_OFF);
>>> +
>>> +	dsb_sev();	/* Exit WFI */
>>
>> Which WFI?  This seems to imply that you have some kind of initial
>> firmware.  If so, that should be taking care of the cache initialisation,
>> not the kernel.
>>
>>> +	mb();		/* make sure write buffer is drained */
>>
>> writel() already ensures that.
>>
>>> +	/*
>>> +	 * The secondary processor is waiting to be released from
>>> +	 * the holding pen - release it, then wait for it to flag
>>> +	 * that it has been released by resetting pen_release.
>>> +	 *
>>> +	 * Note that "pen_release" is the hardware CPU ID, whereas
>>> +	 * "cpu" is Linux's internal ID.
>>> +	 */
>>> +	write_pen_release(cpu_logical_map(cpu));
>>> +
>>> +	 /* Send the secondary CPU SEV */
>>> +	dsb_sev();
>>
>> If you even need any of the pen code, if you're having to send a SEV here,
>> wouldn't having a WFE in the pen assembly loop above be a good idea?
>>
> 
> 
> I have to read more on how WFE and co works.
> 
> Hauke
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH V2] ARM: BCM5301X: Implement SMP support
  2015-10-13 22:48         ` Ray Jui
@ 2015-10-14 13:42           ` Kapil Hali
  2015-10-14 18:22             ` Hauke Mehrtens
  0 siblings, 1 reply; 16+ messages in thread
From: Kapil Hali @ 2015-10-14 13:42 UTC (permalink / raw)
  To: linux-arm-kernel



On 10/14/2015 4:18 AM, Ray Jui wrote:
> + bcm-kernel-feedback-list.
> 
> Kapil, you might want to take a look at this. Not sure how this is
> related to your SMP patches for NSP.

Ray, I don't have complete/other patch sets for this change. It would
be good if I get those patch sets as well or complete e-mail thread. 
I think if we have a cleaner solutions for SMP, we can consolidate 
the change required for NS and NSP. I have few points to add, which 
are inline in this e-mail.

> 
> On 10/13/2015 3:29 PM, Hauke Mehrtens wrote:
>> Hi,
>>
>> I tested this patch on my device now.
>>
>> What does the loader do before Linux gets started on the second CPU and
>> what is ensured?
>>
>> On 03/26/2015 01:00 PM, Russell King - ARM Linux wrote:
>>> On Sun, Mar 22, 2015 at 02:20:15PM +0100, Rafa? Mi?ecki wrote:
>>>> +/*
>>>> + * BCM5301X specific entry point for secondary CPUs.
>>>> + */
>>>> +ENTRY(bcm5301x_secondary_startup)
>>>> +	mrc	p15, 0, r0, c0, c0, 5
>>>> +	and	r0, r0, #15
>>>> +	adr	r4, 1f
>>>> +	ldmia	r4, {r5, r6}
>>>> +	sub	r4, r4, r5
>>>> +	add	r6, r6, r4
>>>> +pen:	ldr	r7, [r6]
>>>> +	cmp	r7, r0
>>>> +	bne	pen
>>>> +
>>>> +	/*
>>>> +	 * In case L1 cache has unpredictable contents at power-up
>>>> +	 * clean its contents without flushing.
>>>> +	 */
>>>> +	bl      v7_invalidate_l1
>>>> +
>>>> +	mov	r0, #0
>>>> +	mcr	p15, 0, r0, c7, c5, 0	/* Invalidate icache */
>>>> +	dsb
>>>> +	isb
>>>
>>> So if your I-cache contains unpredictable contents, how do you execute
>>> the code to this point?  Shouldn't the I-cache invalidate be the very
>>> first instruction you execute followed by the dsb and isb (oh, and iirc
>>> it ignores the value in the register).
>>>
>>> In the case where a CPU has unpredictable contents at power up, the
>>> ARM ARM requires that an implementation specific sequence is followed
>>> to initialise the caches.  I doubt that such a sequence includes testing
>>> a pen value.

Are you sure this is an issue of unpredictable L1 cache contents at
power-up? AFAIK, 5301X had an issue with secondary core initialization. 
Secondary core which waits on WFE would let it out of the pen as soon as the 
first spin_*lock executes. This was because of a BOOTROM bug in NS, so the
work around was to reset the address for the secondary processor to go back 
and wait for the signal from the primary core. This vector fixup is required
so that the secondary core doesn't start executing kernel instructions until 
we've patched its jump address during wakeup_secondary().

Also, v7 setup function should invalidate L1 cache and we should remove all
v7_invalidate_l1 calls in all headsmp.S in platform specific directories.

>>
>> When I remove the test for the pen value the CPU does not come up any
>> more, I get this log output:
>>
>> [ 0.132292] CPU: Testing write buffer coherency: ok
>> [ 0.137635] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
>> [ 0.143675] Setting up static identity map for 0x82a0 - 0x82d4
>> [ 10.149786] CPU1: failed to boot: -38
>> [ 10.153651] Brought up 1 CPUs
>>
>>
>> This was caused just by removing the "cmp r7, r0" and "bne pen"
>> instructions.
>>
>> With these instructions are added it works and I get this:
>>
>> [    0.132329] CPU: Testing write buffer coherency: ok
>> [    0.137682] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
>> [    0.143708] Setting up static identity map for 0x82a0 - 0x82d4
>> [    0.189788] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
>> [    0.189892] Brought up 2 CPUs
>> [    0.198889] SMP: Total of 2 processors activated (3188.32 BogoMIPS).
>>
>> Currently this is 100% reproducible.
>>
>> Could it be that the second CPU needs some time till it is synchronised
>> correctly?
>>
>> I do not know if and why the cache clearing is needed, I do not have
>> access to the SoC documentation or the ASIC/firmware developer.
>>
>>>
>>>> +	sysram_base_addr = of_iomap(node, 0);
>>>> +	if (!sysram_base_addr) {
>>>> +		pr_warn("Failed to map sysram\n");
>>>> +		return;
>>>> +	}
>>>> +
>>>> +	writel(virt_to_phys(entry_point), sysram_base_addr + SOC_ROM_LUT_OFF);
>>>> +
>>>> +	dsb_sev();	/* Exit WFI */
>>>
>>> Which WFI?  This seems to imply that you have some kind of initial
>>> firmware.  If so, that should be taking care of the cache initialisation,
>>> not the kernel.
>>>
>>>> +	mb();		/* make sure write buffer is drained */
>>>
>>> writel() already ensures that.
>>>
>>>> +	/*
>>>> +	 * The secondary processor is waiting to be released from
>>>> +	 * the holding pen - release it, then wait for it to flag
>>>> +	 * that it has been released by resetting pen_release.
>>>> +	 *
>>>> +	 * Note that "pen_release" is the hardware CPU ID, whereas
>>>> +	 * "cpu" is Linux's internal ID.
>>>> +	 */
>>>> +	write_pen_release(cpu_logical_map(cpu));
>>>> +
>>>> +	 /* Send the secondary CPU SEV */
>>>> +	dsb_sev();
>>>
>>> If you even need any of the pen code, if you're having to send a SEV here,
>>> wouldn't having a WFE in the pen assembly loop above be a good idea?
>>>
>>
>>
>> I have to read more on how WFE and co works.
>>
>> Hauke
>>

Thanks,
Kapil

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH V2] ARM: BCM5301X: Implement SMP support
  2015-10-14 13:42           ` Kapil Hali
@ 2015-10-14 18:22             ` Hauke Mehrtens
  2015-10-15 15:50               ` Kapil Hali
  2015-10-22 20:30               ` Jon Mason
  0 siblings, 2 replies; 16+ messages in thread
From: Hauke Mehrtens @ 2015-10-14 18:22 UTC (permalink / raw)
  To: linux-arm-kernel

On 10/14/2015 03:42 PM, Kapil Hali wrote:
> 
> 
> On 10/14/2015 4:18 AM, Ray Jui wrote:
>> + bcm-kernel-feedback-list.
>>
>> Kapil, you might want to take a look at this. Not sure how this is
>> related to your SMP patches for NSP.
> 
> Ray, I don't have complete/other patch sets for this change. It would
> be good if I get those patch sets as well or complete e-mail thread. 
> I think if we have a cleaner solutions for SMP, we can consolidate 
> the change required for NS and NSP. I have few points to add, which 
> are inline in this e-mail.

Hi Kapil,

the patch was posted on the arm mailing list:
http://lists.infradead.org/pipermail/linux-arm-kernel/2015-March/332690.html
but you can also find it in OpenWrt here:
https://dev.openwrt.org/browser/trunk/target/linux/bcm53xx/patches-4.1/131-ARM-BCM5301X-Implement-SMP-support.patch
It looks very similar to your approach so I assume we can use the same
SMP code for NS and NSP. I will look into your patches later on.

Hauke

> 
>>
>> On 10/13/2015 3:29 PM, Hauke Mehrtens wrote:
>>> Hi,
>>>
>>> I tested this patch on my device now.
>>>
>>> What does the loader do before Linux gets started on the second CPU and
>>> what is ensured?
>>>
>>> On 03/26/2015 01:00 PM, Russell King - ARM Linux wrote:
>>>> On Sun, Mar 22, 2015 at 02:20:15PM +0100, Rafa? Mi?ecki wrote:
>>>>> +/*
>>>>> + * BCM5301X specific entry point for secondary CPUs.
>>>>> + */
>>>>> +ENTRY(bcm5301x_secondary_startup)
>>>>> +	mrc	p15, 0, r0, c0, c0, 5
>>>>> +	and	r0, r0, #15
>>>>> +	adr	r4, 1f
>>>>> +	ldmia	r4, {r5, r6}
>>>>> +	sub	r4, r4, r5
>>>>> +	add	r6, r6, r4
>>>>> +pen:	ldr	r7, [r6]
>>>>> +	cmp	r7, r0
>>>>> +	bne	pen
>>>>> +
>>>>> +	/*
>>>>> +	 * In case L1 cache has unpredictable contents at power-up
>>>>> +	 * clean its contents without flushing.
>>>>> +	 */
>>>>> +	bl      v7_invalidate_l1
>>>>> +
>>>>> +	mov	r0, #0
>>>>> +	mcr	p15, 0, r0, c7, c5, 0	/* Invalidate icache */
>>>>> +	dsb
>>>>> +	isb
>>>>
>>>> So if your I-cache contains unpredictable contents, how do you execute
>>>> the code to this point?  Shouldn't the I-cache invalidate be the very
>>>> first instruction you execute followed by the dsb and isb (oh, and iirc
>>>> it ignores the value in the register).
>>>>
>>>> In the case where a CPU has unpredictable contents at power up, the
>>>> ARM ARM requires that an implementation specific sequence is followed
>>>> to initialise the caches.  I doubt that such a sequence includes testing
>>>> a pen value.
> 
> Are you sure this is an issue of unpredictable L1 cache contents at
> power-up? AFAIK, 5301X had an issue with secondary core initialization. 
> Secondary core which waits on WFE would let it out of the pen as soon as the 
> first spin_*lock executes. This was because of a BOOTROM bug in NS, so the
> work around was to reset the address for the secondary processor to go back 
> and wait for the signal from the primary core. This vector fixup is required
> so that the secondary core doesn't start executing kernel instructions until 
> we've patched its jump address during wakeup_secondary().
> 
> Also, v7 setup function should invalidate L1 cache and we should remove all
> v7_invalidate_l1 calls in all headsmp.S in platform specific directories.
> 
>>>
>>> When I remove the test for the pen value the CPU does not come up any
>>> more, I get this log output:
>>>
>>> [ 0.132292] CPU: Testing write buffer coherency: ok
>>> [ 0.137635] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
>>> [ 0.143675] Setting up static identity map for 0x82a0 - 0x82d4
>>> [ 10.149786] CPU1: failed to boot: -38
>>> [ 10.153651] Brought up 1 CPUs
>>>
>>>
>>> This was caused just by removing the "cmp r7, r0" and "bne pen"
>>> instructions.
>>>
>>> With these instructions are added it works and I get this:
>>>
>>> [    0.132329] CPU: Testing write buffer coherency: ok
>>> [    0.137682] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
>>> [    0.143708] Setting up static identity map for 0x82a0 - 0x82d4
>>> [    0.189788] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
>>> [    0.189892] Brought up 2 CPUs
>>> [    0.198889] SMP: Total of 2 processors activated (3188.32 BogoMIPS).
>>>
>>> Currently this is 100% reproducible.
>>>
>>> Could it be that the second CPU needs some time till it is synchronised
>>> correctly?
>>>
>>> I do not know if and why the cache clearing is needed, I do not have
>>> access to the SoC documentation or the ASIC/firmware developer.
>>>
>>>>
>>>>> +	sysram_base_addr = of_iomap(node, 0);
>>>>> +	if (!sysram_base_addr) {
>>>>> +		pr_warn("Failed to map sysram\n");
>>>>> +		return;
>>>>> +	}
>>>>> +
>>>>> +	writel(virt_to_phys(entry_point), sysram_base_addr + SOC_ROM_LUT_OFF);
>>>>> +
>>>>> +	dsb_sev();	/* Exit WFI */
>>>>
>>>> Which WFI?  This seems to imply that you have some kind of initial
>>>> firmware.  If so, that should be taking care of the cache initialisation,
>>>> not the kernel.
>>>>
>>>>> +	mb();		/* make sure write buffer is drained */
>>>>
>>>> writel() already ensures that.
>>>>
>>>>> +	/*
>>>>> +	 * The secondary processor is waiting to be released from
>>>>> +	 * the holding pen - release it, then wait for it to flag
>>>>> +	 * that it has been released by resetting pen_release.
>>>>> +	 *
>>>>> +	 * Note that "pen_release" is the hardware CPU ID, whereas
>>>>> +	 * "cpu" is Linux's internal ID.
>>>>> +	 */
>>>>> +	write_pen_release(cpu_logical_map(cpu));
>>>>> +
>>>>> +	 /* Send the secondary CPU SEV */
>>>>> +	dsb_sev();
>>>>
>>>> If you even need any of the pen code, if you're having to send a SEV here,
>>>> wouldn't having a WFE in the pen assembly loop above be a good idea?
>>>>
>>>
>>>
>>> I have to read more on how WFE and co works.
>>>
>>> Hauke
>>>
> 
> Thanks,
> Kapil
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH V2] ARM: BCM5301X: Implement SMP support
  2015-10-13 22:29       ` Hauke Mehrtens
  2015-10-13 22:48         ` Ray Jui
@ 2015-10-15  8:17         ` Russell King - ARM Linux
  1 sibling, 0 replies; 16+ messages in thread
From: Russell King - ARM Linux @ 2015-10-15  8:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Oct 14, 2015 at 12:29:19AM +0200, Hauke Mehrtens wrote:
> Hi,
> 
> I tested this patch on my device now.
> 
> What does the loader do before Linux gets started on the second CPU and
> what is ensured?
> 
> On 03/26/2015 01:00 PM, Russell King - ARM Linux wrote:
> > On Sun, Mar 22, 2015 at 02:20:15PM +0100, Rafa? Mi?ecki wrote:
> >> +/*
> >> + * BCM5301X specific entry point for secondary CPUs.
> >> + */
> >> +ENTRY(bcm5301x_secondary_startup)
> >> +	mrc	p15, 0, r0, c0, c0, 5
> >> +	and	r0, r0, #15
> >> +	adr	r4, 1f
> >> +	ldmia	r4, {r5, r6}
> >> +	sub	r4, r4, r5
> >> +	add	r6, r6, r4
> >> +pen:	ldr	r7, [r6]
> >> +	cmp	r7, r0
> >> +	bne	pen
> >> +
> >> +	/*
> >> +	 * In case L1 cache has unpredictable contents at power-up
> >> +	 * clean its contents without flushing.
> >> +	 */
> >> +	bl      v7_invalidate_l1
> >> +
> >> +	mov	r0, #0
> >> +	mcr	p15, 0, r0, c7, c5, 0	/* Invalidate icache */
> >> +	dsb
> >> +	isb
> > 
> > So if your I-cache contains unpredictable contents, how do you execute
> > the code to this point?  Shouldn't the I-cache invalidate be the very
> > first instruction you execute followed by the dsb and isb (oh, and iirc
> > it ignores the value in the register).
> > 
> > In the case where a CPU has unpredictable contents at power up, the
> > ARM ARM requires that an implementation specific sequence is followed
> > to initialise the caches.  I doubt that such a sequence includes testing
> > a pen value.

Things have changed in this area: ARMv7 CPU support now conforms with
other Linux CPU support, and we invalidate the caches prior to enabling
them.

However, I still come back to the point I said above, which you have not
addressed.  If the L1 cache contains unpredictable contents at power up,
how can you guarnatee that any code the CPU executes _is read by the CPU_
rather than the random contents of the L1 cache.

This isn't about the pen stuff.  It's about whether you can execute any
code reliably at this point.

There are several possibilities that the ARM ARM allows:
* the caches are reset at CPU reset and contain no valid or dirty lines
* the caches are not reset at CPU reset, but are not searched until
  the enable bits are set
* the caches are not reset at CPU reset, but are searched

The last case is the "special" case that requires a implementation
specific code to initialise them safely - but anyone implementing that
would be really silly to do so, so I doubt this is what you have.

So, I'd just get rid of that unnecessary cache flushing, especially as
I've said above, the ARMv7 CPU entry has been fixed to invalidate caches,
rather than flush dirty data (hence potentially random data in the second
case above) out to memory.

-- 
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH V2] ARM: BCM5301X: Implement SMP support
  2015-10-14 18:22             ` Hauke Mehrtens
@ 2015-10-15 15:50               ` Kapil Hali
  2015-10-22 20:30               ` Jon Mason
  1 sibling, 0 replies; 16+ messages in thread
From: Kapil Hali @ 2015-10-15 15:50 UTC (permalink / raw)
  To: linux-arm-kernel



On 10/14/2015 11:52 PM, Hauke Mehrtens wrote:
> On 10/14/2015 03:42 PM, Kapil Hali wrote:
>>
>>
>> On 10/14/2015 4:18 AM, Ray Jui wrote:
>>> + bcm-kernel-feedback-list.
>>>
>>> Kapil, you might want to take a look at this. Not sure how this is
>>> related to your SMP patches for NSP.
>>
>> Ray, I don't have complete/other patch sets for this change. It would
>> be good if I get those patch sets as well or complete e-mail thread. 
>> I think if we have a cleaner solutions for SMP, we can consolidate 
>> the change required for NS and NSP. I have few points to add, which 
>> are inline in this e-mail.
> 
> Hi Kapil,
> 
> the patch was posted on the arm mailing list:
> http://lists.infradead.org/pipermail/linux-arm-kernel/2015-March/332690.html
> but you can also find it in OpenWrt here:
> https://dev.openwrt.org/browser/trunk/target/linux/bcm53xx/patches-4.1/131-ARM-BCM5301X-Implement-SMP-support.patch
> It looks very similar to your approach so I assume we can use the same
> SMP code for NS and NSP. I will look into your patches later on.

You are right, we can use the common SMP code for NS and NSP, however, I am
only concerned about the secondary_startup() function in case of NS as is 
being discussed in the e-mail chain.
As there are multiple versions of NS SoC, and AFAIK, some of those have 
anomalous BOOTROM. We should have a cleaner generic solution which can be 
used for both NS and NSP.

> 
> Hauke
> 
>>
>>>
>>> On 10/13/2015 3:29 PM, Hauke Mehrtens wrote:
>>>> Hi,
>>>>
>>>> I tested this patch on my device now.
>>>>
>>>> What does the loader do before Linux gets started on the second CPU and
>>>> what is ensured?
>>>>
>>>> On 03/26/2015 01:00 PM, Russell King - ARM Linux wrote:
>>>>> On Sun, Mar 22, 2015 at 02:20:15PM +0100, Rafa? Mi?ecki wrote:
>>>>>> +/*
>>>>>> + * BCM5301X specific entry point for secondary CPUs.
>>>>>> + */
>>>>>> +ENTRY(bcm5301x_secondary_startup)
>>>>>> +	mrc	p15, 0, r0, c0, c0, 5
>>>>>> +	and	r0, r0, #15
>>>>>> +	adr	r4, 1f
>>>>>> +	ldmia	r4, {r5, r6}
>>>>>> +	sub	r4, r4, r5
>>>>>> +	add	r6, r6, r4
>>>>>> +pen:	ldr	r7, [r6]
>>>>>> +	cmp	r7, r0
>>>>>> +	bne	pen
>>>>>> +
>>>>>> +	/*
>>>>>> +	 * In case L1 cache has unpredictable contents at power-up
>>>>>> +	 * clean its contents without flushing.
>>>>>> +	 */
>>>>>> +	bl      v7_invalidate_l1
>>>>>> +
>>>>>> +	mov	r0, #0
>>>>>> +	mcr	p15, 0, r0, c7, c5, 0	/* Invalidate icache */
>>>>>> +	dsb
>>>>>> +	isb
>>>>>
>>>>> So if your I-cache contains unpredictable contents, how do you execute
>>>>> the code to this point?  Shouldn't the I-cache invalidate be the very
>>>>> first instruction you execute followed by the dsb and isb (oh, and iirc
>>>>> it ignores the value in the register).
>>>>>
>>>>> In the case where a CPU has unpredictable contents at power up, the
>>>>> ARM ARM requires that an implementation specific sequence is followed
>>>>> to initialise the caches.  I doubt that such a sequence includes testing
>>>>> a pen value.
>>
>> Are you sure this is an issue of unpredictable L1 cache contents at
>> power-up? AFAIK, 5301X had an issue with secondary core initialization. 
>> Secondary core which waits on WFE would let it out of the pen as soon as the 
>> first spin_*lock executes. This was because of a BOOTROM bug in NS, so the
>> work around was to reset the address for the secondary processor to go back 
>> and wait for the signal from the primary core. This vector fixup is required
>> so that the secondary core doesn't start executing kernel instructions until 
>> we've patched its jump address during wakeup_secondary().
>>
>> Also, v7 setup function should invalidate L1 cache and we should remove all
>> v7_invalidate_l1 calls in all headsmp.S in platform specific directories.
>>
>>>>
>>>> When I remove the test for the pen value the CPU does not come up any
>>>> more, I get this log output:
>>>>
>>>> [ 0.132292] CPU: Testing write buffer coherency: ok
>>>> [ 0.137635] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
>>>> [ 0.143675] Setting up static identity map for 0x82a0 - 0x82d4
>>>> [ 10.149786] CPU1: failed to boot: -38
>>>> [ 10.153651] Brought up 1 CPUs
>>>>
>>>>
>>>> This was caused just by removing the "cmp r7, r0" and "bne pen"
>>>> instructions.
>>>>
>>>> With these instructions are added it works and I get this:
>>>>
>>>> [    0.132329] CPU: Testing write buffer coherency: ok
>>>> [    0.137682] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
>>>> [    0.143708] Setting up static identity map for 0x82a0 - 0x82d4
>>>> [    0.189788] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
>>>> [    0.189892] Brought up 2 CPUs
>>>> [    0.198889] SMP: Total of 2 processors activated (3188.32 BogoMIPS).
>>>>
>>>> Currently this is 100% reproducible.
>>>>
>>>> Could it be that the second CPU needs some time till it is synchronised
>>>> correctly?
>>>>
>>>> I do not know if and why the cache clearing is needed, I do not have
>>>> access to the SoC documentation or the ASIC/firmware developer.
>>>>
>>>>>
>>>>>> +	sysram_base_addr = of_iomap(node, 0);
>>>>>> +	if (!sysram_base_addr) {
>>>>>> +		pr_warn("Failed to map sysram\n");
>>>>>> +		return;
>>>>>> +	}
>>>>>> +
>>>>>> +	writel(virt_to_phys(entry_point), sysram_base_addr + SOC_ROM_LUT_OFF);
>>>>>> +
>>>>>> +	dsb_sev();	/* Exit WFI */
>>>>>
>>>>> Which WFI?  This seems to imply that you have some kind of initial
>>>>> firmware.  If so, that should be taking care of the cache initialisation,
>>>>> not the kernel.
>>>>>
>>>>>> +	mb();		/* make sure write buffer is drained */
>>>>>
>>>>> writel() already ensures that.
>>>>>
>>>>>> +	/*
>>>>>> +	 * The secondary processor is waiting to be released from
>>>>>> +	 * the holding pen - release it, then wait for it to flag
>>>>>> +	 * that it has been released by resetting pen_release.
>>>>>> +	 *
>>>>>> +	 * Note that "pen_release" is the hardware CPU ID, whereas
>>>>>> +	 * "cpu" is Linux's internal ID.
>>>>>> +	 */
>>>>>> +	write_pen_release(cpu_logical_map(cpu));
>>>>>> +
>>>>>> +	 /* Send the secondary CPU SEV */
>>>>>> +	dsb_sev();
>>>>>
>>>>> If you even need any of the pen code, if you're having to send a SEV here,
>>>>> wouldn't having a WFE in the pen assembly loop above be a good idea?
>>>>>
>>>>
>>>>
>>>> I have to read more on how WFE and co works.
>>>>
>>>> Hauke
>>>>
>>
>> Thanks,
>> Kapil
>>
> 

Thanks,
Kapil

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH V2] ARM: BCM5301X: Implement SMP support
  2015-10-14 18:22             ` Hauke Mehrtens
  2015-10-15 15:50               ` Kapil Hali
@ 2015-10-22 20:30               ` Jon Mason
  2015-10-23 22:36                 ` Hauke Mehrtens
  1 sibling, 1 reply; 16+ messages in thread
From: Jon Mason @ 2015-10-22 20:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Oct 14, 2015 at 08:22:54PM +0200, Hauke Mehrtens wrote:
> On 10/14/2015 03:42 PM, Kapil Hali wrote:
> > 
> > 
> > On 10/14/2015 4:18 AM, Ray Jui wrote:
> >> + bcm-kernel-feedback-list.
> >>
> >> Kapil, you might want to take a look at this. Not sure how this is
> >> related to your SMP patches for NSP.
> > 
> > Ray, I don't have complete/other patch sets for this change. It would
> > be good if I get those patch sets as well or complete e-mail thread. 
> > I think if we have a cleaner solutions for SMP, we can consolidate 
> > the change required for NS and NSP. I have few points to add, which 
> > are inline in this e-mail.
> 
> Hi Kapil,
> 
> the patch was posted on the arm mailing list:
> http://lists.infradead.org/pipermail/linux-arm-kernel/2015-March/332690.html
> but you can also find it in OpenWrt here:
> https://dev.openwrt.org/browser/trunk/target/linux/bcm53xx/patches-4.1/131-ARM-BCM5301X-Implement-SMP-support.patch
> It looks very similar to your approach so I assume we can use the same
> SMP code for NS and NSP. I will look into your patches later on.

Hello Hauke,
With my last patch (https://lkml.org/lkml/2015/10/15/690), SMP on 4708
is working with the NSP SMP patch
(https://lkml.org/lkml/2015/10/14/769).  That patch does not have the
issues that Russell King was mentioning in this patch series (and
supports more SoCs).  Have you had a chance to verify that it works
for you?

Thanks,
Jon

> 
> Hauke
> 
> > 
> >>
> >> On 10/13/2015 3:29 PM, Hauke Mehrtens wrote:
> >>> Hi,
> >>>
> >>> I tested this patch on my device now.
> >>>
> >>> What does the loader do before Linux gets started on the second CPU and
> >>> what is ensured?
> >>>
> >>> On 03/26/2015 01:00 PM, Russell King - ARM Linux wrote:
> >>>> On Sun, Mar 22, 2015 at 02:20:15PM +0100, Rafa? Mi?ecki wrote:
> >>>>> +/*
> >>>>> + * BCM5301X specific entry point for secondary CPUs.
> >>>>> + */
> >>>>> +ENTRY(bcm5301x_secondary_startup)
> >>>>> +	mrc	p15, 0, r0, c0, c0, 5
> >>>>> +	and	r0, r0, #15
> >>>>> +	adr	r4, 1f
> >>>>> +	ldmia	r4, {r5, r6}
> >>>>> +	sub	r4, r4, r5
> >>>>> +	add	r6, r6, r4
> >>>>> +pen:	ldr	r7, [r6]
> >>>>> +	cmp	r7, r0
> >>>>> +	bne	pen
> >>>>> +
> >>>>> +	/*
> >>>>> +	 * In case L1 cache has unpredictable contents at power-up
> >>>>> +	 * clean its contents without flushing.
> >>>>> +	 */
> >>>>> +	bl      v7_invalidate_l1
> >>>>> +
> >>>>> +	mov	r0, #0
> >>>>> +	mcr	p15, 0, r0, c7, c5, 0	/* Invalidate icache */
> >>>>> +	dsb
> >>>>> +	isb
> >>>>
> >>>> So if your I-cache contains unpredictable contents, how do you execute
> >>>> the code to this point?  Shouldn't the I-cache invalidate be the very
> >>>> first instruction you execute followed by the dsb and isb (oh, and iirc
> >>>> it ignores the value in the register).
> >>>>
> >>>> In the case where a CPU has unpredictable contents at power up, the
> >>>> ARM ARM requires that an implementation specific sequence is followed
> >>>> to initialise the caches.  I doubt that such a sequence includes testing
> >>>> a pen value.
> > 
> > Are you sure this is an issue of unpredictable L1 cache contents at
> > power-up? AFAIK, 5301X had an issue with secondary core initialization. 
> > Secondary core which waits on WFE would let it out of the pen as soon as the 
> > first spin_*lock executes. This was because of a BOOTROM bug in NS, so the
> > work around was to reset the address for the secondary processor to go back 
> > and wait for the signal from the primary core. This vector fixup is required
> > so that the secondary core doesn't start executing kernel instructions until 
> > we've patched its jump address during wakeup_secondary().
> > 
> > Also, v7 setup function should invalidate L1 cache and we should remove all
> > v7_invalidate_l1 calls in all headsmp.S in platform specific directories.
> > 
> >>>
> >>> When I remove the test for the pen value the CPU does not come up any
> >>> more, I get this log output:
> >>>
> >>> [ 0.132292] CPU: Testing write buffer coherency: ok
> >>> [ 0.137635] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
> >>> [ 0.143675] Setting up static identity map for 0x82a0 - 0x82d4
> >>> [ 10.149786] CPU1: failed to boot: -38
> >>> [ 10.153651] Brought up 1 CPUs
> >>>
> >>>
> >>> This was caused just by removing the "cmp r7, r0" and "bne pen"
> >>> instructions.
> >>>
> >>> With these instructions are added it works and I get this:
> >>>
> >>> [    0.132329] CPU: Testing write buffer coherency: ok
> >>> [    0.137682] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
> >>> [    0.143708] Setting up static identity map for 0x82a0 - 0x82d4
> >>> [    0.189788] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
> >>> [    0.189892] Brought up 2 CPUs
> >>> [    0.198889] SMP: Total of 2 processors activated (3188.32 BogoMIPS).
> >>>
> >>> Currently this is 100% reproducible.
> >>>
> >>> Could it be that the second CPU needs some time till it is synchronised
> >>> correctly?
> >>>
> >>> I do not know if and why the cache clearing is needed, I do not have
> >>> access to the SoC documentation or the ASIC/firmware developer.
> >>>
> >>>>
> >>>>> +	sysram_base_addr = of_iomap(node, 0);
> >>>>> +	if (!sysram_base_addr) {
> >>>>> +		pr_warn("Failed to map sysram\n");
> >>>>> +		return;
> >>>>> +	}
> >>>>> +
> >>>>> +	writel(virt_to_phys(entry_point), sysram_base_addr + SOC_ROM_LUT_OFF);
> >>>>> +
> >>>>> +	dsb_sev();	/* Exit WFI */
> >>>>
> >>>> Which WFI?  This seems to imply that you have some kind of initial
> >>>> firmware.  If so, that should be taking care of the cache initialisation,
> >>>> not the kernel.
> >>>>
> >>>>> +	mb();		/* make sure write buffer is drained */
> >>>>
> >>>> writel() already ensures that.
> >>>>
> >>>>> +	/*
> >>>>> +	 * The secondary processor is waiting to be released from
> >>>>> +	 * the holding pen - release it, then wait for it to flag
> >>>>> +	 * that it has been released by resetting pen_release.
> >>>>> +	 *
> >>>>> +	 * Note that "pen_release" is the hardware CPU ID, whereas
> >>>>> +	 * "cpu" is Linux's internal ID.
> >>>>> +	 */
> >>>>> +	write_pen_release(cpu_logical_map(cpu));
> >>>>> +
> >>>>> +	 /* Send the secondary CPU SEV */
> >>>>> +	dsb_sev();
> >>>>
> >>>> If you even need any of the pen code, if you're having to send a SEV here,
> >>>> wouldn't having a WFE in the pen assembly loop above be a good idea?
> >>>>
> >>>
> >>>
> >>> I have to read more on how WFE and co works.
> >>>
> >>> Hauke
> >>>
> > 
> > Thanks,
> > Kapil
> > 
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH V2] ARM: BCM5301X: Implement SMP support
  2015-10-22 20:30               ` Jon Mason
@ 2015-10-23 22:36                 ` Hauke Mehrtens
  0 siblings, 0 replies; 16+ messages in thread
From: Hauke Mehrtens @ 2015-10-23 22:36 UTC (permalink / raw)
  To: linux-arm-kernel

On 10/22/2015 10:30 PM, Jon Mason wrote:
> On Wed, Oct 14, 2015 at 08:22:54PM +0200, Hauke Mehrtens wrote:
>> On 10/14/2015 03:42 PM, Kapil Hali wrote:
>>>
>>>
>>> On 10/14/2015 4:18 AM, Ray Jui wrote:
>>>> + bcm-kernel-feedback-list.
>>>>
>>>> Kapil, you might want to take a look at this. Not sure how this is
>>>> related to your SMP patches for NSP.
>>>
>>> Ray, I don't have complete/other patch sets for this change. It would
>>> be good if I get those patch sets as well or complete e-mail thread. 
>>> I think if we have a cleaner solutions for SMP, we can consolidate 
>>> the change required for NS and NSP. I have few points to add, which 
>>> are inline in this e-mail.
>>
>> Hi Kapil,
>>
>> the patch was posted on the arm mailing list:
>> http://lists.infradead.org/pipermail/linux-arm-kernel/2015-March/332690.html
>> but you can also find it in OpenWrt here:
>> https://dev.openwrt.org/browser/trunk/target/linux/bcm53xx/patches-4.1/131-ARM-BCM5301X-Implement-SMP-support.patch
>> It looks very similar to your approach so I assume we can use the same
>> SMP code for NS and NSP. I will look into your patches later on.
> 
> Hello Hauke,
> With my last patch (https://lkml.org/lkml/2015/10/15/690), SMP on 4708
> is working with the NSP SMP patch
> (https://lkml.org/lkml/2015/10/14/769).  That patch does not have the
> issues that Russell King was mentioning in this patch series (and
> supports more SoCs).  Have you had a chance to verify that it works
> for you?

Yes I tried it and it works for me. I have already added it to OpenWrt:
https://dev.openwrt.org/changeset/47247

Hauke

> 
> Thanks,
> Jon
> 
>>
>> Hauke
>>
>>>
>>>>
>>>> On 10/13/2015 3:29 PM, Hauke Mehrtens wrote:
>>>>> Hi,
>>>>>
>>>>> I tested this patch on my device now.
>>>>>
>>>>> What does the loader do before Linux gets started on the second CPU and
>>>>> what is ensured?
>>>>>
>>>>> On 03/26/2015 01:00 PM, Russell King - ARM Linux wrote:
>>>>>> On Sun, Mar 22, 2015 at 02:20:15PM +0100, Rafa? Mi?ecki wrote:
>>>>>>> +/*
>>>>>>> + * BCM5301X specific entry point for secondary CPUs.
>>>>>>> + */
>>>>>>> +ENTRY(bcm5301x_secondary_startup)
>>>>>>> +	mrc	p15, 0, r0, c0, c0, 5
>>>>>>> +	and	r0, r0, #15
>>>>>>> +	adr	r4, 1f
>>>>>>> +	ldmia	r4, {r5, r6}
>>>>>>> +	sub	r4, r4, r5
>>>>>>> +	add	r6, r6, r4
>>>>>>> +pen:	ldr	r7, [r6]
>>>>>>> +	cmp	r7, r0
>>>>>>> +	bne	pen
>>>>>>> +
>>>>>>> +	/*
>>>>>>> +	 * In case L1 cache has unpredictable contents at power-up
>>>>>>> +	 * clean its contents without flushing.
>>>>>>> +	 */
>>>>>>> +	bl      v7_invalidate_l1
>>>>>>> +
>>>>>>> +	mov	r0, #0
>>>>>>> +	mcr	p15, 0, r0, c7, c5, 0	/* Invalidate icache */
>>>>>>> +	dsb
>>>>>>> +	isb
>>>>>>
>>>>>> So if your I-cache contains unpredictable contents, how do you execute
>>>>>> the code to this point?  Shouldn't the I-cache invalidate be the very
>>>>>> first instruction you execute followed by the dsb and isb (oh, and iirc
>>>>>> it ignores the value in the register).
>>>>>>
>>>>>> In the case where a CPU has unpredictable contents at power up, the
>>>>>> ARM ARM requires that an implementation specific sequence is followed
>>>>>> to initialise the caches.  I doubt that such a sequence includes testing
>>>>>> a pen value.
>>>
>>> Are you sure this is an issue of unpredictable L1 cache contents at
>>> power-up? AFAIK, 5301X had an issue with secondary core initialization. 
>>> Secondary core which waits on WFE would let it out of the pen as soon as the 
>>> first spin_*lock executes. This was because of a BOOTROM bug in NS, so the
>>> work around was to reset the address for the secondary processor to go back 
>>> and wait for the signal from the primary core. This vector fixup is required
>>> so that the secondary core doesn't start executing kernel instructions until 
>>> we've patched its jump address during wakeup_secondary().
>>>
>>> Also, v7 setup function should invalidate L1 cache and we should remove all
>>> v7_invalidate_l1 calls in all headsmp.S in platform specific directories.
>>>
>>>>>
>>>>> When I remove the test for the pen value the CPU does not come up any
>>>>> more, I get this log output:
>>>>>
>>>>> [ 0.132292] CPU: Testing write buffer coherency: ok
>>>>> [ 0.137635] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
>>>>> [ 0.143675] Setting up static identity map for 0x82a0 - 0x82d4
>>>>> [ 10.149786] CPU1: failed to boot: -38
>>>>> [ 10.153651] Brought up 1 CPUs
>>>>>
>>>>>
>>>>> This was caused just by removing the "cmp r7, r0" and "bne pen"
>>>>> instructions.
>>>>>
>>>>> With these instructions are added it works and I get this:
>>>>>
>>>>> [    0.132329] CPU: Testing write buffer coherency: ok
>>>>> [    0.137682] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
>>>>> [    0.143708] Setting up static identity map for 0x82a0 - 0x82d4
>>>>> [    0.189788] CPU1: thread -1, cpu 1, socket 0, mpidr 80000001
>>>>> [    0.189892] Brought up 2 CPUs
>>>>> [    0.198889] SMP: Total of 2 processors activated (3188.32 BogoMIPS).
>>>>>
>>>>> Currently this is 100% reproducible.
>>>>>
>>>>> Could it be that the second CPU needs some time till it is synchronised
>>>>> correctly?
>>>>>
>>>>> I do not know if and why the cache clearing is needed, I do not have
>>>>> access to the SoC documentation or the ASIC/firmware developer.
>>>>>
>>>>>>
>>>>>>> +	sysram_base_addr = of_iomap(node, 0);
>>>>>>> +	if (!sysram_base_addr) {
>>>>>>> +		pr_warn("Failed to map sysram\n");
>>>>>>> +		return;
>>>>>>> +	}
>>>>>>> +
>>>>>>> +	writel(virt_to_phys(entry_point), sysram_base_addr + SOC_ROM_LUT_OFF);
>>>>>>> +
>>>>>>> +	dsb_sev();	/* Exit WFI */
>>>>>>
>>>>>> Which WFI?  This seems to imply that you have some kind of initial
>>>>>> firmware.  If so, that should be taking care of the cache initialisation,
>>>>>> not the kernel.
>>>>>>
>>>>>>> +	mb();		/* make sure write buffer is drained */
>>>>>>
>>>>>> writel() already ensures that.
>>>>>>
>>>>>>> +	/*
>>>>>>> +	 * The secondary processor is waiting to be released from
>>>>>>> +	 * the holding pen - release it, then wait for it to flag
>>>>>>> +	 * that it has been released by resetting pen_release.
>>>>>>> +	 *
>>>>>>> +	 * Note that "pen_release" is the hardware CPU ID, whereas
>>>>>>> +	 * "cpu" is Linux's internal ID.
>>>>>>> +	 */
>>>>>>> +	write_pen_release(cpu_logical_map(cpu));
>>>>>>> +
>>>>>>> +	 /* Send the secondary CPU SEV */
>>>>>>> +	dsb_sev();
>>>>>>
>>>>>> If you even need any of the pen code, if you're having to send a SEV here,
>>>>>> wouldn't having a WFE in the pen assembly loop above be a good idea?
>>>>>>
>>>>>
>>>>>
>>>>> I have to read more on how WFE and co works.
>>>>>
>>>>> Hauke
>>>>>
>>>
>>> Thanks,
>>> Kapil
>>>
>>

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2015-10-23 22:36 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-02-10 20:32 [PATCH RFC] ARM: BCM5301X: Implement SMP support Rafał Miłecki
2015-02-13 11:54 ` Hauke Mehrtens
2015-02-13 12:29 ` Mark Rutland
2015-02-19 22:32 ` [PATCH] " Rafał Miłecki
2015-03-11 21:23   ` Rafał Miłecki
2015-03-16 16:52   ` Florian Fainelli
2015-03-22 13:20   ` [PATCH V2] " Rafał Miłecki
2015-03-26 12:00     ` Russell King - ARM Linux
2015-10-13 22:29       ` Hauke Mehrtens
2015-10-13 22:48         ` Ray Jui
2015-10-14 13:42           ` Kapil Hali
2015-10-14 18:22             ` Hauke Mehrtens
2015-10-15 15:50               ` Kapil Hali
2015-10-22 20:30               ` Jon Mason
2015-10-23 22:36                 ` Hauke Mehrtens
2015-10-15  8:17         ` Russell King - ARM Linux

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.