Commit 46859ac8 authored by Huacai Chen's avatar Huacai Chen
Browse files

LoongArch: Add multi-processor (SMP) support



LoongArch-based procesors have 4, 8 or 16 cores per package. This patch
adds multi-processor (SMP) support for LoongArch.

Reviewed-by: default avatarWANG Xuerui <git@xen0n.name>
Reviewed-by: default avatarJiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: default avatarHuacai Chen <chenhuacai@loongson.cn>
parent c6b99bed
Loading
Loading
Loading
Loading
+39 −1
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ config LOONGARCH
	select GENERIC_LIB_UCMPDI2
	select GENERIC_PCI_IOMAP
	select GENERIC_SCHED_CLOCK
	select GENERIC_SMP_IDLE_THREAD
	select GENERIC_TIME_VSYSCALL
	select GPIOLIB
	select HAVE_ARCH_AUDITSYSCALL
@@ -92,7 +93,7 @@ config LOONGARCH
	select HAVE_RSEQ
	select HAVE_SYSCALL_TRACEPOINTS
	select HAVE_TIF_NOHZ
	select HAVE_VIRT_CPU_ACCOUNTING_GEN
	select HAVE_VIRT_CPU_ACCOUNTING_GEN if !SMP
	select IRQ_FORCED_THREADING
	select IRQ_LOONGARCH_CPU
	select MODULES_USE_ELF_RELA if MODULES
@@ -297,6 +298,43 @@ config EFI
	  This enables the kernel to use EFI runtime services that are
	  available (such as the EFI variable services).

config SMP
	bool "Multi-Processing support"
	help
	  This enables support for systems with more than one CPU. If you have
	  a system with only one CPU, say N. If you have a system with more
	  than one CPU, say Y.

	  If you say N here, the kernel will run on uni- and multiprocessor
	  machines, but will use only one CPU of a multiprocessor machine. If
	  you say Y here, the kernel will run on many, but not all,
	  uniprocessor machines. On a uniprocessor machine, the kernel
	  will run faster if you say N here.

	  See also the SMP-HOWTO available at <http://www.tldp.org/docs.html#howto>.

	  If you don't know what to do here, say N.

config HOTPLUG_CPU
	bool "Support for hot-pluggable CPUs"
	depends on SMP
	select GENERIC_IRQ_MIGRATION
	help
	  Say Y here to allow turning CPUs off and on. CPUs can be
	  controlled through /sys/devices/system/cpu.
	  (Note: power management support will enable this option
	    automatically on SMP systems. )
	  Say N if you want to disable CPU hotplug.

config NR_CPUS
	int "Maximum number of CPUs (2-256)"
	range 2 256
	depends on SMP
	default "64"
	help
	  This allows you to specify the maximum number of CPUs which this
	  kernel will support.

config FORCE_MAX_ZONEORDER
	int "Maximum zone order"
	range 14 64 if PAGE_SIZE_64KB
+4 −0
Original line number Diff line number Diff line
@@ -162,6 +162,7 @@ static inline int arch_atomic_sub_if_positive(int i, atomic_t *v)
		"	sc.w	%1, %2					\n"
		"	beq	$zero, %1, 1b				\n"
		"2:							\n"
		__WEAK_LLSC_MB
		: "=&r" (result), "=&r" (temp),
		  "+" GCC_OFF_SMALL_ASM() (v->counter)
		: "I" (-i));
@@ -174,6 +175,7 @@ static inline int arch_atomic_sub_if_positive(int i, atomic_t *v)
		"	sc.w	%1, %2					\n"
		"	beq	$zero, %1, 1b				\n"
		"2:							\n"
		__WEAK_LLSC_MB
		: "=&r" (result), "=&r" (temp),
		  "+" GCC_OFF_SMALL_ASM() (v->counter)
		: "r" (i));
@@ -323,6 +325,7 @@ static inline long arch_atomic64_sub_if_positive(long i, atomic64_t *v)
		"	sc.d	%1, %2					\n"
		"	beq	%1, $zero, 1b				\n"
		"2:							\n"
		__WEAK_LLSC_MB
		: "=&r" (result), "=&r" (temp),
		  "+" GCC_OFF_SMALL_ASM() (v->counter)
		: "I" (-i));
@@ -335,6 +338,7 @@ static inline long arch_atomic64_sub_if_positive(long i, atomic64_t *v)
		"	sc.d	%1, %2					\n"
		"	beq	%1, $zero, 1b				\n"
		"2:							\n"
		__WEAK_LLSC_MB
		: "=&r" (result), "=&r" (temp),
		  "+" GCC_OFF_SMALL_ASM() (v->counter)
		: "r" (i));
+108 −0
Original line number Diff line number Diff line
@@ -18,6 +18,19 @@
#define mb()		fast_mb()
#define iob()		fast_iob()

#define __smp_mb()	__asm__ __volatile__("dbar 0" : : : "memory")
#define __smp_rmb()	__asm__ __volatile__("dbar 0" : : : "memory")
#define __smp_wmb()	__asm__ __volatile__("dbar 0" : : : "memory")

#ifdef CONFIG_SMP
#define __WEAK_LLSC_MB		"	dbar 0  \n"
#else
#define __WEAK_LLSC_MB		"		\n"
#endif

#define __smp_mb__before_atomic()	barrier()
#define __smp_mb__after_atomic()	barrier()

/**
 * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise
 * @index: array element index
@@ -46,6 +59,101 @@ static inline unsigned long array_index_mask_nospec(unsigned long index,
	return mask;
}

#define __smp_load_acquire(p)							\
({										\
	union { typeof(*p) __val; char __c[1]; } __u;				\
	unsigned long __tmp = 0;							\
	compiletime_assert_atomic_type(*p);					\
	switch (sizeof(*p)) {							\
	case 1:									\
		*(__u8 *)__u.__c = *(volatile __u8 *)p;				\
		__smp_mb();							\
		break;								\
	case 2:									\
		*(__u16 *)__u.__c = *(volatile __u16 *)p;			\
		__smp_mb();							\
		break;								\
	case 4:									\
		__asm__ __volatile__(						\
		"amor_db.w %[val], %[tmp], %[mem]	\n"				\
		: [val] "=&r" (*(__u32 *)__u.__c)				\
		: [mem] "ZB" (*(u32 *) p), [tmp] "r" (__tmp)			\
		: "memory");							\
		break;								\
	case 8:									\
		__asm__ __volatile__(						\
		"amor_db.d %[val], %[tmp], %[mem]	\n"				\
		: [val] "=&r" (*(__u64 *)__u.__c)				\
		: [mem] "ZB" (*(u64 *) p), [tmp] "r" (__tmp)			\
		: "memory");							\
		break;								\
	}									\
	(typeof(*p))__u.__val;								\
})

#define __smp_store_release(p, v)						\
do {										\
	union { typeof(*p) __val; char __c[1]; } __u =				\
		{ .__val = (__force typeof(*p)) (v) };				\
	unsigned long __tmp;							\
	compiletime_assert_atomic_type(*p);					\
	switch (sizeof(*p)) {							\
	case 1:									\
		__smp_mb();							\
		*(volatile __u8 *)p = *(__u8 *)__u.__c;				\
		break;								\
	case 2:									\
		__smp_mb();							\
		*(volatile __u16 *)p = *(__u16 *)__u.__c;			\
		break;								\
	case 4:									\
		__asm__ __volatile__(						\
		"amswap_db.w %[tmp], %[val], %[mem]	\n"			\
		: [mem] "+ZB" (*(u32 *)p), [tmp] "=&r" (__tmp)			\
		: [val] "r" (*(__u32 *)__u.__c)					\
		: );								\
		break;								\
	case 8:									\
		__asm__ __volatile__(						\
		"amswap_db.d %[tmp], %[val], %[mem]	\n"			\
		: [mem] "+ZB" (*(u64 *)p), [tmp] "=&r" (__tmp)			\
		: [val] "r" (*(__u64 *)__u.__c)					\
		: );								\
		break;								\
	}									\
} while (0)

#define __smp_store_mb(p, v)							\
do {										\
	union { typeof(p) __val; char __c[1]; } __u =				\
		{ .__val = (__force typeof(p)) (v) };				\
	unsigned long __tmp;							\
	switch (sizeof(p)) {							\
	case 1:									\
		*(volatile __u8 *)&p = *(__u8 *)__u.__c;			\
		__smp_mb();							\
		break;								\
	case 2:									\
		*(volatile __u16 *)&p = *(__u16 *)__u.__c;			\
		__smp_mb();							\
		break;								\
	case 4:									\
		__asm__ __volatile__(						\
		"amswap_db.w %[tmp], %[val], %[mem]	\n"			\
		: [mem] "+ZB" (*(u32 *)&p), [tmp] "=&r" (__tmp)			\
		: [val] "r" (*(__u32 *)__u.__c)					\
		: );								\
		break;								\
	case 8:									\
		__asm__ __volatile__(						\
		"amswap_db.d %[tmp], %[val], %[mem]	\n"			\
		: [mem] "+ZB" (*(u64 *)&p), [tmp] "=&r" (__tmp)			\
		: [val] "r" (*(__u64 *)__u.__c)					\
		: );								\
		break;								\
	}									\
} while (0)

#include <asm-generic/barrier.h>

#endif /* __ASM_BARRIER_H */
+1 −0
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ static inline unsigned long __xchg(volatile void *ptr, unsigned long x,
	"	" st "	$t0, %1				\n"		\
	"	beq	$zero, $t0, 1b			\n"		\
	"2:						\n"		\
	__WEAK_LLSC_MB							\
	: "=&r" (__ret), "=ZB"(*m)					\
	: "ZB"(*m), "Jr" (old), "Jr" (new)				\
	: "t0", "memory");						\
+1 −0
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newv
	"2:	sc.w	$t0, %2					\n"
	"	beq	$zero, $t0, 1b				\n"
	"3:							\n"
	__WEAK_LLSC_MB
	"	.section .fixup,\"ax\"				\n"
	"4:	li.d	%0, %6					\n"
	"	b	3b					\n"
Loading