From patchwork Fri Apr 19 10:47:41 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: chenhui zhao X-Patchwork-Id: 237907 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from ozlabs.org (localhost [IPv6:::1]) by ozlabs.org (Postfix) with ESMTP id AACB32C0983 for ; Fri, 19 Apr 2013 20:55:01 +1000 (EST) Received: from va3outboundpool.messaging.microsoft.com (va3ehsobe005.messaging.microsoft.com [216.32.180.31]) (using TLSv1 with cipher AES128-SHA (128/128 bits)) (Client CN "mail.global.frontbridge.com", Issuer "Microsoft Secure Server Authority" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 1BDD32C025C for ; Fri, 19 Apr 2013 20:48:27 +1000 (EST) Received: from mail94-va3-R.bigfish.com (10.7.14.227) by VA3EHSOBE005.bigfish.com (10.7.40.25) with Microsoft SMTP Server id 14.1.225.23; Fri, 19 Apr 2013 10:48:23 +0000 Received: from mail94-va3 (localhost [127.0.0.1]) by mail94-va3-R.bigfish.com (Postfix) with ESMTP id 3BE7D201DC; Fri, 19 Apr 2013 10:48:23 +0000 (UTC) X-Forefront-Antispam-Report: CIP:70.37.183.190; KIP:(null); UIP:(null); IPV:NLI; H:mail.freescale.net; RD:none; EFVD:NLI X-SpamScore: 0 X-BigFish: VS0(zzzz1f42h1fc6h1ee6h1de0h1fdah1202h1e76h1d1ah1d2ahzz8275bhz2dh2a8h668h839hd24he5bhf0ah1288h12a5h12a9h12bdh12e5h1354h137ah139eh13b6h1441h1504h1537h162dh1631h1758h1898h18e1h1946h19b5h1ad9h1b0ah1155h) Received: from mail94-va3 (localhost.localdomain [127.0.0.1]) by mail94-va3 (MessageSwitch) id 1366368501890746_16865; Fri, 19 Apr 2013 10:48:21 +0000 (UTC) Received: from VA3EHSMHS033.bigfish.com (unknown [10.7.14.240]) by mail94-va3.bigfish.com (Postfix) with ESMTP id D1C67300043; Fri, 19 Apr 2013 10:48:21 +0000 (UTC) Received: from mail.freescale.net (70.37.183.190) by VA3EHSMHS033.bigfish.com (10.7.99.43) with Microsoft SMTP Server (TLS) id 14.1.225.23; Fri, 19 Apr 2013 10:48:21 +0000 Received: from az84smr01.freescale.net (10.64.34.197) by 039-SN1MMR1-001.039d.mgd.msft.net (10.84.1.13) with Microsoft SMTP Server (TLS) id 14.2.328.11; Fri, 19 Apr 2013 10:48:20 +0000 Received: from localhost.localdomain ([10.193.20.174]) by az84smr01.freescale.net (8.14.3/8.14.0) with ESMTP id r3JAm5TS028249; Fri, 19 Apr 2013 03:48:19 -0700 From: Zhao Chenhui To: Subject: [PATCH v2 08/15] powerpc/85xx: add cpu hotplug support for e500mc/e5500 Date: Fri, 19 Apr 2013 18:47:41 +0800 Message-ID: <1366368468-29143-8-git-send-email-chenhui.zhao@freescale.com> X-Mailer: git-send-email 1.7.3 In-Reply-To: <1366368468-29143-1-git-send-email-chenhui.zhao@freescale.com> References: <1366368468-29143-1-git-send-email-chenhui.zhao@freescale.com> MIME-Version: 1.0 X-OriginatorOrg: freescale.com Cc: linux-kernel@vger.kernel.org X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Sender: "Linuxppc-dev" From: Chen-Hui Zhao Add support to disable and re-enable individual cores at runtime. This supports e500mc/e5500 core based SoCs. To prevent the register access race, only read/write RCPM registers in platform_cpu_die() on the boot cpu instead of accessing by individual cpus. Platform implementations can override the platform_cpu_die(). Signed-off-by: Zhao Chenhui Signed-off-by: Li Yang Signed-off-by: Andy Fleming --- arch/powerpc/Kconfig | 2 +- arch/powerpc/include/asm/smp.h | 1 + arch/powerpc/kernel/smp.c | 16 ++++++++++- arch/powerpc/platforms/85xx/smp.c | 56 ++++++++++++++++++++++++++++++++++-- 4 files changed, 69 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 0e11a09..b6851be 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -347,7 +347,7 @@ config SWIOTLB config HOTPLUG_CPU bool "Support for enabling/disabling CPUs" depends on SMP && HOTPLUG && (PPC_PSERIES || \ - PPC_PMAC || PPC_POWERNV || (PPC_85xx && !PPC_E500MC)) + PPC_PMAC || PPC_POWERNV || PPC_85xx) ---help--- Say Y here to be able to disable and re-enable individual CPUs at runtime on SMP machines. diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h index 195ce2a..95be584 100644 --- a/arch/powerpc/include/asm/smp.h +++ b/arch/powerpc/include/asm/smp.h @@ -60,6 +60,7 @@ extern void smp_generic_take_timebase(void); DECLARE_PER_CPU(unsigned int, cpu_pvr); #ifdef CONFIG_HOTPLUG_CPU +void platform_cpu_die(unsigned int cpu); extern void migrate_irqs(void); int generic_cpu_disable(void); void generic_cpu_die(unsigned int cpu); diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 76bd9da..386c7ea 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -381,14 +381,28 @@ int generic_cpu_disable(void) return 0; } +/** + * platform_cpu_die() - do platform related operations on the boot cpu + * after CPU_DEAD is assigned to the variable cpu_state of the dying cpu. + * Platform implementations can override this. + * + * @cpu: the cpu to die + */ +void __attribute__ ((weak)) platform_cpu_die(unsigned int cpu) +{ + return; +} + void generic_cpu_die(unsigned int cpu) { int i; for (i = 0; i < 100; i++) { smp_rmb(); - if (per_cpu(cpu_state, cpu) == CPU_DEAD) + if (per_cpu(cpu_state, cpu) == CPU_DEAD) { + platform_cpu_die(cpu); return; + } msleep(100); } printk(KERN_ERR "CPU%d didn't die...\n", cpu); diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index 6c2fe6b..6eae2e0 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -40,7 +40,7 @@ struct epapr_spin_table { u32 pir; }; -static struct ccsr_guts __iomem *guts; +static void __iomem *guts_regs; static u64 timebase; static int tb_req; static int tb_valid; @@ -62,7 +62,7 @@ static inline u32 get_phy_cpu_mask(void) static void mpc85xx_timebase_freeze(int freeze) { - struct ccsr_rcpm __iomem *rcpm = (typeof(rcpm))guts; + struct ccsr_rcpm __iomem *rcpm = guts_regs; u32 mask = get_phy_cpu_mask(); if (freeze) @@ -76,6 +76,7 @@ static void mpc85xx_timebase_freeze(int freeze) #else static void mpc85xx_timebase_freeze(int freeze) { + struct ccsr_guts __iomem *guts = guts_regs; uint32_t mask; mask = CCSR_GUTS_DEVDISR_TB0 | CCSR_GUTS_DEVDISR_TB1; @@ -84,6 +85,7 @@ static void mpc85xx_timebase_freeze(int freeze) else clrbits32(&guts->devdisr, mask); + /* read back to push the previous write */ in_be32(&guts->devdisr); } #endif @@ -128,7 +130,45 @@ static void mpc85xx_take_timebase(void) local_irq_restore(flags); } +static void core_reset_erratum(int hw_cpu) +{ +#ifdef CONFIG_PPC_E500MC + struct ccsr_rcpm __iomem *rcpm = guts_regs; + + clrbits32(&rcpm->cnapcr, 1 << hw_cpu); +#endif +} + #ifdef CONFIG_HOTPLUG_CPU +#ifdef CONFIG_PPC_E500MC +static void __cpuinit smp_85xx_mach_cpu_die(void) +{ + unsigned int cpu = smp_processor_id(); + + local_irq_disable(); + idle_task_exit(); + mb(); + + mtspr(SPRN_TCR, 0); + + __flush_disable_L1(); + disable_backside_L2_cache(); + + generic_set_cpu_dead(cpu); + + while (1); +} + +void platform_cpu_die(unsigned int cpu) +{ + unsigned int hw_cpu = get_hard_smp_processor_id(cpu); + struct ccsr_rcpm __iomem *rcpm = guts_regs; + + /* Core Nap Operation */ + setbits32(&rcpm->cnapcr, 1 << hw_cpu); +} +#else +/* for e500v1 and e500v2 */ static void __cpuinit smp_85xx_mach_cpu_die(void) { unsigned int cpu = smp_processor_id(); @@ -156,6 +196,7 @@ static void __cpuinit smp_85xx_mach_cpu_die(void) while (1) ; } +#endif /* CONFIG_PPC_E500MC */ #endif static inline void flush_spin_table(void *spin_table) @@ -228,6 +269,13 @@ static int __cpuinit smp_85xx_kick_cpu(int nr) flush_spin_table(spin_table); /* + * Due to an erratum that core hard reset and core warm reset + * are unable to wake up cores from power management modes, + * wake up cores before reset. + */ + core_reset_erratum(hw_cpu); + + /* * We don't set the BPTR register here since it already points * to the boot page properly. */ @@ -436,9 +484,9 @@ void __init mpc85xx_smp_init(void) np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids); if (np) { - guts = of_iomap(np, 0); + guts_regs = of_iomap(np, 0); of_node_put(np); - if (!guts) { + if (!guts_regs) { pr_err("%s: Could not map guts node address\n", __func__); return;