Skip to contentSkip to conversation

riscv: don't stop itself in smp_send_stop

PATCH Superseded Andreas Schwab 3 participants 7 messages Nov 29, 2018 – Jan 3, 2019 RISC-V

v1 of 3 Superseded Latest is v3 →

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 riscv: don't stop itself in smp_send_stop

Only run ipi_stop on other cpus, not itself. Don't wait for ipi_stop to return, since it never does. Also, mark each cpu offline.

---
 arch/riscv/kernel/smp.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)
arch/riscv/kernel/smp.c +16 -1
index 57b1383e5e..5c6bb5fe5a 100644
@@ -23,6 +23,7 @@
 #include <linux/smp.h>
 #include <linux/sched.h>
 #include <linux/seq_file.h>
+#include <linux/delay.h>
 
 #include <asm/sbi.h>
 #include <asm/tlbflush.h>
@@ -148,13 +149,27 @@ void arch_send_call_function_single_ipi(int cpu)
 
 static void ipi_stop(void *unused)
 {
+	set_cpu_online (smp_processor_id(), false);
 	while (1)
 		wait_for_interrupt();
 }
 
 void smp_send_stop(void)
 {
-	on_each_cpu(ipi_stop, NULL, 1);
+	unsigned long timeout;
+	struct cpumask mask;
+
+	cpumask_copy (&mask, cpu_online_mask);
+	cpumask_clear_cpu (smp_processor_id (), &mask);
+	on_each_cpu_mask(&mask, ipi_stop, NULL, 0);
+
+	/* Wait up to one second for other CPUs to stop */
+	timeout = USEC_PER_SEC;
+	while (num_online_cpus() > 1 && timeout--)
+		udelay(1);
+
+	if (num_online_cpus() > 1)
+		pr_warn("SMP: failed to stop secondary CPUs\n");
 }
 
 void smp_send_reschedule(int cpu)
Signature · 12 lines
2.19.2


-- 
Andreas Schwab, SUSE Labs, [email protected]
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

_______________________________________________
linux-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-riscv
#1 lore raw
Quoted 25 lines · Andreas Schwab

Only run ipi_stop on other cpus, not itself. Don't wait for ipi_stop to return, since it never does. Also, mark each cpu offline.

---
  arch/riscv/kernel/smp.c | 17 ++++++++++++++++-
  1 file changed, 16 insertions(+), 1 deletion(-)
arch/riscv/kernel/smp.c +2 -0
index 57b1383e5e..5c6bb5fe5a 100644
@@ -23,6 +23,7 @@
  #include <linux/smp.h>
  #include <linux/sched.h>
  #include <linux/seq_file.h>
+#include <linux/delay.h>
 
  #include <asm/sbi.h>
  #include <asm/tlbflush.h>
@@ -148,13 +149,27 @@ void arch_send_call_function_single_ipi(int cpu)
 
  static void ipi_stop(void *unused)
  {
+	set_cpu_online (smp_processor_id(), false);

arch/riscv/kernel/smp.c void arch_send_call_function_single_ipi(int cpu) · line 161

Quoted 10 lines
arch/riscv/kernel/smp.c +3 -1
  	while (1)
  		wait_for_interrupt();
  }
 
  void smp_send_stop(void)
  {
-	on_each_cpu(ipi_stop, NULL, 1);
+	unsigned long timeout;
+	struct cpumask mask;
+

No need to do mask copy this, if num_online_cpus() == 1.

arch/riscv/kernel/smp.c void arch_send_call_function_single_ipi(int cpu) · line 164

Quoted 3 lines
arch/riscv/kernel/smp.c +3 -0
+	cpumask_copy (&mask, cpu_online_mask);
+	cpumask_clear_cpu (smp_processor_id (), &mask);
+	on_each_cpu_mask(&mask, ipi_stop, NULL, 0);

The function header of on_each_cpu_mask says func should be non-blocking. Not sure if that's a hard requirement or not.

If it is, we can introduce an extra IPI_STOP in ipi_names and just send ipi. The receiving CPU can handle the IPI_STOP.

arch/riscv/kernel/smp.c void arch_send_call_function_single_ipi(int cpu) · line 172

Quoted 8 lines
arch/riscv/kernel/smp.c +8 -0
+
+	/* Wait up to one second for other CPUs to stop */
+	timeout = USEC_PER_SEC;
+	while (num_online_cpus() > 1 && timeout--)
+		udelay(1);
+
+	if (num_online_cpus() > 1)
+		pr_warn("SMP: failed to stop secondary CPUs\n");

May be print the remaining online cpus so that we know which one failed ?

Regards,
Atish

arch/riscv/kernel/smp.c void arch_send_call_function_single_ipi(int cpu) · line 175

Quoted 4 lines
arch/riscv/kernel/smp.c +0 -0
  }
 
  void smp_send_reschedule(int cpu)

