[RFC PATCH 2/2] RISCV: Support cpu hotplug.

2018-04-13 Thread Atish Patra
This patch enable support for cpu hotplug in RISC-V.

In absensece of generic cpu stop functions, WFI is used
to put the cpu in low power state during offline. An IPI
is sent to bring it out of WFI during online operation.

Tested both on QEMU and HighFive Unleashed board with
4 cpus. Test result follows.

$ echo 0 > /sys/devices/system/cpu/cpu2/online
[   31.828562] CPU2: shutdown
$ cat /proc/cpuinfo
hart: 1
isa : rv64imafdc
mmu : sv39
uarch   : sifive,rocket0

hart: 3
isa : rv64imafdc
mmu : sv39
uarch   : sifive,rocket0

hart: 4
isa : rv64imafdc
mmu : sv39
uarch   : sifive,rocket0

$ echo 0 > /sys/devices/system/cpu/cpu4/online
[   52.968495] CPU4: shutdown
$ cat /proc/cpuinfo
hart: 1
isa : rv64imafdc
mmu : sv39
uarch   : sifive,rocket0

hart: 3
isa : rv64imafdc
mmu : sv39
uarch   : sifive,rocket0

$ echo 1 > /sys/devices/system/cpu/cpu4/online
[   64.298250] CPU4: online
$ cat /proc/cpuinfo
hart: 1
isa : rv64imafdc
mmu : sv39
uarch   : sifive,rocket0

hart: 3
isa : rv64imafdc
mmu : sv39
uarch   : sifive,rocket0

hart: 4
isa : rv64imafdc
mmu : sv39
uarch   : sifive,rocket0

Signed-off-by: Atish Patra 
---
 arch/riscv/Kconfig   | 11 ++-
 arch/riscv/include/asm/csr.h |  1 +
 arch/riscv/include/asm/smp.h |  9 --
 arch/riscv/kernel/head.S | 12 
 arch/riscv/kernel/process.c  |  7 +
 arch/riscv/kernel/setup.c| 17 +++
 arch/riscv/kernel/smpboot.c  | 70 ++--
 arch/riscv/kernel/traps.c|  6 ++--
 8 files changed, 123 insertions(+), 10 deletions(-)

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 578f966..5ae307b 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -14,7 +14,6 @@ config RISCV
select CLONE_BACKWARDS
select COMMON_CLK
select GENERIC_CLOCKEVENTS
-   select GENERIC_CPU_DEVICES
select GENERIC_IRQ_SHOW
select GENERIC_PCI_IOMAP
select GENERIC_STRNCPY_FROM_USER
@@ -178,6 +177,16 @@ config NR_CPUS
depends on SMP
default "8"
 
+config HOTPLUG_CPU
+   bool "Support for hot-pluggable CPUs"
+   select GENERIC_IRQ_MIGRATION
+   help
+
+ Say Y here to experiment with turning CPUs off and on.  CPUs
+ can be controlled through /sys/devices/system/cpu.
+
+ Say N if you want to disable CPU hotplug.
+
 config CPU_SUPPORTS_32BIT_KERNEL
bool
 config CPU_SUPPORTS_64BIT_KERNEL
diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 421fa35..1baf8e0 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -54,6 +54,7 @@
 /* Interrupt Enable and Interrupt Pending flags */
 #define SIE_SSIE _AC(0x0002, UL) /* Software Interrupt Enable */
 #define SIE_STIE _AC(0x0020, UL) /* Timer Interrupt Enable */
+#define SIE_SEIE _AC(0x00200, UL) /* External Interrupt Enable */
 
 #define EXC_INST_MISALIGNED 0
 #define EXC_INST_ACCESS 1
diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h
index 01b8df8..e78b7f1 100644
--- a/arch/riscv/include/asm/smp.h
+++ b/arch/riscv/include/asm/smp.h
@@ -25,9 +25,6 @@
 #ifdef CONFIG_SMP
 
 /* SMP initialization hook for setup_arch */
-void init_clockevent(void);
-
-/* SMP initialization hook for setup_arch */
 void __init setup_smp(void);
 
 /* Hook for the generic smp_call_function_many() routine. */
@@ -47,6 +44,12 @@ void arch_send_call_function_single_ipi(int cpu);
 /* Interprocessor interrupt handler */
 irqreturn_t handle_ipi(void);
 
+#ifdef CONFIG_HOTPLUG_CPU
+extern int __cpu_disable(void);
+extern void __cpu_die(unsigned int cpu);
+extern void cpu_play_dead(void);
+extern void boot_sec_cpu(void);
+#endif
 #endif /* CONFIG_SMP */
 
 #endif /* _ASM_RISCV_SMP_H */
diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
index 226eeb1..63d478d 100644
--- a/arch/riscv/kernel/head.S
+++ b/arch/riscv/kernel/head.S
@@ -149,6 +149,18 @@ relocate:
j .Lsecondary_park
 END(_start)
 
+.section .text
+.global boot_sec_cpu
+
+boot_sec_cpu:
+   /* clear all pending flags */
+   csrw sip, zero
+   /* Mask all interrupts */
+   csrw sie, zero
+   fence
+
+   tail smp_callin
+
 __PAGE_ALIGNED_BSS
/* Empty zero page */
.balign PAGE_SIZE
diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
index d74d4ad..c5e2234 100644
--- a/arch/riscv/kernel/process.c
+++ b/arch/riscv/kernel/process.c
@@ -42,6 +42,13 @@ void arch_cpu_idle(void)
local_irq_enable();
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+void arch_cpu_idle_dead(void)
+{
+   cpu_play_dead();
+}
+#endif
+
 void show_regs(struct pt_regs *regs)
 {
show_regs_print_info(KERN_DEFAULT);
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
index a1d5853..4ef8a8b 100644
--- a/arch/riscv/kernel/setup.c
+++ b/arch/riscv/kernel/setup.c
@@ -81,6 +81,7 @@ 

[RFC PATCH 2/2] RISCV: Support cpu hotplug.

2018-04-13 Thread Atish Patra
This patch enable support for cpu hotplug in RISC-V.

In absensece of generic cpu stop functions, WFI is used
to put the cpu in low power state during offline. An IPI
is sent to bring it out of WFI during online operation.

Tested both on QEMU and HighFive Unleashed board with
4 cpus. Test result follows.

$ echo 0 > /sys/devices/system/cpu/cpu2/online
[   31.828562] CPU2: shutdown
$ cat /proc/cpuinfo
hart: 1
isa : rv64imafdc
mmu : sv39
uarch   : sifive,rocket0

hart: 3
isa : rv64imafdc
mmu : sv39
uarch   : sifive,rocket0

hart: 4
isa : rv64imafdc
mmu : sv39
uarch   : sifive,rocket0

$ echo 0 > /sys/devices/system/cpu/cpu4/online
[   52.968495] CPU4: shutdown
$ cat /proc/cpuinfo
hart: 1
isa : rv64imafdc
mmu : sv39
uarch   : sifive,rocket0

hart: 3
isa : rv64imafdc
mmu : sv39
uarch   : sifive,rocket0

$ echo 1 > /sys/devices/system/cpu/cpu4/online
[   64.298250] CPU4: online
$ cat /proc/cpuinfo
hart: 1
isa : rv64imafdc
mmu : sv39
uarch   : sifive,rocket0

hart: 3
isa : rv64imafdc
mmu : sv39
uarch   : sifive,rocket0

hart: 4
isa : rv64imafdc
mmu : sv39
uarch   : sifive,rocket0

Signed-off-by: Atish Patra 
---
 arch/riscv/Kconfig   | 11 ++-
 arch/riscv/include/asm/csr.h |  1 +
 arch/riscv/include/asm/smp.h |  9 --
 arch/riscv/kernel/head.S | 12 
 arch/riscv/kernel/process.c  |  7 +
 arch/riscv/kernel/setup.c| 17 +++
 arch/riscv/kernel/smpboot.c  | 70 ++--
 arch/riscv/kernel/traps.c|  6 ++--
 8 files changed, 123 insertions(+), 10 deletions(-)

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 578f966..5ae307b 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -14,7 +14,6 @@ config RISCV
select CLONE_BACKWARDS
select COMMON_CLK
select GENERIC_CLOCKEVENTS
-   select GENERIC_CPU_DEVICES
select GENERIC_IRQ_SHOW
select GENERIC_PCI_IOMAP
select GENERIC_STRNCPY_FROM_USER
@@ -178,6 +177,16 @@ config NR_CPUS
depends on SMP
default "8"
 
+config HOTPLUG_CPU
+   bool "Support for hot-pluggable CPUs"
+   select GENERIC_IRQ_MIGRATION
+   help
+
+ Say Y here to experiment with turning CPUs off and on.  CPUs
+ can be controlled through /sys/devices/system/cpu.
+
+ Say N if you want to disable CPU hotplug.
+
 config CPU_SUPPORTS_32BIT_KERNEL
bool
 config CPU_SUPPORTS_64BIT_KERNEL
diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 421fa35..1baf8e0 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -54,6 +54,7 @@
 /* Interrupt Enable and Interrupt Pending flags */
 #define SIE_SSIE _AC(0x0002, UL) /* Software Interrupt Enable */
 #define SIE_STIE _AC(0x0020, UL) /* Timer Interrupt Enable */
+#define SIE_SEIE _AC(0x00200, UL) /* External Interrupt Enable */
 
 #define EXC_INST_MISALIGNED 0
 #define EXC_INST_ACCESS 1
diff --git a/arch/riscv/include/asm/smp.h b/arch/riscv/include/asm/smp.h
index 01b8df8..e78b7f1 100644
--- a/arch/riscv/include/asm/smp.h
+++ b/arch/riscv/include/asm/smp.h
@@ -25,9 +25,6 @@
 #ifdef CONFIG_SMP
 
 /* SMP initialization hook for setup_arch */
-void init_clockevent(void);
-
-/* SMP initialization hook for setup_arch */
 void __init setup_smp(void);
 
 /* Hook for the generic smp_call_function_many() routine. */
@@ -47,6 +44,12 @@ void arch_send_call_function_single_ipi(int cpu);
 /* Interprocessor interrupt handler */
 irqreturn_t handle_ipi(void);
 
+#ifdef CONFIG_HOTPLUG_CPU
+extern int __cpu_disable(void);
+extern void __cpu_die(unsigned int cpu);
+extern void cpu_play_dead(void);
+extern void boot_sec_cpu(void);
+#endif
 #endif /* CONFIG_SMP */
 
 #endif /* _ASM_RISCV_SMP_H */
diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
index 226eeb1..63d478d 100644
--- a/arch/riscv/kernel/head.S
+++ b/arch/riscv/kernel/head.S
@@ -149,6 +149,18 @@ relocate:
j .Lsecondary_park
 END(_start)
 
+.section .text
+.global boot_sec_cpu
+
+boot_sec_cpu:
+   /* clear all pending flags */
+   csrw sip, zero
+   /* Mask all interrupts */
+   csrw sie, zero
+   fence
+
+   tail smp_callin
+
 __PAGE_ALIGNED_BSS
/* Empty zero page */
.balign PAGE_SIZE
diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
index d74d4ad..c5e2234 100644
--- a/arch/riscv/kernel/process.c
+++ b/arch/riscv/kernel/process.c
@@ -42,6 +42,13 @@ void arch_cpu_idle(void)
local_irq_enable();
 }
 
+#ifdef CONFIG_HOTPLUG_CPU
+void arch_cpu_idle_dead(void)
+{
+   cpu_play_dead();
+}
+#endif
+
 void show_regs(struct pt_regs *regs)
 {
show_regs_print_info(KERN_DEFAULT);
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
index a1d5853..4ef8a8b 100644
--- a/arch/riscv/kernel/setup.c
+++ b/arch/riscv/kernel/setup.c
@@ -81,6 +81,7 @@