xtensa: SMP: rework IPI processing
authorMax Filippov <jcmvbkbc@gmail.com>
Sat, 19 Jan 2019 02:45:17 +0000 (18:45 -0800)
committerMax Filippov <jcmvbkbc@gmail.com>
Thu, 7 Feb 2019 20:16:17 +0000 (12:16 -0800)
Don't skip current CPU in send_ipi_message: callers of this function
take care of it and it's harmless anyway.
Don't clear IPI bits one by one, clear all that were read at once.
Check IPI register in a loop in case new IPI was posted while previous
was being handled.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
arch/xtensa/kernel/smp.c

index be1f280c322cd17307e0377736abdb3d955e3ebc..3699d6d3e47997d394752e1689a38d460a6eb914 100644 (file)
@@ -372,8 +372,7 @@ static void send_ipi_message(const struct cpumask *callmask,
        unsigned long mask = 0;
 
        for_each_cpu(index, callmask)
-               if (index != smp_processor_id())
-                       mask |= 1 << index;
+               mask |= 1 << index;
 
        set_er(mask, MIPISET(msg_id));
 }
@@ -412,22 +411,31 @@ irqreturn_t ipi_interrupt(int irq, void *dev_id)
 {
        unsigned int cpu = smp_processor_id();
        struct ipi_data *ipi = &per_cpu(ipi_data, cpu);
-       unsigned int msg;
-       unsigned i;
 
-       msg = get_er(MIPICAUSE(cpu));
-       for (i = 0; i < IPI_MAX; i++)
-               if (msg & (1 << i)) {
-                       set_er(1 << i, MIPICAUSE(cpu));
-                       ++ipi->ipi_count[i];
+       for (;;) {
+               unsigned int msg;
+
+               msg = get_er(MIPICAUSE(cpu));
+               set_er(msg, MIPICAUSE(cpu));
+
+               if (!msg)
+                       break;
+
+               if (msg & (1 << IPI_CALL_FUNC)) {
+                       ++ipi->ipi_count[IPI_CALL_FUNC];
+                       generic_smp_call_function_interrupt();
                }
 
-       if (msg & (1 << IPI_RESCHEDULE))
-               scheduler_ipi();
-       if (msg & (1 << IPI_CALL_FUNC))
-               generic_smp_call_function_interrupt();
-       if (msg & (1 << IPI_CPU_STOP))
-               ipi_cpu_stop(cpu);
+               if (msg & (1 << IPI_RESCHEDULE)) {
+                       ++ipi->ipi_count[IPI_RESCHEDULE];
+                       scheduler_ipi();
+               }
+
+               if (msg & (1 << IPI_CPU_STOP)) {
+                       ++ipi->ipi_count[IPI_CPU_STOP];
+                       ipi_cpu_stop(cpu);
+               }
+       }
 
        return IRQ_HANDLED;
 }