_______________________________________________
linux-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-riscv

#2 lore raw
Quoted 6 lines · Atish Patra

arch/riscv/kernel/smp.c void arch_send_call_function_single_ipi(int cpu) · line 164

Quoted 3 lines
arch/riscv/kernel/smp.c +3 -0
+	cpumask_copy (&mask, cpu_online_mask);
+	cpumask_clear_cpu (smp_processor_id (), &mask);
+	on_each_cpu_mask(&mask, ipi_stop, NULL, 0);

The function header of on_each_cpu_mask says func should be non-blocking. Not sure if that's a hard requirement or not.

What does that mean?

Quoted 10 lines

arch/riscv/kernel/smp.c void arch_send_call_function_single_ipi(int cpu) · line 172

Quoted 8 lines
arch/riscv/kernel/smp.c +8 -0
+
+	/* Wait up to one second for other CPUs to stop */
+	timeout = USEC_PER_SEC;
+	while (num_online_cpus() > 1 && timeout--)
+		udelay(1);
+
+	if (num_online_cpus() > 1)
+		pr_warn("SMP: failed to stop secondary CPUs\n");

May be print the remaining online cpus so that we know which one failed ?

I have copied that from arm. The only user of smp_send_stop is panic, which can cope with that, and the probability of that happening is very low anyway.

Andreas.

Signature · 8 lines
Andreas Schwab, SUSE Labs, [email protected]
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

_______________________________________________
linux-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-riscv
#3 lore raw
Quoted 11 lines · Andreas Schwab
Quoted 6 lines · Atish Patra

arch/riscv/kernel/smp.c void arch_send_call_function_single_ipi(int cpu) · line 164

Quoted 3 lines
arch/riscv/kernel/smp.c +3 -0
+	cpumask_copy (&mask, cpu_online_mask);
+	cpumask_clear_cpu (smp_processor_id (), &mask);
+	on_each_cpu_mask(&mask, ipi_stop, NULL, 0);

The function header of on_each_cpu_mask says func should be non-blocking. Not sure if that's a hard requirement or not.

What does that mean?

https://elixir.bootlin.com/linux/v4.20-rc6/source/kernel/smp.c#L617

Quoted 11 lines
Quoted 10 lines

arch/riscv/kernel/smp.c void arch_send_call_function_single_ipi(int cpu) · line 172

Quoted 8 lines
arch/riscv/kernel/smp.c +8 -0
+
+	/* Wait up to one second for other CPUs to stop */
+	timeout = USEC_PER_SEC;
+	while (num_online_cpus() > 1 && timeout--)
+		udelay(1);
+
+	if (num_online_cpus() > 1)
+		pr_warn("SMP: failed to stop secondary CPUs\n");

May be print the remaining online cpus so that we know which one failed ?

Quoted 4 lines

I have copied that from arm. The only user of smp_send_stop is panic, which can cope with that, and the probability of that happening is very low anyway.

My suggestion was based on arm64 code. IMHO, it makes more sense to follow arm64 code than arm.

https://elixir.bootlin.com/linux/v4.20-rc6/source/arch/arm64/kernel/smp.c#L955

