sparc64: Use CPU_POKE to resume idle cpu
authorVijay Kumar <vijay.ac.kumar@oracle.com>
Fri, 21 Jul 2017 16:23:57 +0000 (10:23 -0600)
committerDavid S. Miller <davem@davemloft.net>
Thu, 10 Aug 2017 05:15:10 +0000 (22:15 -0700)
Use CPU_POKE hypervisor call to resume idle cpu if supported.

Signed-off-by: Vijay Kumar <vijay.ac.kumar@oracle.com>
Reviewed-by: Anthony Yznaga <anthony.yznaga@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
arch/sparc/include/asm/smp_64.h
arch/sparc/kernel/hvapi.c
arch/sparc/kernel/process_64.c
arch/sparc/kernel/setup_64.c
arch/sparc/kernel/smp_64.c

index ce2233f..a750892 100644 (file)
@@ -33,6 +33,9 @@
 DECLARE_PER_CPU(cpumask_t, cpu_sibling_map);
 extern cpumask_t cpu_core_map[NR_CPUS];
 
+void smp_init_cpu_poke(void);
+void scheduler_poke(void);
+
 void arch_send_call_function_single_ipi(int cpu);
 void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 
@@ -74,6 +77,8 @@ void __cpu_die(unsigned int cpu);
 #define smp_fetch_global_regs() do { } while (0)
 #define smp_fetch_global_pmu() do { } while (0)
 #define smp_fill_in_cpu_possible_map() do { } while (0)
+#define smp_init_cpu_poke() do { } while (0)
+#define scheduler_poke() do { } while (0)
 
 #endif /* !(CONFIG_SMP) */
 
index 2677312..d41ce33 100644 (file)
@@ -189,7 +189,7 @@ void __init sun4v_hvapi_init(void)
 
        group = HV_GRP_CORE;
        major = 1;
-       minor = 1;
+       minor = 6;
        if (sun4v_hvapi_register(group, major, &minor))
                goto bad;
 
index b96104d..44e5da4 100644 (file)
@@ -77,8 +77,13 @@ void arch_cpu_idle(void)
                        : "=&r" (pstate)
                        : "i" (PSTATE_IE));
 
-               if (!need_resched() && !cpu_is_offline(smp_processor_id()))
+               if (!need_resched() && !cpu_is_offline(smp_processor_id())) {
                        sun4v_cpu_yield();
+                       /* If resumed by cpu_poke then we need to explicitly
+                        * call scheduler_ipi().
+                        */
+                       scheduler_poke();
+               }
 
                /* Re-enable interrupts. */
                __asm__ __volatile__(
index 4d9c3e1..f92d5c6 100644 (file)
@@ -356,6 +356,7 @@ void __init start_early_boot(void)
        check_if_starfire();
        per_cpu_patch();
        sun4v_patch();
+       smp_init_cpu_poke();
 
        cpu = hard_smp_processor_id();
        if (cpu >= NR_CPUS) {
index 3218bc4..4898329 100644 (file)
@@ -74,6 +74,9 @@ EXPORT_SYMBOL(cpu_core_sib_cache_map);
 
 static cpumask_t smp_commenced_mask;
 
+static DEFINE_PER_CPU(bool, poke);
+static bool cpu_poke;
+
 void smp_info(struct seq_file *m)
 {
        int i;
@@ -1439,15 +1442,86 @@ void __init smp_cpus_done(unsigned int max_cpus)
 {
 }
 
+static void send_cpu_ipi(int cpu)
+{
+       xcall_deliver((u64) &xcall_receive_signal,
+                       0, 0, cpumask_of(cpu));
+}
+
+void scheduler_poke(void)
+{
+       if (!cpu_poke)
+               return;
+
+       if (!__this_cpu_read(poke))
+               return;
+
+       __this_cpu_write(poke, false);
+       set_softint(1 << PIL_SMP_RECEIVE_SIGNAL);
+}
+
+static unsigned long send_cpu_poke(int cpu)
+{
+       unsigned long hv_err;
+
+       per_cpu(poke, cpu) = true;
+       hv_err = sun4v_cpu_poke(cpu);
+       if (hv_err != HV_EOK) {
+               per_cpu(poke, cpu) = false;
+               pr_err_ratelimited("%s: sun4v_cpu_poke() fails err=%lu\n",
+                                   __func__, hv_err);
+       }
+
+       return hv_err;
+}
+
 void smp_send_reschedule(int cpu)
 {
        if (cpu == smp_processor_id()) {
                WARN_ON_ONCE(preemptible());
                set_softint(1 << PIL_SMP_RECEIVE_SIGNAL);
-       } else {
-               xcall_deliver((u64) &xcall_receive_signal,
-                             0, 0, cpumask_of(cpu));
+               return;
+       }
+
+       /* Use cpu poke to resume idle cpu if supported. */
+       if (cpu_poke && idle_cpu(cpu)) {
+               unsigned long ret;
+
+               ret = send_cpu_poke(cpu);
+               if (ret == HV_EOK)
+                       return;
        }
+
+       /* Use IPI in following cases:
+        * - cpu poke not supported
+        * - cpu not idle
+        * - send_cpu_poke() returns with error
+        */
+       send_cpu_ipi(cpu);
+}
+
+void smp_init_cpu_poke(void)
+{
+       unsigned long major;
+       unsigned long minor;
+       int ret;
+
+       if (tlb_type != hypervisor)
+               return;
+
+       ret = sun4v_hvapi_get(HV_GRP_CORE, &major, &minor);
+       if (ret) {
+               pr_debug("HV_GRP_CORE is not registered\n");
+               return;
+       }
+
+       if (major == 1 && minor >= 6) {
+               /* CPU POKE is registered. */
+               cpu_poke = true;
+               return;
+       }
+
+       pr_debug("CPU_POKE not supported\n");
 }
 
 void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs)