OSDN Git Service

ARM64: smp: Prevent cluster LPM modes when pending IPIs on cluster CPUs
authorMahesh Sivasubramanian <msivasub@codeaurora.org>
Fri, 19 Sep 2014 02:33:55 +0000 (20:33 -0600)
committerDavid Keitel <dkeitel@codeaurora.org>
Tue, 22 Mar 2016 18:07:25 +0000 (11:07 -0700)
LPM modes can fail if there is a pending IPI interrupt at GIC CPU
interface. On some usecases frequent failure of LPM modes can
cause power and performance degradation. Hence, prevent cluster
low power modes when there is a pending IPI on cluster CPUs.

Change-Id: Id8a0ac24e4867ef824e0a6f11d989f1e1a2b0e93
Signed-off-by: Mahesh Sivasubramanian <msivasub@codeaurora.org>
Signed-off-by: Murali Nalajala <mnalajal@codeaurora.org>
Conflicts:
arch/arm/kernel/smp.c
arch/arm64/kernel/smp.c

arch/arm/kernel/smp.c
arch/arm64/kernel/smp.c

index b263613..8166aaa 100644 (file)
@@ -462,6 +462,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
 }
 
 static void (*__smp_cross_call)(const struct cpumask *, unsigned int);
+DEFINE_PER_CPU(bool, pending_ipi);
 
 void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int))
 {
@@ -469,6 +470,21 @@ void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int))
                __smp_cross_call = fn;
 }
 
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
+{
+       smp_cross_call(mask, IPI_CALL_FUNC);
+}
+
+void arch_send_wakeup_ipi_mask(const struct cpumask *mask)
+{
+       smp_cross_call(mask, IPI_WAKEUP);
+}
+
+void arch_send_call_function_single_ipi(int cpu)
+{
+       smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
+}
+
 static const char *ipi_types[NR_IPI] __tracepoint_string = {
 #define S(x,s) [x] = s
        S(IPI_WAKEUP, "CPU wakeup interrupts"),
@@ -483,6 +499,11 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
 
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
 {
+       unsigned int cpu;
+
+       for_each_cpu(cpu, target)
+               per_cpu(pending_ipi, cpu) = true;
+
        trace_ipi_raise(target, ipi_types[ipinr]);
        __smp_cross_call(target, ipinr);
 }
@@ -513,21 +534,6 @@ u64 smp_irq_stat_cpu(unsigned int cpu)
        return sum;
 }
 
-void arch_send_call_function_ipi_mask(const struct cpumask *mask)
-{
-       smp_cross_call(mask, IPI_CALL_FUNC);
-}
-
-void arch_send_wakeup_ipi_mask(const struct cpumask *mask)
-{
-       smp_cross_call(mask, IPI_WAKEUP);
-}
-
-void arch_send_call_function_single_ipi(int cpu)
-{
-       smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
-}
-
 #ifdef CONFIG_IRQ_WORK
 void arch_irq_work_raise(void)
 {
@@ -660,11 +666,15 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 
        if ((unsigned)ipinr < NR_IPI)
                trace_ipi_exit_rcuidle(ipi_types[ipinr]);
+
+       per_cpu(pending_ipi, cpu) = false;
+
        set_irq_regs(old_regs);
 }
 
 void smp_send_reschedule(int cpu)
 {
+       BUG_ON(cpu_is_offline(cpu));
        smp_cross_call(cpumask_of(cpu), IPI_RESCHEDULE);
 }
 
index 91d673a..60946e1 100644 (file)
@@ -469,6 +469,8 @@ acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header,
 #else
 #define acpi_table_parse_madt(...)     do { } while (0)
 #endif
+void (*__smp_cross_call)(const struct cpumask *, unsigned int);
+DEFINE_PER_CPU(bool, pending_ipi);
 
 /*
  * Enumerate the possible CPU set from the device tree and build the
@@ -615,8 +617,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        }
 }
 
-void (*__smp_cross_call)(const struct cpumask *, unsigned int);
-
 void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int))
 {
        __smp_cross_call = fn;
@@ -633,6 +633,11 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
 
 static void smp_cross_call(const struct cpumask *target, unsigned int ipinr)
 {
+       unsigned int cpu;
+
+       for_each_cpu(cpu, target)
+               per_cpu(pending_ipi, cpu) = true;
+
        trace_ipi_raise(target, ipi_types[ipinr]);
        __smp_cross_call(target, ipinr);
 }
@@ -760,6 +765,8 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
 
        if ((unsigned)ipinr < NR_IPI)
                trace_ipi_exit_rcuidle(ipi_types[ipinr]);
+
+       per_cpu(pending_ipi, cpu) = false;
        set_irq_regs(old_regs);
 }