[linux-yocto] [PATCH 35/89] arm/mach-axxia: Clean up the sequence of starting other cores.
Paul Butler
butler.paul at gmail.com
Sun Oct 27 12:33:00 PDT 2013
From: John Jacques <john.jacques at lsi.com>
Signed-off-by: John Jacques <john.jacques at lsi.com>
---
arch/arm/mach-axxia/platsmp.c | 107 +++++++++++++++++++++++++++++++++++-------
1 file changed, 90 insertions(+), 17 deletions(-)
diff --git a/arch/arm/mach-axxia/platsmp.c b/arch/arm/mach-axxia/platsmp.c
index 8d6dbd8..0984dea 100644
--- a/arch/arm/mach-axxia/platsmp.c
+++ b/arch/arm/mach-axxia/platsmp.c
@@ -35,6 +35,65 @@ extern void axxia_secondary_startup(void);
#define APB2_SER3_ADDR_SIZE 0x10000
/*
+ flush_l3
+*/
+
+static void
+flush_l3(void)
+{
+#if 0
+ unsigned long hnf_offsets[] = {
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
+ };
+ int i;
+ unsigned long status;
+ int retries;
+ void __iomem *dickens;
+
+ dickens = ioremap(0x2000000000, 0x1000000);
+
+ for (i = 0; i < (sizeof(hnf_offsets) / sizeof(unsigned long)); ++i) {
+ /* set state NOL3 */
+ writel(0x0, dickens + (0x10000 * hnf_offsets[i]) + 0x10);
+ }
+
+ for (i = 0; i < (sizeof(hnf_offsets) / sizeof(unsigned long)); ++i) {
+ retries = 10000;
+
+ do {
+ status = readl(dickens +
+ (0x10000 * hnf_offsets[i]) + 0x18);
+ udelay(1);
+ } while ((0 < --retries) && (0x0 != (status & 0xf)));
+
+ if (0 == retries)
+ BUG();
+ }
+
+ for (i = 0; i < (sizeof(hnf_offsets) / sizeof(unsigned long)); ++i) {
+ /* set state FAM */
+ writel(0x3, dickens + (0x10000 * hnf_offsets[i]) + 0x10);
+ }
+
+ for (i = 0; i < (sizeof(hnf_offsets) / sizeof(unsigned long)); ++i) {
+ retries = 10000;
+
+ do {
+ status = readl(dickens +
+ (0x10000 * hnf_offsets[i]) + 0x18);
+ udelay(1);
+ } while ((0 < --retries) && (0xc != (status & 0xf)));
+
+ if (0 == retries)
+ BUG();
+ }
+
+ iounmap(dickens);
+#endif
+ return;
+}
+
+/*
* Write pen_release in a way that is guaranteed to be visible to all
* observers, irrespective of whether they're taking part in coherency
* or not. This is necessary for the hotplug code to work reliably.
@@ -45,6 +104,7 @@ static void __cpuinit write_pen_release(int val)
smp_wmb();
__cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
+ flush_l3();
}
static DEFINE_RAW_SPINLOCK(boot_lock);
@@ -191,7 +251,7 @@ platform_smp_prepare_cpus(unsigned int max_cpus)
int i;
void __iomem *apb2_ser3_base;
unsigned long resetVal;
- int phys_cpu, cpu_count=0;
+ int phys_cpu, cpu_count = 0;
struct device_node *np;
unsigned long release_addr[NR_CPUS] = {0};
unsigned long release;
@@ -216,25 +276,33 @@ platform_smp_prepare_cpus(unsigned int max_cpus)
* actually populated at the present time.
*/
- apb2_ser3_base = ioremap(APB2_SER3_PHY_ADDR, APB2_SER3_ADDR_SIZE);
+ apb2_ser3_base =
+ ioremap(APB2_SER3_PHY_ADDR, APB2_SER3_ADDR_SIZE);
- for (i = 0; i < NR_CPUS; i++) {
+ for (i = 0; i < NR_CPUS; i++) {
/* check if this is a possible CPU and
it is within max_cpus range */
if ((cpu_possible(i)) &&
(cpu_count < max_cpus) &&
(0 != release_addr[i])) {
- resetVal = readl(apb2_ser3_base + 0x1010);
- phys_cpu = cpu_logical_map(i);
set_cpu_present(cpu_count, true);
- if (phys_cpu != 0) {
- writel(0xab, apb2_ser3_base+0x1000);
- resetVal &= ~(1 << phys_cpu);
- writel(resetVal, apb2_ser3_base+0x1010);
- udelay(1000);
- }
cpu_count++;
}
+
+ /* Release all physical cpu:s since we might want to
+ * bring them online later. Also we need to get the
+ * execution into kernel code (it's currently executing
+ * in u-boot).
+ */
+ phys_cpu = cpu_logical_map(i);
+
+ if (phys_cpu != 0) {
+ resetVal = readl(apb2_ser3_base + 0x1010);
+ writel(0xab, apb2_ser3_base+0x1000);
+ resetVal &= ~(1 << phys_cpu);
+ writel(resetVal, apb2_ser3_base+0x1010);
+ udelay(1000);
+ }
}
iounmap(apb2_ser3_base);
@@ -244,14 +312,19 @@ platform_smp_prepare_cpus(unsigned int max_cpus)
* cores will execute once they are released from their
* "holding pen".
*/
- *(u32 *)phys_to_virt(release) =
- virt_to_phys(axxia_secondary_startup);
- smp_wmb();
- __cpuc_flush_dcache_area((void *)phys_to_virt(release),
- sizeof(u32));
+ for (i = 0; i < NR_CPUS; i++) {
+ if (release_addr[i] != 0) {
+ u32 *vrel_addr =
+ (u32 *)phys_to_virt(release_addr[i]);
+ *vrel_addr =
+ virt_to_phys(axxia_secondary_startup);
+ smp_wmb();
+ __cpuc_flush_dcache_area(vrel_addr, sizeof(u32));
+ }
+ }
} else if (of_find_compatible_node(NULL, NULL, "lsi,axm5516-sim")) {
for (i = 0; i < max_cpus; i++)
- set_cpu_present(i, true);
+ set_cpu_present(i, true);
/*
* This is the entry point of the routine that the secondary
--
1.8.3.4
More information about the linux-yocto
mailing list