Sorry, there is something wrong.
Please ignore this mail.

On Wed, 2012-12-05 at 18:01 +0800, Joseph Lo wrote:
> 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
> 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 <linux/module.h>
>  #include <linux/cpuidle.h>
>  #include <linux/cpu_pm.h>
> +#include <linux/cpumask.h>
>  #include <linux/clockchips.h>
>  
>  #include <asm/cpuidle.h>
> @@ -30,14 +31,18 @@
>  #include <asm/suspend.h>
>  #include <asm/smp_plat.h>
>  
> +#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);
> --
> To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
> the body of a message to [email protected]
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to