From patchwork Wed Dec 5 10:01:55 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joseph Lo X-Patchwork-Id: 203812 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 14D1D2C00AC for ; Wed, 5 Dec 2012 21:02:33 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753326Ab2LEKCc (ORCPT ); Wed, 5 Dec 2012 05:02:32 -0500 Received: from hqemgate03.nvidia.com ([216.228.121.140]:5923 "EHLO hqemgate03.nvidia.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753312Ab2LEKCc (ORCPT ); Wed, 5 Dec 2012 05:02:32 -0500 Received: from hqnvupgp05.nvidia.com (Not Verified[216.228.121.13]) by hqemgate03.nvidia.com id ; Wed, 05 Dec 2012 02:05:46 -0800 Received: from hqemhub02.nvidia.com ([172.17.108.22]) by hqnvupgp05.nvidia.com (PGP Universal service); Wed, 05 Dec 2012 02:02:28 -0800 X-PGP-Universal: processed; by hqnvupgp05.nvidia.com on Wed, 05 Dec 2012 02:02:28 -0800 Received: from localhost.localdomain (172.20.144.16) by hqemhub02.nvidia.com (172.20.150.31) with Microsoft SMTP Server (TLS) id 8.3.279.1; Wed, 5 Dec 2012 02:02:27 -0800 From: Joseph Lo To: Stephen Warren CC: , Subject: [PATCH V2 6/6] ARM: tegra20: cpuidle: apply coupled cpuidle for powered-down mode Date: Wed, 5 Dec 2012 18:01:55 +0800 Message-ID: <1354701715-24150-9-git-send-email-josephl@nvidia.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1354701715-24150-1-git-send-email-josephl@nvidia.com> References: <1354701715-24150-1-git-send-email-josephl@nvidia.com> MIME-Version: 1.0 Sender: linux-tegra-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-tegra@vger.kernel.org config ARCH_TEGRA_3x_SOC bool "Enable support for Tegra30 family" + select ARCH_NEEDS_CPU_IDLE_COUPLED select ARCH_REQUIRE_GPIOLIB select ARM_ERRATA_743622 select ARM_ERRATA_751472 --- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c index 5e8cbf5..f880350 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra30.c +++ b/arch/arm/mach-tegra/cpuidle-tegra30.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -30,14 +31,18 @@ #include #include +#include "irq.h" #include "pm.h" #include "sleep.h" #include "tegra_cpu_car.h" #ifdef CONFIG_PM_SLEEP -static int tegra30_idle_lp2(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index); +static bool abort_flag; +static atomic_t abort_barrier; +static cpumask_t cpus_out_lp2; +static int tegra30_idle_lp2_coupled(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index); #endif static struct cpuidle_driver tegra_idle_driver = { @@ -53,11 +58,12 @@ static struct cpuidle_driver tegra_idle_driver = { [0] = ARM_CPUIDLE_WFI_STATE_PWR(600), #ifdef CONFIG_PM_SLEEP [1] = { - .enter = tegra30_idle_lp2, + .enter = tegra30_idle_lp2_coupled, .exit_latency = 2000, .target_residency = 2200, .power_usage = 0, - .flags = CPUIDLE_FLAG_TIME_VALID, + .flags = CPUIDLE_FLAG_TIME_VALID | + CPUIDLE_FLAG_COUPLED, .name = "powered-down", .desc = "CPU power gated", }, @@ -79,8 +85,8 @@ static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev, /* All CPUs entering LP2 is not working. * Don't let CPU0 enter LP2 when any secondary CPU is online. */ - if (num_online_cpus() > 1 || !tegra_cpu_rail_off_ready()) { - cpu_do_idle(); + if (num_online_cpus() > 1 && !tegra_cpu_rail_off_ready()) { +// cpu_do_idle(); return false; } @@ -94,6 +100,13 @@ static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev, } #ifdef CONFIG_SMP +static void tegra30_wake_up_secondary_cpus(u32 cpu) +{ +// if (!cpumask_test_cpu(cpu, &cpus_out_lp2)) + arch_send_wakeup_ipi_mask(cpumask_of(cpu)); +// gic_raise_softirq(cpumask_of(cpu), 0); +} + static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) @@ -113,6 +126,11 @@ static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev, return true; } #else +static inline void tegra30_wake_up_secondary_cpus(u32 cpu) +{ + return; +} + static inline bool tegra30_cpu_core_power_down(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) @@ -121,36 +139,56 @@ static inline bool tegra30_cpu_core_power_down(struct cpuidle_device *dev, } #endif -static int __cpuinit tegra30_idle_lp2(struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index) +static int __cpuinit tegra30_idle_lp2_coupled(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) { u32 cpu = is_smp() ? cpu_logical_map(dev->cpu) : dev->cpu; bool entered_lp2 = false; - bool last_cpu; +int i; + abort_flag = tegra_pending_irq(); + cpumask_clear(&cpus_out_lp2); + cpuidle_coupled_parallel_barrier(dev, &abort_barrier); +//printk(KERN_EMERG "cpu %d in\n", cpu); + if (abort_flag) + return -EINTR; local_fiq_disable(); - last_cpu = tegra_set_cpu_in_lp2(cpu); + tegra_set_cpu_in_lp2(cpu); cpu_pm_enter(); if (cpu == 0) { - if (last_cpu) - entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv, - index); - else - cpu_do_idle(); + while (num_online_cpus() > 1 && !tegra_cpu_rail_off_ready()) { + cpu_relax(); + +// if (!cpumask_empty(&cpus_out_lp2)) +// goto out; + } + entered_lp2 = tegra30_cpu_cluster_power_down(dev, drv, index); + +out: +// if (!entered_lp2) { +// int i; + for_each_online_cpu(i) + if (i != cpu) + tegra30_wake_up_secondary_cpus(i); +// } } else { entered_lp2 = tegra30_cpu_core_power_down(dev, drv, index); + cpumask_set_cpu(cpu, &cpus_out_lp2); } + cpu_pm_exit(); tegra_clear_cpu_in_lp2(cpu); - +// +// local_fiq_enable(); smp_rmb(); - +//printk(KERN_EMERG "cpu %d out\n", cpu); +cpuidle_coupled_parallel_barrier(dev, &abort_barrier); return (entered_lp2) ? index : 0; } #endif @@ -175,6 +213,9 @@ int __init tegra30_cpuidle_init(void) for_each_possible_cpu(cpu) { dev = &per_cpu(tegra_idle_device, cpu); dev->cpu = cpu; +#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED + dev->coupled_cpus = *cpu_online_mask; +#endif dev->state_count = drv->state_count; ret = cpuidle_register_device(dev);