From patchwork Thu Jan 15 06:05:30 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dongsheng Wang X-Patchwork-Id: 429259 X-Patchwork-Delegate: scottwood@freescale.com Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 1ED4414027F for ; Thu, 15 Jan 2015 17:08:29 +1100 (AEDT) Received: from ozlabs.org (ozlabs.org [103.22.144.67]) by lists.ozlabs.org (Postfix) with ESMTP id EA7151A0E6C for ; Thu, 15 Jan 2015 17:08:28 +1100 (AEDT) X-Original-To: linuxppc-dev@lists.ozlabs.org Delivered-To: linuxppc-dev@lists.ozlabs.org Received: from na01-bn1-obe.outbound.protection.outlook.com (mail-bn1bon0117.outbound.protection.outlook.com [157.56.111.117]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id CFF151A0DC2 for ; Thu, 15 Jan 2015 17:07:46 +1100 (AEDT) Received: from BY2PR03CA003.namprd03.prod.outlook.com (10.255.93.20) by BY2PR03MB159.namprd03.prod.outlook.com (10.242.36.18) with Microsoft SMTP Server (TLS) id 15.1.53.17; Thu, 15 Jan 2015 06:07:39 +0000 Received: from BL2FFO11FD057.protection.gbl (10.255.93.4) by BY2PR03CA003.outlook.office365.com (10.255.93.20) with Microsoft SMTP Server (TLS) id 15.1.59.20 via Frontend Transport; Thu, 15 Jan 2015 06:07:38 +0000 Received: from az84smr01.freescale.net (192.88.158.2) by BL2FFO11FD057.mail.protection.outlook.com (10.173.161.185) with Microsoft SMTP Server (TLS) id 15.1.49.13 via Frontend Transport; Thu, 15 Jan 2015 06:07:38 +0000 Received: from titan.ap.freescale.net ([10.192.208.233]) by az84smr01.freescale.net (8.14.3/8.14.0) with ESMTP id t0F67ZZJ009294; Wed, 14 Jan 2015 23:07:35 -0700 From: Dongsheng Wang To: , , Subject: [PATCH] fsl/smp: add low power boot support to replace spin boot Date: Thu, 15 Jan 2015 14:05:30 +0800 Message-ID: <1421301930-10035-1-git-send-email-dongsheng.wang@freescale.com> X-Mailer: git-send-email 2.1.0.27.g96db324 X-EOPAttributedMessage: 0 Received-SPF: Fail (protection.outlook.com: domain of freescale.com does not designate 192.88.158.2 as permitted sender) receiver=protection.outlook.com; client-ip=192.88.158.2; helo=az84smr01.freescale.net; Authentication-Results: spf=fail (sender IP is 192.88.158.2) smtp.mailfrom=Dongsheng.Wang@freescale.com; X-Forefront-Antispam-Report: CIP:192.88.158.2; CTRY:US; IPV:NLI; EFV:NLI; SFV:NSPM; SFS:(10019020)(6009001)(339900001)(199003)(189002)(77096005)(50466002)(33646002)(104016003)(48376002)(86362001)(85426001)(92566002)(50226001)(47776003)(64706001)(36756003)(62966003)(450100001)(97736003)(68736005)(19580405001)(77156002)(81156004)(106466001)(105606002)(87936001)(69596002)(46102003)(6806004)(19580395003)(229853001)(2201001)(50986999); DIR:OUT; SFP:1102; SCL:1; SRVR:BY2PR03MB159; H:az84smr01.freescale.net; FPR:; SPF:Fail; MLV:sfv; PTR:InfoDomainNonexistent; A:1; MX:1; LANG:en; MIME-Version: 1.0 X-DmarcAction-Test: None X-Microsoft-Antispam: UriScan:; X-Microsoft-Antispam: BCL:0;PCL:0;RULEID:(3005004);SRVR:BY2PR03MB159; X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004); SRVR:BY2PR03MB159; X-Forefront-PRVS: 0457F11EAF X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:;SRVR:BY2PR03MB159; X-OriginatorOrg: freescale.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 15 Jan 2015 06:07:38.4942 (UTC) X-MS-Exchange-CrossTenant-Id: 710a03f5-10f6-4d38-9ff4-a80b81da590d X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=710a03f5-10f6-4d38-9ff4-a80b81da590d; Ip=[192.88.158.2] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY2PR03MB159 Cc: linuxppc-dev@lists.ozlabs.org, Wang Dongsheng X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.18 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: Wang Dongsheng U-boot put non-boot cpus into an low power state(PW10/PW20 or DOZE) when cpu powered up. To exit low power state kernel will send DOORBELL or MPIC-IPI signal to all those CPUs. e500/e500v2 use mpic to send IPI signal. e500mc and later use doorbell to send IPI signal. This feature tested on: POWER UP TEST: P1022DS(e500v2),96k times. P4080(e500mc), 110k times. T1024(e5500), 83k times. T4240(e6500), 150k times. CPU HOTPLUG TEST: P1022DS(e500v2),1.4 million times. P4080(e500mc), 1.8 million times. T1024(e5500), 1.3 million times. T4240(e6500), 1.1 million times. Signed-off-by: Wang Dongsheng diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index 754f93d..8af6a25 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h @@ -474,6 +474,15 @@ extern int mpic_cpu_get_priority(void); /* Set the current cpu priority for this cpu */ extern void mpic_cpu_set_priority(int prio); +/* Set cpu priority */ +void mpic_set_cpu_priority(int nr, int prio); + +/* Set cpu EOI */ +void mpic_cpu_eoi_write(int cpu); + +/* CPU ACK interrupt */ +void mpic_cpu_ack(int cpu); + /* Request IPIs on primary mpic */ extern void mpic_request_ipis(void); diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index d7c1e69..6c54632 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c @@ -193,6 +193,30 @@ static int smp_85xx_kick_cpu(int nr) const u64 *cpu_rel_addr; __iomem struct epapr_spin_table *spin_table; struct device_node *np; + + /* + * DOORBELL: + * When kernel kick one of cpus, all cpus will be wakenup. To make + * sure that only the target cpu is effected, other cpus (by checking + * spin_table->addr_l) should go back to low power state. + * + * U-boot has renumber the cpu PIR Why we need to set all of PIR to + * the same value? + * A: Before kernel kicking cpu, the doorbell message was not configured + * for target cpu(cpu_messages->data). If we try to send a + * non-configured message to target cpu, it cannot correctly receive + * doorbell interrput. So SET ALL OF CPU'S PIR to the same value to + * let all cpus catch the interrupt. + * + * Why set PIR to zero? + * A: U-boot cannot know how many cpus will be kicked up(Kernel allow us + * to configure NR_CPUS) and IPI is a per_cpu variable, u-boot cannot + * set a appropriate PIR for every cpu, but the boot cpu(CPU0) always be + * there. U-boot set PIR to zero as a default PIR ID for each CPU, so + * initialize the kick_cpus to 0. + */ + u32 kick_cpus = 0; + int hw_cpu = get_hard_smp_processor_id(nr); int ioremappable; int ret = 0; @@ -251,8 +275,7 @@ static int smp_85xx_kick_cpu(int nr) spin_table = phys_to_virt(*cpu_rel_addr); local_irq_save(flags); -#ifdef CONFIG_PPC32 -#ifdef CONFIG_HOTPLUG_CPU +#if defined(CONFIG_PPC32) && defined(CONFIG_HOTPLUG_CPU) /* Corresponding to generic_set_cpu_dead() */ generic_set_cpu_up(nr); @@ -292,11 +315,58 @@ static int smp_85xx_kick_cpu(int nr) __secondary_hold_acknowledge = -1; } #endif + flush_spin_table(spin_table); - out_be32(&spin_table->pir, hw_cpu); + /* + * U-boot will wait kernel send eoi to MPIC, after EOI has send + * kernel will set PIR for uboot, let uboot know EOI has send. + */ + out_be32(&spin_table->pir, 0); + +#ifdef CONFIG_PPC32 out_be32(&spin_table->addr_l, __pa(__early_start)); +#else + out_be64((u64 *)(&spin_table->addr_h), + __pa(ppc_function_entry(generic_secondary_smp_init))); +#endif flush_spin_table(spin_table); + /* + * e500, e500v2 need to use MPIC to send IPI signal, so we need to + * open IPI firstly. + */ + if (!cpu_has_feature(CPU_FTR_DBELL)) { + mpic_set_cpu_priority(nr, 0); + kick_cpus = nr; + } + + /* Let cpu exit low power state, and from u-boot jump to kernel */ + arch_send_call_function_single_ipi(kick_cpus); + + /* + * Let we ACK interrput and Send EOI signal to finish INT server + * U-boot has read EPR to ACK interrput when MPIC work in external + * proxy mode. Without the external proxy facility, we need to read + * MPIC ACK register. + * + * There just ACK interrput, we don't need to get the interrupt vector + * and to handle it. Because there just IPI or DOORBELL interrupt to + * make u-boot exit low power state and jump to kernel. + */ + mpic_cpu_ack(nr); + /* Send EOI to clear ISR bit to remove interrupt from service */ + mpic_cpu_eoi_write(nr); + + /* After wakeup CPU disable IPI, IPI will be opened in setup_cpu */ + if (!cpu_has_feature(CPU_FTR_DBELL)) + mpic_set_cpu_priority(nr, 0xf); + + /* After EOI finish, let we release cpu */ + flush_spin_table(spin_table); + out_be32(&spin_table->pir, hw_cpu); + flush_spin_table(spin_table); + +#ifdef CONFIG_PPC32 /* Wait a bit for the CPU to ack. */ if (!spin_event_timeout(__secondary_hold_acknowledge == hw_cpu, 10000, 100)) { @@ -308,12 +378,6 @@ static int smp_85xx_kick_cpu(int nr) out: #else smp_generic_kick_cpu(nr); - - flush_spin_table(spin_table); - out_be32(&spin_table->pir, hw_cpu); - out_be64((u64 *)(&spin_table->addr_h), - __pa(ppc_function_entry(generic_secondary_smp_init))); - flush_spin_table(spin_table); #endif local_irq_restore(flags); diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index c4648ad..b2ba47e 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c @@ -658,6 +658,21 @@ static inline void mpic_eoi(struct mpic *mpic) (void)mpic_cpu_read(MPIC_INFO(CPU_WHOAMI)); } +void mpic_cpu_eoi_write(int cpu) +{ + struct mpic *mpic = mpic_primary; + + _mpic_write(mpic->reg_type, &mpic->cpuregs[cpu], MPIC_INFO(CPU_EOI), 0); + _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], MPIC_INFO(CPU_WHOAMI)); +} + +void mpic_cpu_ack(int cpu) +{ + struct mpic *mpic = mpic_primary; + + _mpic_read(mpic->reg_type, &mpic->cpuregs[cpu], MPIC_INFO(CPU_INTACK)); +} + /* * Linux descriptor level callbacks */ @@ -1778,6 +1793,16 @@ void mpic_cpu_set_priority(int prio) mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), prio); } +void mpic_set_cpu_priority(int nr, int prio) +{ + struct mpic *mpic = mpic_primary; + int hw_cpu = get_hard_smp_processor_id(nr); + + prio &= MPIC_CPU_TASKPRI_MASK; + _mpic_write(mpic->reg_type, &mpic->cpuregs[hw_cpu], + MPIC_INFO(CPU_CURRENT_TASK_PRI), prio); +} + void mpic_teardown_this_cpu(int secondary) { struct mpic *mpic = mpic_primary;