Regards,
Atish

Quoted 2 lines

Andreas.

_______________________________________________
linux-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-riscv

#4 lore raw

PATCH v2 1/1 riscv: don't stop itself in smp_send_stop

In reply to Andreas Schwab

Add IPI_CPU_STOP message and use it in smp_send_stop to stop other cpus, but not itself. Mark cpu offline on reception of IPI_CPU_STOP.

---
 arch/riscv/kernel/smp.c | 43 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 36 insertions(+), 7 deletions(-)
arch/riscv/kernel/smp.c +36 -7
index 57b1383e5e..b813264416 100644
@@ -23,6 +23,7 @@
 #include <linux/smp.h>
 #include <linux/sched.h>
 #include <linux/seq_file.h>
+#include <linux/delay.h>
 
 #include <asm/sbi.h>
 #include <asm/tlbflush.h>
@@ -31,6 +32,7 @@
 enum ipi_message_type {
 	IPI_RESCHEDULE,
 	IPI_CALL_FUNC,
+	IPI_CPU_STOP,
 	IPI_MAX
 };
 
@@ -66,6 +68,13 @@ int setup_profiling_timer(unsigned int multiplier)
 	return -EINVAL;
 }
 
+static void ipi_stop(void)
+{
+	set_cpu_online (smp_processor_id(), false);
+	while (1)
+		wait_for_interrupt();
+}
+
 void riscv_software_interrupt(void)
 {
 	unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
@@ -94,6 +103,11 @@ void riscv_software_interrupt(void)
 			generic_smp_call_function_interrupt();
 		}
 
+		if (ops & (1 << IPI_CPU_STOP)) {
+			stats[IPI_CPU_STOP]++;
+			ipi_stop();
+		}
+
 		BUG_ON((ops >> IPI_MAX) != 0);
 
 		/* Order data access and bit testing. */
@@ -121,6 +135,7 @@ send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation)
 static const char * const ipi_names[] = {
 	[IPI_RESCHEDULE]	= "Rescheduling interrupts",
 	[IPI_CALL_FUNC]		= "Function call interrupts",
+	[IPI_CPU_STOP]		= "CPU stop interrupts",
 };
 
 void show_ipi_stats(struct seq_file *p, int prec)
@@ -146,15 +161,29 @@ void arch_send_call_function_single_ipi(int cpu)
 	send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC);
 }
 
-static void ipi_stop(void *unused)
-{
-	while (1)
-		wait_for_interrupt();
-}
-
 void smp_send_stop(void)
 {
-	on_each_cpu(ipi_stop, NULL, 1);
+	unsigned long timeout;
+
+	if (num_online_cpus() > 1) {
+		cpumask_t mask;
+
+		cpumask_copy(&mask, cpu_online_mask);
+		cpumask_clear_cpu(smp_processor_id(), &mask);
+
+		if (system_state <= SYSTEM_RUNNING)
+			pr_crit("SMP: stopping secondary CPUs\n");
+		send_ipi_message(&mask, IPI_CPU_STOP);
+	}
+
+	/* Wait up to one second for other CPUs to stop */
+	timeout = USEC_PER_SEC;
+	while (num_online_cpus() > 1 && timeout--)
+		udelay(1);
+
+	if (num_online_cpus() > 1)
+		pr_warning("SMP: failed to stop secondary CPUs %*pbl\n",
+			   cpumask_pr_args(cpu_online_mask));
 }
 
 void smp_send_reschedule(int cpu)
Signature · 12 lines
2.20.0


-- 
Andreas Schwab, SUSE Labs, [email protected]
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

_______________________________________________
linux-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-riscv
Reviewed-by on v2 1/1
#5 lore raw
Quoted 90 lines · Andreas Schwab

Add IPI_CPU_STOP message and use it in smp_send_stop to stop other cpus, but not itself. Mark cpu offline on reception of IPI_CPU_STOP.

---
  arch/riscv/kernel/smp.c | 43 ++++++++++++++++++++++++++++++++++-------
  1 file changed, 36 insertions(+), 7 deletions(-)
arch/riscv/kernel/smp.c +29 -7
index 57b1383e5e..b813264416 100644
@@ -23,6 +23,7 @@
  #include <linux/smp.h>
  #include <linux/sched.h>
  #include <linux/seq_file.h>
+#include <linux/delay.h>
 
  #include <asm/sbi.h>
  #include <asm/tlbflush.h>
@@ -31,6 +32,7 @@
  enum ipi_message_type {
  	IPI_RESCHEDULE,
  	IPI_CALL_FUNC,
+	IPI_CPU_STOP,
  	IPI_MAX
  };
 
@@ -66,6 +68,13 @@ int setup_profiling_timer(unsigned int multiplier)
  	return -EINVAL;
  }
 
+static void ipi_stop(void)
+{
+	set_cpu_online (smp_processor_id(), false);
+	while (1)
+		wait_for_interrupt();
+}
+
  void riscv_software_interrupt(void)
  {
  	unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
@@ -94,6 +103,11 @@ void riscv_software_interrupt(void)
  			generic_smp_call_function_interrupt();
  		}
 
+		if (ops & (1 << IPI_CPU_STOP)) {
+			stats[IPI_CPU_STOP]++;
+			ipi_stop();
+		}
+
  		BUG_ON((ops >> IPI_MAX) != 0);
 
  		/* Order data access and bit testing. */
@@ -121,6 +135,7 @@ send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation)
  static const char * const ipi_names[] = {
  	[IPI_RESCHEDULE]	= "Rescheduling interrupts",
  	[IPI_CALL_FUNC]		= "Function call interrupts",
+	[IPI_CPU_STOP]		= "CPU stop interrupts",
  };
 
  void show_ipi_stats(struct seq_file *p, int prec)
@@ -146,15 +161,29 @@ void arch_send_call_function_single_ipi(int cpu)
  	send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC);
  }
 
-static void ipi_stop(void *unused)
-{
-	while (1)
-		wait_for_interrupt();
-}
-
  void smp_send_stop(void)
  {
-	on_each_cpu(ipi_stop, NULL, 1);
+	unsigned long timeout;
+
+	if (num_online_cpus() > 1) {
+		cpumask_t mask;
+
+		cpumask_copy(&mask, cpu_online_mask);
+		cpumask_clear_cpu(smp_processor_id(), &mask);
+
+		if (system_state <= SYSTEM_RUNNING)
+			pr_crit("SMP: stopping secondary CPUs\n");
+		send_ipi_message(&mask, IPI_CPU_STOP);
+	}
+
+	/* Wait up to one second for other CPUs to stop */

arch/riscv/kernel/smp.c void arch_send_call_function_single_ipi(int cpu) · line 189

Quoted 10 lines
arch/riscv/kernel/smp.c +7 -0
+	timeout = USEC_PER_SEC;
+	while (num_online_cpus() > 1 && timeout--)
+		udelay(1);
+
+	if (num_online_cpus() > 1)
+		pr_warning("SMP: failed to stop secondary CPUs %*pbl\n",
+			   cpumask_pr_args(cpu_online_mask));
  }
 
  void smp_send_reschedule(int cpu)

Checkpatch warnings.
WARNING: space prohibited between function name and open parenthesis '(' #40: FILE: arch/riscv/kernel/smp.c:73:
+ set_cpu_online (smp_processor_id(), false);

WARNING: Prefer pr_warn(... to pr_warning(...
#100: FILE: arch/riscv/kernel/smp.c:185:
+ pr_warning("SMP: failed to stop secondary CPUs %*pbl\n",

Otherwise, Looks good to me.

Regards,
Atish

_______________________________________________
linux-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-riscv

#6 lore raw
Quoted 107 lines · On Thu, 13 Dec 2018 15:27:36 PST (-0800), [email protected] wrote:
Quoted 90 lines · Andreas Schwab

Add IPI_CPU_STOP message and use it in smp_send_stop to stop other cpus, but not itself. Mark cpu offline on reception of IPI_CPU_STOP.

---
  arch/riscv/kernel/smp.c | 43 ++++++++++++++++++++++++++++++++++-------
  1 file changed, 36 insertions(+), 7 deletions(-)
arch/riscv/kernel/smp.c +29 -7
index 57b1383e5e..b813264416 100644
@@ -23,6 +23,7 @@
  #include <linux/smp.h>
  #include <linux/sched.h>
  #include <linux/seq_file.h>
+#include <linux/delay.h>
 
  #include <asm/sbi.h>
  #include <asm/tlbflush.h>
@@ -31,6 +32,7 @@
  enum ipi_message_type {
  	IPI_RESCHEDULE,
  	IPI_CALL_FUNC,
+	IPI_CPU_STOP,
  	IPI_MAX
  };
 
@@ -66,6 +68,13 @@ int setup_profiling_timer(unsigned int multiplier)
  	return -EINVAL;
  }
 
+static void ipi_stop(void)
+{
+	set_cpu_online (smp_processor_id(), false);
+	while (1)
+		wait_for_interrupt();
+}
+
  void riscv_software_interrupt(void)
  {
  	unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
@@ -94,6 +103,11 @@ void riscv_software_interrupt(void)
  			generic_smp_call_function_interrupt();
  		}
 
+		if (ops & (1 << IPI_CPU_STOP)) {
+			stats[IPI_CPU_STOP]++;
+			ipi_stop();
+		}
+
  		BUG_ON((ops >> IPI_MAX) != 0);
 
  		/* Order data access and bit testing. */
@@ -121,6 +135,7 @@ send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation)
  static const char * const ipi_names[] = {
  	[IPI_RESCHEDULE]	= "Rescheduling interrupts",
  	[IPI_CALL_FUNC]		= "Function call interrupts",
+	[IPI_CPU_STOP]		= "CPU stop interrupts",
  };
 
  void show_ipi_stats(struct seq_file *p, int prec)
@@ -146,15 +161,29 @@ void arch_send_call_function_single_ipi(int cpu)
  	send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC);
  }
 
-static void ipi_stop(void *unused)
-{
-	while (1)
-		wait_for_interrupt();
-}
-
  void smp_send_stop(void)
  {
-	on_each_cpu(ipi_stop, NULL, 1);
+	unsigned long timeout;
+
+	if (num_online_cpus() > 1) {
+		cpumask_t mask;
+
+		cpumask_copy(&mask, cpu_online_mask);
+		cpumask_clear_cpu(smp_processor_id(), &mask);
+
+		if (system_state <= SYSTEM_RUNNING)
+			pr_crit("SMP: stopping secondary CPUs\n");
+		send_ipi_message(&mask, IPI_CPU_STOP);
+	}
+
+	/* Wait up to one second for other CPUs to stop */

arch/riscv/kernel/smp.c void arch_send_call_function_single_ipi(int cpu) · line 189

Quoted 10 lines
arch/riscv/kernel/smp.c +7 -0
+	timeout = USEC_PER_SEC;
+	while (num_online_cpus() > 1 && timeout--)
+		udelay(1);
+
+	if (num_online_cpus() > 1)
+		pr_warning("SMP: failed to stop secondary CPUs %*pbl\n",
+			   cpumask_pr_args(cpu_online_mask));
  }
 
  void smp_send_reschedule(int cpu)

Checkpatch warnings.
WARNING: space prohibited between function name and open parenthesis '(' #40: FILE: arch/riscv/kernel/smp.c:73:
+ set_cpu_online (smp_processor_id(), false);

Quoted 7 lines

WARNING: Prefer pr_warn(... to pr_warning(...
#100: FILE: arch/riscv/kernel/smp.c:185:
+ pr_warning("SMP: failed to stop secondary CPUs %*pbl\n",

Otherwise, Looks good to me.

I've fixed these up and added the patch to my fix queue, it should go up next week.

Thanks!

_______________________________________________
linux-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-riscv