diff --git a/arch/sw_64/Kconfig b/arch/sw_64/Kconfig index 30e63a5616fab03795c16c582f738186bae335f2..130a177a75362e16c339c0dcbdf36e7381de5cfc 100644 --- a/arch/sw_64/Kconfig +++ b/arch/sw_64/Kconfig @@ -5,8 +5,11 @@ config SW64 select ACPI select ACPI_GENERIC_GSI if ACPI select ACPI_MCFG if (ACPI && PCI) + select ACPI_PPTT if ACPI select ACPI_REDUCED_HARDWARE_ONLY + select ACPI_SYSTEM_POWER_STATES_SUPPORT if ACPI select ARCH_ATOMIC + select ARCH_CLOCKSOURCE_INIT select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_PHYS_TO_DMA @@ -59,7 +62,9 @@ config SW64 select AUDIT_ARCH select COMMON_CLK select DMA_OPS if PCI + select GENERIC_ARCH_TOPOLOGY select GENERIC_CLOCKEVENTS + select GENERIC_GETTIMEOFDAY if HAVE_GENERIC_VDSO select GENERIC_IRQ_LEGACY select GENERIC_IRQ_MIGRATION if SMP select GENERIC_IRQ_PROBE @@ -89,6 +94,7 @@ config SW64 select HAVE_FTRACE_MCOUNT_RECORD select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_TRACER + select HAVE_GENERIC_VDSO if MMU && 64BIT select HAVE_IDE select HAVE_KPROBES select HAVE_KPROBES_ON_FTRACE diff --git a/arch/sw_64/Kconfig.debug b/arch/sw_64/Kconfig.debug index 6cb3c2488b368e3acc38cd32b33fe658036ac8d6..985fe68c29b9e9346a30b210ea57e7ebc8fb17b9 100644 --- a/arch/sw_64/Kconfig.debug +++ b/arch/sw_64/Kconfig.debug @@ -47,7 +47,7 @@ config SW64_RRK config DEBUG_MATCH bool "instruction-flow and data-flow match debugfs interface" - depends on DEBUG_FS + depends on DEBUG_FS && SUBARCH_C4 default n help Turns on the DebugFS interface for instruction-flow and data-flow match. diff --git a/arch/sw_64/Makefile b/arch/sw_64/Makefile index cfea96316c94ffb42153ff06b88ac8386065da88..bae64bdfd7af1accdfc8487abdd4442df9bdebf3 100644 --- a/arch/sw_64/Makefile +++ b/arch/sw_64/Makefile @@ -49,6 +49,8 @@ export LIBS_Y boot := arch/sw_64/boot +vdso-install-y += arch/sw_64/kernel/vdso.so.dbg + #Default target when executing make with no arguments all: $(boot)/vmlinux.bin.gz diff --git a/arch/sw_64/configs/junzhang_defconfig b/arch/sw_64/configs/junzhang_defconfig index 2073cb0fecdb927cf2cea36c9720e83df22b7c39..06e792cd8662d360c4c96d918f0ab3744e276143 100644 --- a/arch/sw_64/configs/junzhang_defconfig +++ b/arch/sw_64/configs/junzhang_defconfig @@ -3,6 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y # CONFIG_CROSS_MEMORY_ATTACH is not set CONFIG_USELIB=y +CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_BPF_SYSCALL=y CONFIG_BPF_JIT=y @@ -28,7 +29,6 @@ CONFIG_DEBUG_PERF_USE_VMALLOC=y CONFIG_SUBARCH_C4=y CONFIG_SMP=y CONFIG_SCHED_SMT=y -CONFIG_NR_CPUS=512 CONFIG_ARCH_SPARSEMEM_ENABLE=y CONFIG_NUMA=y CONFIG_HZ=100 @@ -521,10 +521,9 @@ CONFIG_SERIAL_OF_PLATFORM=y CONFIG_VIRTIO_CONSOLE=y # CONFIG_HW_RANDOM is not set # CONFIG_I2C_COMPAT is not set -CONFIG_I2C=y CONFIG_I2C_CHARDEV=y -CONFIG_I2C_DESIGNWARE_PLATFORM=y CONFIG_I2C_MUX=y +CONFIG_I2C_DESIGNWARE_PLATFORM=y CONFIG_SPI=y CONFIG_SPI_SUNWAY=y CONFIG_SPI_SUNWAY_MMIO=y @@ -574,7 +573,6 @@ CONFIG_FSCACHE=y CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y -CONFIG_UDF_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_FAT_DEFAULT_UTF8=y @@ -665,6 +663,7 @@ CONFIG_CRYPTO_SHA1=y CONFIG_CRYPTO_DEFLATE=y CONFIG_CRYPTO_LZO=y # CONFIG_CRYPTO_HW is not set +CONFIG_CRC_ITU_T=y CONFIG_CONSOLE_LOGLEVEL_QUIET=7 # CONFIG_ENABLE_MUST_CHECK is not set CONFIG_SCHEDSTATS=y diff --git a/arch/sw_64/configs/xuelang_defconfig b/arch/sw_64/configs/xuelang_defconfig index 2272d99db00c4ed65876b9251a2dfdca33b1154f..15110ecdce89cfe4790fc800c7e26def3a20a062 100644 --- a/arch/sw_64/configs/xuelang_defconfig +++ b/arch/sw_64/configs/xuelang_defconfig @@ -3,6 +3,7 @@ CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y # CONFIG_CROSS_MEMORY_ATTACH is not set CONFIG_USELIB=y +CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_BPF_SYSCALL=y CONFIG_BPF_JIT=y @@ -25,6 +26,7 @@ CONFIG_EXPERT=y CONFIG_KALLSYMS_ALL=y CONFIG_PERF_EVENTS=y CONFIG_DEBUG_PERF_USE_VMALLOC=y +# CONFIG_COMPAT_BRK is not set CONFIG_SMP=y CONFIG_ARCH_SPARSEMEM_ENABLE=y CONFIG_NUMA=y @@ -557,7 +559,6 @@ CONFIG_VIRTIO_MMIO=y CONFIG_STAGING=y CONFIG_IOMMU_DEFAULT_PASSTHROUGH=y CONFIG_SUNWAY_IOMMU=y -CONFIG_SW64_LPC_INTC=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y @@ -571,7 +572,6 @@ CONFIG_FSCACHE=y CONFIG_ISO9660_FS=y CONFIG_JOLIET=y CONFIG_ZISOFS=y -CONFIG_UDF_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_FAT_DEFAULT_UTF8=y @@ -662,6 +662,7 @@ CONFIG_CRYPTO_SHA1=y CONFIG_CRYPTO_DEFLATE=y CONFIG_CRYPTO_LZO=y # CONFIG_CRYPTO_HW is not set +CONFIG_CRC_ITU_T=y CONFIG_CONSOLE_LOGLEVEL_QUIET=7 # CONFIG_FRAME_POINTER is not set CONFIG_SCHEDSTATS=y diff --git a/arch/sw_64/include/asm/acpi.h b/arch/sw_64/include/asm/acpi.h index ef46f481e1fdffa89929a0857e85b3d5055c5bad..e386d07d1e73c443646f50928b43724b33306935 100644 --- a/arch/sw_64/include/asm/acpi.h +++ b/arch/sw_64/include/asm/acpi.h @@ -7,6 +7,7 @@ #include #include #include +#include #ifdef CONFIG_ACPI extern int acpi_noirq; @@ -105,6 +106,24 @@ static inline bool arch_has_acpi_pdc(void) static inline void arch_acpi_set_pdc_bits(u32 *buf) { } + +static inline u32 get_acpi_id_for_cpu(unsigned int cpu) +{ + /* We take rcid as processor _UID */ + return cpu_physical_id(cpu); +} + +static inline unsigned long acpi_get_wakeup_address(void) +{ + return 0; +} + +static inline bool acpi_skip_set_wakeup_address(void) +{ + return true; +} + +#define acpi_skip_set_wakeup_address acpi_skip_set_wakeup_address #else /* !CONFIG_ACPI */ static inline void acpi_noirq_set(void) { } diff --git a/arch/sw_64/include/asm/ast2400.h b/arch/sw_64/include/asm/ast2400.h index 5f4cc84ff3a8cb729ce2d59c796274b548ccd7c9..30d45eff62a2e6fb8b4e01ba5af073e5c3a625fe 100644 --- a/arch/sw_64/include/asm/ast2400.h +++ b/arch/sw_64/include/asm/ast2400.h @@ -49,9 +49,17 @@ #define SUPERIO_PNP_PORT 0x2E #define SUPERIO_CHIPID 0xC333 +#ifdef CONFIG_SUBARCH_C3B +#define PORT_OFFSET 0 +#endif + +#ifdef CONFIG_SUBARCH_C4 +#define PORT_OFFSET 12 +#endif + struct device_operations; typedef struct pnp_device { - unsigned int port; + unsigned long port; unsigned int device; struct device_operations *ops; @@ -100,8 +108,8 @@ typedef struct superio_ast2400_device { struct device *dev; const char *name; unsigned int enabled : 1; /* set if we should enable the device */ - unsigned int superio_ast2400_efir; /* extended function index register */ - unsigned int superio_ast2400_efdr; /* extended function data register */ + unsigned long superio_ast2400_efir; /* extended function index register */ + unsigned long superio_ast2400_efdr; /* extended function data register */ struct chip_operations *chip_ops; const void *chip_info; } *superio_device_t; @@ -136,19 +144,18 @@ static inline void pnp_exit_conf_mode(device_t dev) static inline u8 pnp_read_config(device_t dev, u8 reg) { outb(reg, dev->port); - return inb(dev->port + 1); + return inb(dev->port + (1 << PORT_OFFSET)); } static inline void pnp_write_config(device_t dev, u8 reg, u8 value) { outb(reg, dev->port); - outb(value, dev->port + 1); + outb(value, dev->port + (1 << PORT_OFFSET)); } static inline void pnp_set_logical_device(device_t dev) { pnp_write_config(dev, 0x07, dev->device & 0xff); -// pnp_write_config(dev, 0x07, 0x3); } static inline void pnp_set_enable(device_t dev, int enable) diff --git a/arch/sw_64/include/asm/cache.h b/arch/sw_64/include/asm/cache.h index 6a6ce4e99265a02576d448ec0577d486c7b16ffe..411218f5eb0e89d114f69d3d8042929b25397636 100644 --- a/arch/sw_64/include/asm/cache.h +++ b/arch/sw_64/include/asm/cache.h @@ -1,13 +1,20 @@ /* SPDX-License-Identifier: GPL-2.0 */ -/* - * include/asm/cache.h - */ + #ifndef _ASM_SW64_CACHE_H #define _ASM_SW64_CACHE_H #define L1_CACHE_SHIFT 7 #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) -#define SMP_CACHE_BYTES L1_CACHE_BYTES +#ifndef __ASSEMBLY__ + +enum sunway_cache_type { + L1_ICACHE = 0, + L1_DCACHE = 1, + L2_CACHE = 2, + L3_CACHE = 3 +}; + +#endif #endif /* _ASM_SW64_CACHE_H */ diff --git a/arch/sw_64/include/asm/clocksource.h b/arch/sw_64/include/asm/clocksource.h new file mode 100644 index 0000000000000000000000000000000000000000..482185566b0cfa3f2dceb8beb8a5f42e53f14fc9 --- /dev/null +++ b/arch/sw_64/include/asm/clocksource.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _ASM_CLOCKSOURCE_H +#define _ASM_CLOCKSOURCE_H + +#include + +#endif diff --git a/arch/sw_64/include/asm/cpu.h b/arch/sw_64/include/asm/cpu.h index 4da30bb91d89602e48c55c01fdff08d3f495b45c..37a588fe12d9a2d630d90ee2155dc8719dfadf4d 100644 --- a/arch/sw_64/include/asm/cpu.h +++ b/arch/sw_64/include/asm/cpu.h @@ -1,5 +1,56 @@ /* SPDX-License-Identifier: GPL-2.0 */ + #ifndef _ASM_SW64_CPU_H #define _ASM_SW64_CPU_H +#include +#include +#include + +#define current_cpu_data cpu_data[smp_processor_id()] + +enum hmcall_cpuid_cmd { + GET_TABLE_ENTRY = 1, + GET_VENDOR_ID = 2, + GET_MODEL = 3, + GET_CPU_FREQ = 4, + GET_CACHE_INFO = 5, + GET_FEATURES = 6 +}; + +#define CPU_FEAT_FPU 0x1 +#define CPU_FEAT_SIMD 0x2 +#define CPU_FEAT_UNA 0x4 + +enum sunway_cpu_model { + CPU_SW3231 = 0x31, + CPU_SW831 = 0x32, + CPU_SW8A = 0x41 +}; + +struct cpuinfo_sw64 { + __u8 model; + __u8 family; + __u8 chip_var; + __u8 arch_var; + __u8 arch_rev; + __u8 pa_bits; + __u8 va_bits; + const char *vendor_id; + const char *model_id; + unsigned long last_asid; + unsigned long last_vpn; + unsigned long ipi_count; +} __aligned(SMP_CACHE_BYTES); + +extern struct cpuinfo_sw64 cpu_data[NR_CPUS]; +extern cpumask_t cpu_offline; + +extern void store_cpu_data(int cpu); +extern unsigned long get_cpu_freq(void); +extern void update_cpu_freq(unsigned long khz); + +extern unsigned int get_cpu_cache_size(int cpu, int level, enum cache_type type); +extern unsigned int get_cpu_cacheline_size(int cpu, int level, enum cache_type type); + #endif /* _ASM_SW64_CPU_H */ diff --git a/arch/sw_64/include/asm/cpufreq.h b/arch/sw_64/include/asm/cpufreq.h index 93244b3b18c617c166be372da63b24e20dc9961a..d89db83b42a66dae469c9547a2d0c5924c21aa7f 100644 --- a/arch/sw_64/include/asm/cpufreq.h +++ b/arch/sw_64/include/asm/cpufreq.h @@ -8,6 +8,7 @@ #include #include #include +#include struct clk; @@ -51,7 +52,8 @@ struct clk { #define CORE_CLK2_VALID (0x1UL << 33) #define CORE_CLK2_RESET (0x1UL << 34) #define CORE_CLK2_LOCK (0x1UL << 35) -#define CORE_PLL0_CFG_SHIFT 20 +#define CORE_PLL0_CFG_SHIFT 4 +#define CORE_PLL1_CFG_SHIFT 20 #define CORE_PLL2_CFG_SHIFT 36 #define CORE_PLL2_CFG_MASK 0x1f #define STARTUP_RATE (2000UL * 1000 * 1000) @@ -65,6 +67,7 @@ struct clk { #define CORE_CLK2_RESET (0x1UL << 16) #define CORE_CLK2_LOCK (0x1UL << 17) #define CORE_PLL0_CFG_SHIFT 4 +#define CORE_PLL1_CFG_SHIFT 11 #define CORE_PLL2_CFG_SHIFT 18 #define CORE_PLL2_CFG_MASK 0xf #define STARTUP_RATE (2400UL * 1000 * 1000) diff --git a/arch/sw_64/include/asm/csr.h b/arch/sw_64/include/asm/csr.h index 9101e4c91fe17fed18ab7dc2699bbbcf45095ca6..e205c3f1427e120ab94fcbc101756aaaf7bf935c 100644 --- a/arch/sw_64/include/asm/csr.h +++ b/arch/sw_64/include/asm/csr.h @@ -29,6 +29,10 @@ #define CSR_PTBR_SYS 0x68 #define CSR_PTBR_USR 0x69 #define CSR_APTP 0x6a +#define CSR_IDR_PCCTL 0x7a +#define CSR_IACC 0x7b +#define CSR_IMISC 0x7c +#define CSR_RETIC 0x7f #define CSR_CID 0xc4 #define CSR_WR_FREGS 0xc8 #define CSR_SHTCLOCK 0xca @@ -104,6 +108,12 @@ static inline void update_ptbr_sys(unsigned long ptbr) sw64_write_csr_imb(ptbr, CSR_PTBR_SYS); } +static inline void update_ptbr_usr(unsigned long ptbr) +{ + imemb(); + sw64_write_csr_imb(ptbr, CSR_PTBR_USR); +} + #endif #else #define sw64_read_csr(x) (0) diff --git a/arch/sw_64/include/asm/efi.h b/arch/sw_64/include/asm/efi.h index 34d5637e23c2e23045764f6f316a1f5dcb5f36fb..ef2eda461f947b4bd4a3b435e7c1998702efa9ad 100644 --- a/arch/sw_64/include/asm/efi.h +++ b/arch/sw_64/include/asm/efi.h @@ -4,16 +4,22 @@ #include #include + #ifdef CONFIG_EFI + extern void efi_init(void); extern unsigned long entSuspend; -#define SLEEP_ENTRY_GUID EFI_GUID(0x59cb76bb, 0x9c3a, 0x4c8f, 0xbd, 0x5c, 0xc0, 0x0f, 0x20, 0x61, 0x18, 0x4b) +#define SLEEP_ENTRY_GUID EFI_GUID(0x59cb76bb, 0x9c3a, 0x4c8f, 0xbd, 0x5c, 0xc0, 0x0f, 0x20, 0x61, 0x18, 0x4b) +#define BIOS_VERSION_GUID EFI_GUID(0xc47a23c3, 0xcebb, 0x4cc9, 0xa5, 0xe2, 0xde, 0xd0, 0x8f, 0xe4, 0x20, 0xb5) + +extern unsigned long sunway_bios_version; #else #define efi_init() #define efi_idmap_init() -#endif +#define sunway_bios_version (0) +#endif /* CONFIG_EFI */ #define arch_efi_call_virt_setup() #define arch_efi_call_virt_teardown() diff --git a/arch/sw_64/include/asm/hmcall.h b/arch/sw_64/include/asm/hmcall.h index 574144eab22b5673edc6dd0d6cd243f3e1cf915a..60f68e31c568b5b8507a1fb91784df20f25f55c6 100644 --- a/arch/sw_64/include/asm/hmcall.h +++ b/arch/sw_64/include/asm/hmcall.h @@ -54,6 +54,7 @@ /* Following will be deprecated from user level invocation */ #define HMC_rwreg 0x87 #define HMC_sz_uflush 0xA8 +#define HMC_uwhami 0xA0 #define HMC_longtime 0xB1 #ifdef __KERNEL__ @@ -162,6 +163,7 @@ __CALL_HMC_VOID(wrktp); __CALL_HMC_R0(rdps, unsigned long); __CALL_HMC_R0(rvpcr, unsigned long); +__CALL_HMC_R0(uwhami, unsigned long); __CALL_HMC_R0(rdusp, unsigned long); __CALL_HMC_W1(wrusp, unsigned long); diff --git a/arch/sw_64/include/asm/hw_init.h b/arch/sw_64/include/asm/hw_init.h index 5af3336d5fd68df52f125494f04a60b09e81d094..c13fbb4d620e9add446d780fdfa8e3d763607416 100644 --- a/arch/sw_64/include/asm/hw_init.h +++ b/arch/sw_64/include/asm/hw_init.h @@ -10,40 +10,6 @@ #define MM_SIZE __va(0x2040) #define VPCR_SHIFT 44 -/* - * Descriptor for a cache - */ -struct cache_desc { - unsigned int size; /* Bytes per way */ - unsigned int sets; /* Number of lines per set */ - unsigned char ways; /* Number of ways */ - unsigned char linesz; /* Size of line in bytes */ - unsigned char flags; /* Flags describing cache properties */ -}; - -struct cpuinfo_sw64 { - unsigned long last_asid; - unsigned long last_vpn; - unsigned long ipi_count; - struct cache_desc icache; /* Primary I-cache */ - struct cache_desc dcache; /* Primary D or combined I/D cache */ - struct cache_desc scache; /* Secondary cache */ - struct cache_desc tcache; /* Tertiary/split secondary cache */ -} __aligned(SMP_CACHE_BYTES); - -struct cpu_desc_t { - __u8 model; - __u8 family; - __u8 chip_var; - __u8 arch_var; - __u8 arch_rev; - __u8 pa_bits; - __u8 va_bits; - char vendor_id[16]; - char model_id[64]; - unsigned long frequency; -} __randomize_layout; - #define MAX_NUMSOCKETS 8 struct socket_desc_t { bool is_online; /* 1 for online, 0 for offline */ @@ -69,29 +35,14 @@ struct memmap_entry { enum memmap_types type; }; -extern struct cpuinfo_sw64 cpu_data[NR_CPUS]; -extern void store_cpu_data(int cpu); - -extern struct cpu_desc_t cpu_desc; extern struct socket_desc_t socket_desc[MAX_NUMSOCKETS]; extern int memmap_nr; extern struct memmap_entry memmap_map[MAX_NUMMEMMAPS]; -extern cpumask_t cpu_offline; extern bool memblock_initialized; int __init add_memmap_region(u64 addr, u64 size, enum memmap_types type); void __init process_memmap(void); -static inline unsigned long get_cpu_freq(void) -{ - return cpu_desc.frequency; -} - -static inline void update_cpu_freq(unsigned long khz) -{ - cpu_desc.frequency = khz * 1000; -} - #define EMUL_FLAG (0x1UL << 63) #define MM_SIZE_MASK (EMUL_FLAG - 1) @@ -100,72 +51,16 @@ DECLARE_STATIC_KEY_FALSE(run_mode_guest_key); DECLARE_STATIC_KEY_FALSE(run_mode_emul_key); DECLARE_STATIC_KEY_FALSE(hw_una_enabled); +DECLARE_STATIC_KEY_FALSE(junzhang_v1_key); +DECLARE_STATIC_KEY_FALSE(junzhang_v2_key); +DECLARE_STATIC_KEY_FALSE(junzhang_v3_key); #define is_in_host() static_branch_likely(&run_mode_host_key) #define is_in_guest() static_branch_unlikely(&run_mode_guest_key) #define is_in_emul() static_branch_unlikely(&run_mode_emul_key) #define is_guest_or_emul() !static_branch_likely(&run_mode_host_key) - -#define CPU_SW3231 0x31 -#define CPU_SW831 0x32 -#define CPU_SW8A 0x41 - -#define GET_TABLE_ENTRY 1 -#define GET_VENDOR_ID 2 -#define GET_MODEL 3 -#define GET_CPU_FREQ 4 -#define GET_CACHE_INFO 5 - -#define TABLE_ENTRY_MAX 32 -#define VENDOR_ID_MAX 2 -#define MODEL_MAX 8 -#define CACHE_INFO_MAX 4 - -#define L1_ICACHE 0 -#define L1_DCACHE 1 -#define L2_CACHE 2 -#define L3_CACHE 3 - -#define CPUID_ARCH_REV_MASK 0xf -#define CPUID_ARCH_REV(val) ((val) & CPUID_ARCH_REV_MASK) -#define CPUID_ARCH_VAR_SHIFT 4 -#define CPUID_ARCH_VAR_MASK (0xf << CPUID_ARCH_VAR_SHIFT) -#define CPUID_ARCH_VAR(val) \ - (((val) & CPUID_ARCH_VAR_MASK) >> CPUID_ARCH_VAR_SHIFT) -#define CPUID_CHIP_VAR_SHIFT 8 -#define CPUID_CHIP_VAR_MASK (0xf << CPUID_CHIP_VAR_SHIFT) -#define CPUID_CHIP_VAR(val) \ - (((val) & CPUID_CHIP_VAR_MASK) >> CPUID_CHIP_VAR_SHIFT) -#define CPUID_FAMILY_SHIFT 12 -#define CPUID_FAMILY_MASK (0xf << CPUID_FAMILY_SHIFT) -#define CPUID_FAMILY(val) \ - (((val) & CPUID_FAMILY_MASK) >> CPUID_FAMILY_SHIFT) -#define CPUID_MODEL_SHIFT 24 -#define CPUID_MODEL_MASK (0xff << CPUID_MODEL_SHIFT) -#define CPUID_MODEL(val) \ - (((val) & CPUID_MODEL_MASK) >> CPUID_MODEL_SHIFT) -#define CPUID_PA_BITS_SHIFT 32 -#define CPUID_PA_BITS_MASK (0x7fUL << CPUID_PA_BITS_SHIFT) -#define CPUID_PA_BITS(val) \ - (((val) & CPUID_PA_BITS_MASK) >> CPUID_PA_BITS_SHIFT) -#define CPUID_VA_BITS_SHIFT 39 -#define CPUID_VA_BITS_MASK (0x7fUL << CPUID_VA_BITS_SHIFT) -#define CPUID_VA_BITS(val) \ - (((val) & CPUID_VA_BITS_MASK) >> CPUID_VA_BITS_SHIFT) - - -#define CACHE_SIZE_SHIFT 0 -#define CACHE_SIZE_MASK (0xffffffffUL << CACHE_SIZE_SHIFT) -#define CACHE_SIZE(val) \ - (((val) & CACHE_SIZE_MASK) >> CACHE_SIZE_SHIFT) -#define CACHE_LINE_BITS_SHIFT 32 -#define CACHE_LINE_BITS_MASK (0xfUL << CACHE_LINE_BITS_SHIFT) -#define CACHE_LINE_BITS(val) \ - (((val) & CACHE_LINE_BITS_MASK) >> CACHE_LINE_BITS_SHIFT) -#define CACHE_INDEX_BITS_SHIFT 36 -#define CACHE_INDEX_BITS_MASK (0x3fUL << CACHE_INDEX_BITS_SHIFT) -#define CACHE_INDEX_BITS(val) \ - (((val) & CACHE_INDEX_BITS_MASK) >> CACHE_INDEX_BITS_SHIFT) -#define current_cpu_data cpu_data[smp_processor_id()] +#define is_junzhang_v1() static_branch_unlikely(&junzhang_v1_key) +#define is_junzhang_v2() static_branch_likely(&junzhang_v2_key) +#define is_junzhang_v3() static_branch_unlikely(&junzhang_v3_key) #endif /* _ASM_SW64_HW_INIT_H */ diff --git a/arch/sw_64/include/asm/irq.h b/arch/sw_64/include/asm/irq.h index de3530b687e070b8f4116b10030ed783854a7801..ae837f19b2d882ffb2b6ad7ff2fdc183adee9720 100644 --- a/arch/sw_64/include/asm/irq.h +++ b/arch/sw_64/include/asm/irq.h @@ -2,12 +2,6 @@ #ifndef _ASM_SW64_IRQ_H #define _ASM_SW64_IRQ_H -/* - * arch/sw/include/asm/irq.h - * - * (C) 2012 OSKernel JN - */ - #include #define NR_VECTORS_PERCPU 256 @@ -38,6 +32,15 @@ struct acpi_madt_sw_lpc_intc; extern int __init sw64_add_gsi_domain_map(u32 gsi_base, u32 gsi_count, struct fwnode_handle *handle); +#ifdef CONFIG_SW64_PCI_INTX +extern void handle_intx(unsigned int offset); +#else +static inline void handle_intx(unsigned int offset) +{ + pr_crit("Enter PCI INTx, but no handle configured!\n"); +} +#endif + #ifdef CONFIG_SW64_PINTC extern int __init pintc_acpi_init(struct irq_domain *parent, struct acpi_madt_sw_pintc *pintc); diff --git a/arch/sw_64/include/asm/irq_impl.h b/arch/sw_64/include/asm/irq_impl.h index c4f2690bca2e044d99fae01f031a879ff7e59ebd..0e31aaf37ac68e33c5451d220abaaa511b093393 100644 --- a/arch/sw_64/include/asm/irq_impl.h +++ b/arch/sw_64/include/asm/irq_impl.h @@ -44,7 +44,7 @@ extern struct irqaction timer_irqaction; extern void init_rtc_irq(irq_handler_t handler); extern void handle_irq(int irq); extern void handle_ipi(struct pt_regs *regs); -extern void __init sw64_init_irq(void); +extern void __init sunway_init_pci_intx(void); extern irqreturn_t timer_interrupt(int irq, void *dev); #endif /* _ASM_SW64_IRQ_IMPL_H */ diff --git a/arch/sw_64/include/asm/irq_work.h b/arch/sw_64/include/asm/irq_work.h new file mode 100644 index 0000000000000000000000000000000000000000..f4d0cd857be7268ac4430ed140e9d04e2c14a0cf --- /dev/null +++ b/arch/sw_64/include/asm/irq_work.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_SW64_IRQ_WORK_H +#define __ASM_SW64_IRQ_WORK_H + +extern void arch_irq_work_raise(void); + +static inline bool arch_irq_work_has_interrupt(void) +{ + return IS_ENABLED(CONFIG_SMP); +} + +#endif /* __ASM_SW64_IRQ_WORK_H */ diff --git a/arch/sw_64/include/asm/jump_label.h b/arch/sw_64/include/asm/jump_label.h index 32fbf7573b206bb2c935cc173de392b100d02010..27898e8e2c75017f9d5301eb691c5dabe0f5c486 100644 --- a/arch/sw_64/include/asm/jump_label.h +++ b/arch/sw_64/include/asm/jump_label.h @@ -12,12 +12,12 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool branch) { - asm_volatile_goto("1: nop\n\t" - ".pushsection __jump_table, \"aw\"\n\t" - ".align 3\n\t" - ".quad 1b, %l[l_yes], %0\n\t" - ".popsection\n\t" - : : "i"(&((char *)key)[branch]) : : l_yes); + asm goto("1: nop\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".align 3\n\t" + ".quad 1b, %l[l_yes], %0\n\t" + ".popsection\n\t" + : : "i"(&((char *)key)[branch]) : : l_yes); return false; l_yes: @@ -26,12 +26,12 @@ static __always_inline bool arch_static_branch(struct static_key *key, bool bran static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch) { - asm_volatile_goto("1: br %l[l_yes]\n\t" - ".pushsection __jump_table, \"aw\"\n\t" - ".align 3\n\t" - ".quad 1b, %l[l_yes], %0\n\t" - ".popsection\n\t" - : : "i"(&((char *)key)[branch]) : : l_yes); + asm goto("1: br %l[l_yes]\n\t" + ".pushsection __jump_table, \"aw\"\n\t" + ".align 3\n\t" + ".quad 1b, %l[l_yes], %0\n\t" + ".popsection\n\t" + : : "i"(&((char *)key)[branch]) : : l_yes); return false; l_yes: diff --git a/arch/sw_64/include/asm/kvm_host.h b/arch/sw_64/include/asm/kvm_host.h index e2f3670035094d78746692b62d8e296ecf88ef2a..221a7db26f0f0c37407ce227ec4ee1e293828466 100644 --- a/arch/sw_64/include/asm/kvm_host.h +++ b/arch/sw_64/include/asm/kvm_host.h @@ -27,6 +27,7 @@ #include #include +#include #define last_vpn(cpu) (cpu_data[cpu].last_vpn) diff --git a/arch/sw_64/include/asm/mmu_context.h b/arch/sw_64/include/asm/mmu_context.h index 1ff7df9539c55a4053ab03c413743588e3c6d418..84dfb15b43bf9f803a27f4e3c5a3777447644f0c 100644 --- a/arch/sw_64/include/asm/mmu_context.h +++ b/arch/sw_64/include/asm/mmu_context.h @@ -15,7 +15,7 @@ #define ASID_BITS 10 #endif -#include +#include #define last_asid(cpu) (cpu_data[cpu].last_asid) #define ASID_FIRST_VERSION (1UL << ASID_BITS) diff --git a/arch/sw_64/include/asm/pci.h b/arch/sw_64/include/asm/pci.h index 9662fdd87cb1e58f98505ed3d61181bf8fb26b70..a1acda1c166c8068aa416eff4ca90bdaeeb97152 100644 --- a/arch/sw_64/include/asm/pci.h +++ b/arch/sw_64/include/asm/pci.h @@ -153,7 +153,7 @@ struct pci_controller { extern void __init sw64_init_pci(void); extern void __init sw64_device_interrupt(unsigned long vector); extern void setup_intx_irqs(struct pci_controller *hose); -extern void __init sw64_init_irq(void); +extern void __init sunway_init_pci_intx(void); extern void __init sw64_init_arch(void); extern int sw64_map_irq(const struct pci_dev *dev, u8 slot, u8 pin); extern struct pci_controller *hose_head; @@ -236,6 +236,7 @@ extern int chip_pcie_configure(struct pci_controller *hose); #define PCI_INTX_ENABLE ((1UL) << 62) #define PCI_INTX_DISABLE ~((1UL) << 62) #define PCI_INTX_VALID (1UL << 63) +#define PCI_INTX_INTDST_MASK 0x3ffUL #define PCI_VENDOR_ID_JN 0x5656 #define PCI_DEVICE_ID_SW64_ROOT_BRIDGE 0x3231 diff --git a/arch/sw_64/include/asm/perf_event.h b/arch/sw_64/include/asm/perf_event.h index dc55a361babd015aa92fbf7b0387f1e2beeecc40..a92545694c65bb599b99ce17e6574de137cf5c05 100644 --- a/arch/sw_64/include/asm/perf_event.h +++ b/arch/sw_64/include/asm/perf_event.h @@ -2,8 +2,14 @@ #ifndef _ASM_SW64_PERF_EVENT_H #define _ASM_SW64_PERF_EVENT_H +#if defined(CONFIG_SUBARCH_C3B) #include +#elif defined(CONFIG_SUBARCH_C4) +#include +#endif #include +#include +#include #ifdef CONFIG_PERF_EVENTS struct pt_regs; @@ -13,4 +19,15 @@ extern unsigned long perf_misc_flags(struct pt_regs *regs); #define perf_arch_bpf_user_pt_regs(regs) ®s->user_regs #endif +/* For tracking PMCs and the hw events they monitor on each CPU. */ +struct cpu_hw_events { + /* + * Set the bit (indexed by the counter number) when the counter + * is used for an event. + */ + unsigned long used_mask[BITS_TO_LONGS(MAX_HWEVENTS)]; + /* Array of events current scheduled on this cpu. */ + struct perf_event *event[MAX_HWEVENTS]; +}; + #endif /* _ASM_SW64_PERF_EVENT_H */ diff --git a/arch/sw_64/include/asm/pgtable.h b/arch/sw_64/include/asm/pgtable.h index b9f98b9af33ef823d0d49273b3c5db2a1a083e39..0b9b65685e7443827905e36b7e2f4c47393b7075 100644 --- a/arch/sw_64/include/asm/pgtable.h +++ b/arch/sw_64/include/asm/pgtable.h @@ -142,9 +142,6 @@ static inline void set_p4d(p4d_t *p4dp, p4d_t p4d) * the page is accessed. They are cleared only by the page-out routines */ #define PAGE_NONE __pgprot(__ACCESS_BITS | _PAGE_FOR | _PAGE_FOW | _PAGE_FOE | _PAGE_PROTNONE) -#define PAGE_SHARED __pgprot(_PAGE_VALID | __ACCESS_BITS) -#define PAGE_COPY __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW) -#define PAGE_READONLY __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW) #define PAGE_KERNEL __pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE | _PAGE_KWE) #define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | (x)) @@ -189,9 +186,6 @@ static inline void set_p4d(p4d_t *p4dp, p4d_t p4d) * the page is accessed. They are cleared only by the page-out routines */ #define PAGE_NONE __pgprot(__ACCESS_BITS | _PAGE_FOR | _PAGE_FOW | _PAGE_FOE | _PAGE_LEAF | _PAGE_PROTNONE) -#define PAGE_SHARED __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_LEAF) -#define PAGE_COPY __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW | _PAGE_LEAF) -#define PAGE_READONLY __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW | _PAGE_LEAF) #define PAGE_KERNEL __pgprot(_PAGE_VALID | _PAGE_KERN | _PAGE_LEAF) #define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_LEAF | (x)) @@ -200,14 +194,54 @@ static inline void set_p4d(p4d_t *p4dp, p4d_t p4d) #define PFN_PTE_SHIFT _PFN_SHIFT -#define _PFN_BITS (MAX_PHYSMEM_BITS - PAGE_SHIFT) -#define _PFN_MASK (GENMASK(_PFN_BITS - 1, 0) << _PFN_SHIFT) +#define __PFN_BITS (MAX_PHYSMEM_BITS - PAGE_SHIFT) +#define _PFN_MASK (GENMASK(__PFN_BITS - 1, 0) << _PFN_SHIFT) #define _PAGE_TABLE (_PAGE_VALID | __DIRTY_BITS | __ACCESS_BITS) #define _PAGE_CHG_MASK (_PFN_MASK | __DIRTY_BITS | __ACCESS_BITS | _PAGE_SPECIAL | _PAGE_LEAF | _PAGE_CONT) -#define _PAGE_P(x) _PAGE_NORMAL((x) | _PAGE_FOW) -#define _PAGE_S(x) _PAGE_NORMAL(x) +#define PAGE_READONLY_NOEXEC _PAGE_NORMAL(_PAGE_FOE | _PAGE_FOW) +#define PAGE_EXEC _PAGE_NORMAL(_PAGE_FOW | _PAGE_FOR) +#define PAGE_READONLY_EXEC _PAGE_NORMAL(_PAGE_FOW) +#define PAGE_COPY_NOEXEC PAGE_READONLY_NOEXEC +#define PAGE_COPY_EXEC PAGE_READONLY_EXEC +/* + * Since we don't have hardware dirty-bit management yet, shared + * writable page has FOW bit set to make sure dirty-bit could be + * set properly. + */ +#define PAGE_SHARED_NOEXEC PAGE_READONLY_NOEXEC +#define PAGE_SHARED_EXEC PAGE_READONLY_EXEC + +/* For backward compatibility */ +#define PAGE_READONLY PAGE_READONLY_EXEC +#define PAGE_COPY PAGE_COPY_EXEC +#define PAGE_SHARED PAGE_SHARED_EXEC + +/* + * The hardware can handle write-only mappings, but as the sw64 + * architecture does byte-wide writes with a read-modify-write + * sequence, it's not practical to have write-without-read privs. + * Thus the "-w- -> rw-" and "-wx -> rwx" mapping here (and in + * arch/sw_64/mm/fault.c) + */ +#define __P000 PAGE_NONE +#define __P001 PAGE_READONLY_NOEXEC +#define __P010 PAGE_COPY_NOEXEC +#define __P011 PAGE_COPY_NOEXEC +#define __P100 PAGE_EXEC +#define __P101 PAGE_READONLY_EXEC +#define __P110 PAGE_COPY_EXEC +#define __P111 PAGE_COPY_EXEC + +#define __S000 PAGE_NONE +#define __S001 PAGE_READONLY_NOEXEC +#define __S010 PAGE_SHARED_NOEXEC +#define __S011 PAGE_SHARED_NOEXEC +#define __S100 PAGE_EXEC +#define __S101 PAGE_READONLY_EXEC +#define __S110 PAGE_SHARED_EXEC +#define __S111 PAGE_SHARED_EXEC /* * pgprot_noncached() is only for infiniband pci support, and a real diff --git a/arch/sw_64/include/asm/platform.h b/arch/sw_64/include/asm/platform.h index c44116df8e16f406bd09068b0e3a3b887a59de93..96656f112c40992ecbf8fd07d8b5ff6d0a211e59 100644 --- a/arch/sw_64/include/asm/platform.h +++ b/arch/sw_64/include/asm/platform.h @@ -9,27 +9,12 @@ #include #endif -#ifdef CONFIG_EFI -#define BIOS_VERSION_GUID EFI_GUID(0xc47a23c3, 0xcebb, 0x4cc9, 0xa5, 0xe2, 0xde, 0xd0, 0x8f, 0xe4, 0x20, 0xb5) - -#define BIOS_SUPPORT_RESET_CLALLBACK(bios_version) ((bios_version) != NULL) - -extern unsigned long bios_version; - -#endif - extern struct boot_params *sunway_boot_params; extern unsigned long sunway_boot_magic; extern unsigned long sunway_dtb_address; -extern void sw64_halt(void); -extern void sw64_poweroff(void); -extern void sw64_restart(void); -extern void (*pm_restart)(void); -extern void (*pm_halt)(void); -extern int i2c_set_adapter(void); extern void cpld_write(uint8_t slave_addr, uint8_t reg, uint8_t data); -extern void fix_jm585_reset(void); + extern void early_parse_fdt_property(const void *fdt, const char *path, const char *prop_name, u64 *property, int size); diff --git a/arch/sw_64/include/asm/pmc_c4.h b/arch/sw_64/include/asm/pmc_c4.h new file mode 100644 index 0000000000000000000000000000000000000000..cdee1041ce3b56d96faf69494e57a65c303c0592 --- /dev/null +++ b/arch/sw_64/include/asm/pmc_c4.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Definitions for use with the sw64 wrperfmon HMCODE call. + */ + +#ifndef _ASM_SW64_WRPMC_H +#define _ASM_SW64_WRPMC_H + +/* Following commands are implemented on all CPUs */ +/* core4 */ +#define PMC_CMD_READ_PC0 5 +#define PMC_CMD_READ_PC1 6 +#define PMC_CMD_READ_PC2 7 +#define PMC_CMD_READ_PC3 8 +#define PMC_CMD_READ_PC4 9 +#define PMC_CMD_ENABLE 11 +#define PMC_CMD_DISABLE 12 +#define PMC_CMD_WRITE_BASE 16 + +#define PC_RAW_BASE 0x0 +#define PC_MAX 0x8D + +#define SW64_PERFCTRL_AM 0x0 +#define SW64_PERFCTRL_VM 0x3 +#define SW64_PERFCTRL_KM 0x5 +#define SW64_PERFCTRL_UM 0x7 + +/* pc0-4 events */ +#define SW64_PMU_INSTRUCTIONS 0x3 +#define SW64_PMU_BRANCH 0x4 +#define SW64_PMU_BRANCH_MISSES 0x5 +#define SW64_L1I_CACHE 0x6 +#define SW64_L1I_CACHE_MISSES 0x7 +#define SW64_PMU_CYCLE 0x30 +#define SW64_DTB 0x31 +#define SW64_DTB_MISSES 0x32 +#define SW64_L1D_CACHE 0x3D +#define SW64_L1D_CACHE_MISSES 0x3E +#define SW64_PMU_L2_REFERENCES 0x50 +#define SW64_PMU_L2_MISSES 0x53 + +#define PC_ALL_PM_SET 3 +#define MAX_HWEVENTS 5 +#define PMC_COUNT_MASK (-1UL) + +#define IACC_EN 0x4 +#define IMISC_EN 0x8 +#define RETIC_EN 0x10 +#define BRRETC_EN 0x20 +#define BRFAILC_EN 0x40 + +#endif /* _ASM_SW64_WRPMC_H */ diff --git a/arch/sw_64/include/asm/smp.h b/arch/sw_64/include/asm/smp.h index 33a73ca25a6b28c3f6c9f1134f892dde24ba3df8..4249b10dc5501d16ec3998059b488a5da9f3ec92 100644 --- a/arch/sw_64/include/asm/smp.h +++ b/arch/sw_64/include/asm/smp.h @@ -50,8 +50,7 @@ extern void __init smp_rcb_init(struct smp_rcb_struct *smp_rcb_base_addr); #ifdef GENERATING_ASM_OFFSETS #define raw_smp_processor_id() (0) #else -#include -#define raw_smp_processor_id() (*((unsigned int *)((void *)current + TASK_CPU))) +#define raw_smp_processor_id() (current_thread_info()->cpu) #endif #define hard_smp_processor_id() cpu_to_rcid(raw_smp_processor_id()) diff --git a/arch/sw_64/include/asm/sw64_init.h b/arch/sw_64/include/asm/sw64_init.h index 34a28e365ec6b9a05ddaba7f86c000ca7ef6fa8b..20901ede574c83bbe68b0e8ebc807db61ecc6ede 100644 --- a/arch/sw_64/include/asm/sw64_init.h +++ b/arch/sw_64/include/asm/sw64_init.h @@ -8,7 +8,7 @@ #include struct sw64_early_init_ops { - void (*setup_core_map)(struct cpumask *cpumask); + void (*setup_core_map)(void); unsigned long (*get_node_mem)(int nodeid); void (*get_smp_info)(void); }; diff --git a/arch/sw_64/include/asm/topology.h b/arch/sw_64/include/asm/topology.h index c4da0cfccefffc948341a31c74d6da7717446f6a..48e66c51cfc9ca4599d389088e83385f2ce7e96d 100644 --- a/arch/sw_64/include/asm/topology.h +++ b/arch/sw_64/include/asm/topology.h @@ -9,19 +9,6 @@ #include #include -extern struct cpu_topology cpu_topology[NR_CPUS]; - -#define topology_physical_package_id(cpu) (cpu_topology[cpu].package_id) -#define topology_core_id(cpu) (cpu_topology[cpu].core_id) -#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling) -#define topology_sibling_cpumask(cpu) (&cpu_topology[cpu].thread_sibling) -#define topology_llc_cpumask(cpu) (&cpu_topology[cpu].llc_sibling) - -void init_cpu_topology(void); -void store_cpu_topology(int cpuid); -void remove_cpu_topology(int cpuid); -const struct cpumask *cpu_coregroup_mask(int cpu); - static inline int rcid_to_thread_id(int rcid) { return (rcid & THREAD_ID_MASK) >> THREAD_ID_SHIFT; diff --git a/arch/sw_64/include/asm/vdso.h b/arch/sw_64/include/asm/vdso.h index 7a2e23c648f3d48c50ab72709e9d2091aee9410c..3f6ba2d72b62d7a7a084ffd263dc59d1122a318e 100644 --- a/arch/sw_64/include/asm/vdso.h +++ b/arch/sw_64/include/asm/vdso.h @@ -50,6 +50,13 @@ struct vdso_data { s32 tz_minuteswest; s32 tz_dsttime; u32 seq_count; +#ifdef CONFIG_SUBARCH_C3B + u8 vdso_whami_to_cpu[NR_CPUS]; + u8 vdso_whami_to_node[NR_CPUS]; +#endif +#ifdef CONFIG_SUBARCH_C4 + u8 vdso_cpu_to_node[NR_CPUS]; +#endif }; static inline unsigned long get_vdso_base(void) diff --git a/arch/sw_64/include/asm/vdso/clocksource.h b/arch/sw_64/include/asm/vdso/clocksource.h new file mode 100644 index 0000000000000000000000000000000000000000..df6ea65c1decad7423bebcb6d4b71dd95ee1579f --- /dev/null +++ b/arch/sw_64/include/asm/vdso/clocksource.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_VDSOCLOCKSOURCE_H +#define __ASM_VDSOCLOCKSOURCE_H + +#define VDSO_ARCH_CLOCKMODES \ + VDSO_CLOCKMODE_ARCHTIMER + +#endif diff --git a/arch/sw_64/include/asm/vdso/gettimeofday.h b/arch/sw_64/include/asm/vdso/gettimeofday.h new file mode 100644 index 0000000000000000000000000000000000000000..57eb602550c71b3251cb98cb2f2b7f819674baef --- /dev/null +++ b/arch/sw_64/include/asm/vdso/gettimeofday.h @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_VDSO_GETTIMEOFDAY_H +#define __ASM_VDSO_GETTIMEOFDAY_H + +#ifndef __ASSEMBLY__ + +#include +#include +#include +#include +#include +#include +#define VDSO_HAS_CLOCK_GETRES 1 + +static __always_inline +int gettimeofday_fallback(struct __kernel_old_timeval *_tv, + struct timezone *_tz) +{ + long retval; + long error; + asm volatile( + " mov %2, $16\n" + " mov %3, $17\n" + " ldi $0, %4\n" + " sys_call %5\n" + " mov $0, %0\n" + " mov $19, %1" + : "=r"(retval), "=r"(error) + : "r"(_tv), "r"(_tz), "i"(__NR_gettimeofday), "i"(HMC_callsys) + : "$0", "$16", "$17", "$19"); + if (unlikely(error)) + return -retval; + else + return retval; +} + +static __always_inline +long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts) +{ + long retval; + long error; + asm volatile( + " mov %2, $16\n" + " mov %3, $17\n" + " ldi $0, %4\n" + " sys_call %5\n" + " mov $0, %0\n" + " mov $19, %1" + : "=r"(retval), "=r"(error) + : "r"(_clkid), "r"(_ts), "i"(__NR_clock_gettime), "i"(HMC_callsys) + : "$0", "$16", "$17", "$19"); + if (unlikely(error)) + return -retval; + else + return retval; +} + +static __always_inline +int clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts) +{ + long retval; + long error; + asm volatile( + " mov %2, $16\n" + " mov %3, $17\n" + " ldi $0, %4\n" + " sys_call %5\n" + " mov $0, %0\n" + " mov $19, %1" + : "=r"(retval), "=r"(error) + : "r"(_clkid), "r"(_ts), "i"(__NR_clock_getres), "i"(HMC_callsys) + : "$0", "$16", "$17", "$19"); + if (unlikely(error)) + return -retval; + else + return retval; +} + +#if defined(CONFIG_SUBARCH_C3B) +static __always_inline u64 __arch_get_hw_counter(s32 clock_mode, + const struct vdso_data *vd) +{ + register unsigned long __r0 __asm__("$0"); + + __asm__ __volatile__( + "sys_call %1" : "=r"(__r0) : "i" (HMC_longtime)); + + return __r0; +} +#elif defined(CONFIG_SUBARCH_C4) +static __always_inline u64 __arch_get_hw_counter(s32 clock_mode, + const struct vdso_data *vd) +{ + return sw64_read_csr(CSR_SHTCLOCK); +} +#endif + +static __always_inline const struct vdso_data *__arch_get_vdso_data(void) +{ + return _vdso_data; +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* __ASM_VDSO_GETTIMEOFDAY_H */ diff --git a/arch/sw_64/include/asm/vdso/processor.h b/arch/sw_64/include/asm/vdso/processor.h new file mode 100644 index 0000000000000000000000000000000000000000..8bd332e1db8754b59276f07cd726f9a3f2673a3b --- /dev/null +++ b/arch/sw_64/include/asm/vdso/processor.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef __ASM_VDSO_PROCESSOR_H +#define __ASM_VDSO_PROCESSOR_H + +#include + +#endif /* __ASM_VDSO_PROCESSOR_H */ diff --git a/arch/sw_64/include/asm/vdso/vsyscall.h b/arch/sw_64/include/asm/vdso/vsyscall.h new file mode 100644 index 0000000000000000000000000000000000000000..edd710ccd851cb6b570d2e171fdf9ad102461498 --- /dev/null +++ b/arch/sw_64/include/asm/vdso/vsyscall.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_VDSO_VSYSCALL_H +#define __ASM_VDSO_VSYSCALL_H + +#ifndef __ASSEMBLY__ + +#include +#include + +extern struct vdso_data *vdso_data; + +/* + * Update the vDSO data page to keep in sync with kernel timekeeping. + */ +static __always_inline struct vdso_data *__sw64_get_k_vdso_data(void) +{ + return vdso_data; +} + +#define __arch_get_k_vdso_data __sw64_get_k_vdso_data + +/* The asm-generic header needs to be included after the definitions above */ +#include + +#endif /* !__ASSEMBLY__ */ + +#endif /* __ASM_VDSO_VSYSCALL_H */ diff --git a/arch/sw_64/include/uapi/asm/kvm.h b/arch/sw_64/include/uapi/asm/kvm.h index 430e82acee3ed9666fd9e983729c8b6b2493391c..8cc5f752bc6b8549ae74594ebc7f7ea5e561a4d2 100644 --- a/arch/sw_64/include/uapi/asm/kvm.h +++ b/arch/sw_64/include/uapi/asm/kvm.h @@ -19,6 +19,8 @@ enum SW64_KVM_IRQ { }; #define __KVM_HAVE_IRQ_LINE +#define __KVM_HAVE_READONLY_MEM +#define __KVM_HAVE_GUEST_DEBUG #define KVM_NR_IRQCHIPS 1 diff --git a/arch/sw_64/include/uapi/asm/mman.h b/arch/sw_64/include/uapi/asm/mman.h index c83c4b50662a44c5f849990355ac763d4f210329..0214e6eda384f8a74fdd62216dc643682de8d3b4 100644 --- a/arch/sw_64/include/uapi/asm/mman.h +++ b/arch/sw_64/include/uapi/asm/mman.h @@ -2,8 +2,6 @@ #ifndef _UAPI_ASM_SW64_MMAN_H #define _UAPI_ASM_SW64_MMAN_H -#include - #define PROT_READ 0x1 /* page can be read */ #define PROT_WRITE 0x2 /* page can be written */ #define PROT_EXEC 0x4 /* page can be executed */ @@ -79,6 +77,9 @@ #define MADV_COLLAPSE 25 /* Synchronous hugepage collapse */ +#define MADV_HWPOISON 100 /* poison a page for testing */ +#define MADV_SOFT_OFFLINE 101 /* soft offline page for testing */ + /* compatibility flags */ #define MAP_FILE 0 diff --git a/arch/sw_64/kernel/Makefile b/arch/sw_64/kernel/Makefile index b5756003776fe8cdca1fd84bcb17ae123a5aaf6f..0b001246251755b5ca229b5af1324f76d09ed219 100644 --- a/arch/sw_64/kernel/Makefile +++ b/arch/sw_64/kernel/Makefile @@ -13,7 +13,7 @@ CFLAGS_REMOVE_insn.o = -pg CFLAGS_REMOVE_printk.o = -pg endif -obj-y := fpu.o traps.o process.o sys_sw64.o irq.o \ +obj-y := fpu.o traps.o process.o sys_sw64.o irq.o cpu.o \ signal.o setup.o ptrace.o time.o \ systbls.o dup_print.o chip_setup.o \ insn.o early_init.o topology.o cacheinfo.o \ @@ -28,13 +28,19 @@ obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_SUSPEND) += suspend_asm.o suspend.o -obj-$(CONFIG_PERF_EVENTS) += perf_event.o +obj-$(CONFIG_PERF_EVENTS) += perf_callchain.o obj-$(CONFIG_HIBERNATION) += hibernate_asm.o hibernate.o obj-$(CONFIG_AUDIT) += audit.o obj-$(CONFIG_RELOCATABLE) += relocate.o obj-$(CONFIG_DEBUG_FS) += segvdbg.o unaligned.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o obj-$(CONFIG_DEBUG_MATCH) += match.o +obj-$(CONFIG_EFI) += efi.o + +ifdef CONFIG_PERF_EVENTS +obj-$(CONFIG_SUBARCH_C3B) += perf_event.o +obj-$(CONFIG_SUBARCH_C4) += perf_event_c4.o +endif ifndef CONFIG_PCI obj-y += pci-noop.o diff --git a/arch/sw_64/kernel/acpi.c b/arch/sw_64/kernel/acpi.c index 515728920cfdc90b09336a469a8a58e5cc028e7b..ebe3447520355772fec120a86c53818ed96ee097 100644 --- a/arch/sw_64/kernel/acpi.c +++ b/arch/sw_64/kernel/acpi.c @@ -6,6 +6,7 @@ #include #include +#include #include #ifdef CONFIG_ACPI_HOTPLUG_CPU diff --git a/arch/sw_64/kernel/asm-offsets.c b/arch/sw_64/kernel/asm-offsets.c index d865caffd0140130bebe216d204e23fb098fd7e0..c4e4e40a03d51904c32daef75e9f4a9a0bab5098 100644 --- a/arch/sw_64/kernel/asm-offsets.c +++ b/arch/sw_64/kernel/asm-offsets.c @@ -30,9 +30,6 @@ void foo(void) DEFINE(TASK_GROUP_LEADER, offsetof(struct task_struct, group_leader)); DEFINE(TASK_TGID, offsetof(struct task_struct, tgid)); DEFINE(TASK_STACK, offsetof(struct task_struct, stack)); -#ifdef CONFIG_SMP - DEFINE(TASK_CPU, offsetof(struct task_struct, thread_info.cpu)); -#endif BLANK(); OFFSET(PSTATE_REGS, processor_state, regs); diff --git a/arch/sw_64/kernel/cacheinfo.c b/arch/sw_64/kernel/cacheinfo.c index e340c53690a9e486269465512e9ddf494afd1fe0..c8528cf9f3ba3e5981b1814bb0789556b34af701 100644 --- a/arch/sw_64/kernel/cacheinfo.c +++ b/arch/sw_64/kernel/cacheinfo.c @@ -14,27 +14,74 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + #include +#include + +#include +#include -#include +#define get_cache_info(type) cpuid(GET_CACHE_INFO, (type)) +#define get_cache_size(info) ((info) & 0xffffffffUL) +#define get_cacheline_size(info) (1 << (((info) >> 32) & 0xfUL)) +#define get_cache_sets(info) (1 << (((info) >> 36) & 0x3fUL)) +#define get_cache_ways(info) (get_cache_size(info) / get_cache_sets(info) / get_cacheline_size(info)) +#define cache_size(type) get_cache_size(get_cache_info((type))) +#define cache_level(type) ((type) < L2_CACHE ? 1 : (type)) /* Populates leaf and increments to next leaf */ -#define populate_cache(cache, leaf, c_level, c_type, c_id) \ -do { \ - leaf->id = c_id; \ - leaf->attributes = CACHE_ID; \ - leaf->type = c_type; \ - leaf->level = c_level; \ - leaf->coherency_line_size = c->cache.linesz; \ - leaf->number_of_sets = c->cache.sets; \ - leaf->ways_of_associativity = c->cache.ways; \ - leaf->size = c->cache.size; \ - leaf++; \ +#define populate_cache(cache_info, leaf, c_level, c_type, c_id) \ +do { \ + leaf->id = c_id; \ + leaf->attributes = CACHE_ID; \ + leaf->type = c_type; \ + leaf->level = c_level; \ + leaf->coherency_line_size = get_cacheline_size(cache_info); \ + leaf->number_of_sets = get_cache_sets(cache_info); \ + leaf->ways_of_associativity = get_cache_ways(cache_info); \ + leaf->size = get_cache_size(cache_info); \ } while (0) +static struct cacheinfo *get_cacheinfo(int cpu, int level, enum cache_type type) +{ + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + struct cacheinfo *leaf; + int index; + + for (index = 0; index < this_cpu_ci->num_leaves; index++) { + leaf = this_cpu_ci->info_list + index; + if ((leaf->level == level) && (leaf->type == type)) + return leaf; + } + + return NULL; +} + +unsigned int get_cpu_cache_size(int cpu, int level, enum cache_type type) +{ + struct cacheinfo *leaf = get_cacheinfo(cpu, level, type); + + return leaf ? leaf->size : 0; +} + +unsigned int get_cpu_cacheline_size(int cpu, int level, enum cache_type type) +{ + struct cacheinfo *leaf = get_cacheinfo(cpu, level, type); + + return leaf ? leaf->coherency_line_size : 0; +} + + +static inline enum cache_type kernel_cache_type(enum sunway_cache_type type) +{ + if ((type > L1_DCACHE) || !cache_size(L1_ICACHE)) + return CACHE_TYPE_UNIFIED; + + return (type == L1_DCACHE) ? CACHE_TYPE_DATA : CACHE_TYPE_INST; +} + int init_cache_level(unsigned int cpu) { - struct cpuinfo_sw64 *c = &cpu_data[cpu]; struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); int levels = 0, leaves = 0; @@ -42,58 +89,102 @@ int init_cache_level(unsigned int cpu) * If Dcache is not set, we assume the cache structures * are not properly initialized. */ - if (c->dcache.size) + if (cache_size(L1_DCACHE)) levels += 1; else return -ENOENT; + leaves += cache_size(L1_ICACHE) ? 2 : 1; - leaves += (c->icache.size) ? 2 : 1; - - if (c->scache.size) { + if (cache_size(L2_CACHE)) { levels++; leaves++; } - if (c->tcache.size) { + if (cache_size(L3_CACHE)) { levels++; leaves++; } this_cpu_ci->num_levels = levels; this_cpu_ci->num_leaves = leaves; + return 0; } -int populate_cache_leaves(unsigned int cpu) +static void setup_shared_cpu_map(unsigned int cpu) { - struct cpuinfo_sw64 *c = &cpu_data[cpu]; + unsigned int index; + unsigned int rcid = cpu_to_rcid(cpu); + struct cacheinfo *this_leaf; struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); - struct cacheinfo *this_leaf = this_cpu_ci->info_list; - struct cpu_topology *topo = &cpu_topology[cpu]; - if (c->icache.size) { - cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map); - populate_cache(dcache, this_leaf, 1, CACHE_TYPE_DATA, cpu); - cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map); - populate_cache(icache, this_leaf, 1, CACHE_TYPE_INST, cpu); + for (index = 0; index < this_cpu_ci->num_leaves; index++) { + unsigned int i; - } else { - cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map); - populate_cache(dcache, this_leaf, 1, CACHE_TYPE_UNIFIED, cpu); - } + this_leaf = this_cpu_ci->info_list + index; - if (c->scache.size) { cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map); - populate_cache(scache, this_leaf, 2, CACHE_TYPE_UNIFIED, cpu); + + for_each_possible_cpu(i) { + unsigned int sib_rcid = cpu_to_rcid(i); + + if ((rcid_to_domain_id(sib_rcid) != rcid_to_domain_id(rcid)) || + (i == cpu)) + continue; + + if ((rcid_to_core_id(rcid) == rcid_to_core_id(sib_rcid)) || + (this_leaf->level == 3)) + cpumask_set_cpu(i, &this_leaf->shared_cpu_map); + } } +} + +static bool is_pptt_cache_info_valid(void) +{ + struct acpi_table_header *table; + acpi_status status; + + if (is_guest_or_emul() || acpi_disabled) + return false; + + status = acpi_get_table(ACPI_SIG_PPTT, 0, &table); + if (ACPI_FAILURE(status)) + return false; + + acpi_put_table(table); + + return true; +} + +int populate_cache_leaves(unsigned int cpu) +{ + enum sunway_cache_type type; + unsigned int cache_id; + struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); + struct cacheinfo *this_leaf = this_cpu_ci->info_list; + bool pptt_valid = is_pptt_cache_info_valid(); + + for (type = L1_ICACHE; type <= L3_CACHE; type++, this_leaf++) { + if (!cache_size(type)) + continue; + + /* L3 Cache is shared */ + cache_id = (type == L3_CACHE) ? rcid_to_domain_id(cpu_to_rcid(cpu)) : + rcid_to_core_id(cpu_to_rcid(cpu)); + + populate_cache(get_cache_info(type), this_leaf, cache_level(type), + kernel_cache_type(type), cache_id); + + if (pptt_valid) + this_leaf->attributes &= ~CACHE_ID; - if (c->tcache.size) { - cpumask_copy(&this_leaf->shared_cpu_map, topology_llc_cpumask(cpu)); - populate_cache(tcache, this_leaf, 3, CACHE_TYPE_UNIFIED, topo->package_id); } - this_cpu_ci->cpu_map_populated = true; + if (!pptt_valid) { + setup_shared_cpu_map(cpu); + this_cpu_ci->cpu_map_populated = true; + } return 0; } diff --git a/arch/sw_64/kernel/chip_setup.c b/arch/sw_64/kernel/chip_setup.c index 211d673250c7c8c7eae9b2519731467c354ec637..732943cb18595feba9063d3f659b7f8466999919 100644 --- a/arch/sw_64/kernel/chip_setup.c +++ b/arch/sw_64/kernel/chip_setup.c @@ -3,7 +3,7 @@ #include #include -#include +#include #include #define OFFSET_CORE_ONLINE 0x780UL @@ -38,7 +38,7 @@ static unsigned long __init get_node_mem(int nodeid) return __get_node_mem(nodeid); } -static void __init setup_core_map(struct cpumask *cpumask) +static void __init setup_core_map(void) { int i, j, cpu_num, cpuid, max_cores_per_cpu; unsigned long coreonline; @@ -196,7 +196,7 @@ static inline void intpu_save(void) { void __iomem *intpu_base = misc_platform_get_intpu_base(0); - switch (cpu_desc.model) { + switch (current_cpu_data.model) { case CPU_SW831: saved_long_time = readq(intpu_base + OFFSET_LONG_TIME); default: @@ -210,7 +210,7 @@ static inline void intpu_restore(void) void __iomem *spbu_base = misc_platform_get_spbu_base(0); void __iomem *gpio_base = misc_platform_get_gpio_base(0); - switch (cpu_desc.model) { + switch (current_cpu_data.model) { case CPU_SW831: writeq(saved_long_time, intpu_base + OFFSET_LONG_TIME); writeq(0x1, spbu_base + OFFSET_LONG_TIME_START_EN); diff --git a/arch/sw_64/kernel/cpu.c b/arch/sw_64/kernel/cpu.c new file mode 100644 index 0000000000000000000000000000000000000000..030b334058733088bad230b241ffbd5b7ed3120a --- /dev/null +++ b/arch/sw_64/kernel/cpu.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define TABLE_ENTRY_MAX 32 +#define VENDOR_ID_MAX 2 +#define MODEL_MAX 8 + +#define cpuinfo_arch_rev(cpu_info) ((cpu_info) & 0xf) +#define cpuinfo_arch_var(cpu_info) (((cpu_info) >> 4) & 0xf) +#define cpuinfo_chip_var(cpu_info) (((cpu_info) >> 8) & 0xf) +#define cpuinfo_family(cpu_info) (((cpu_info) >> 12) & 0xf) +#define cpuinfo_model(cpu_info) (((cpu_info) >> 24) & 0xff) +#define cpuinfo_pa_bits(cpu_info) (((cpu_info) >> 32) & 0x7fUL) +#define cpuinfo_va_bits(cpu_info) (((cpu_info) >> 39) & 0x7fUL) + +/* Map logical to physical */ +int __cpu_to_rcid[NR_CPUS]; +EXPORT_SYMBOL(__cpu_to_rcid); + +/* A collection of per-processor data. */ +struct cpuinfo_sw64 cpu_data[NR_CPUS]; +EXPORT_SYMBOL(cpu_data); + +cpumask_t cpu_offline = CPU_MASK_NONE; + +static unsigned long cpu_freq; +static unsigned long cpu_info; +static char vendor_id[16]; +static char model_id[64]; + +unsigned long get_cpu_freq(void) +{ + if (likely(cpu_freq)) + return cpu_freq; + + return cpuid(GET_CPU_FREQ, 0) * 1000UL * 1000UL; +} + +void update_cpu_freq(unsigned long khz) +{ + cpu_freq = khz * 1000; +} + +/* Move global data into per-processor storage */ +void store_cpu_data(int cpu) +{ + cpu_data[cpu].last_asid = ASID_FIRST_VERSION; +} + +static int cpuinfo_cpu_online(unsigned int cpu) +{ + /* Currently, cpu info is shared by all cores */ + cpu_data[cpu].model = cpuinfo_model(cpu_info); + cpu_data[cpu].family = cpuinfo_family(cpu_info); + cpu_data[cpu].chip_var = cpuinfo_chip_var(cpu_info); + cpu_data[cpu].arch_var = cpuinfo_arch_var(cpu_info); + cpu_data[cpu].arch_rev = cpuinfo_arch_rev(cpu_info); + cpu_data[cpu].pa_bits = cpuinfo_pa_bits(cpu_info); + cpu_data[cpu].va_bits = cpuinfo_va_bits(cpu_info); + + cpu_data[cpu].vendor_id = vendor_id; + cpu_data[cpu].model_id = model_id; + + return 0; +} + +static int __init sw64_cpuinfo_init(void) +{ + int i, ret; + unsigned long val; + + /* Get cpu info */ + cpu_info = cpuid(GET_TABLE_ENTRY, 0); + + /* Get vendor name in string format */ + for (i = 0; i < VENDOR_ID_MAX; i++) { + val = cpuid(GET_VENDOR_ID, i); + memcpy(vendor_id + (i * 8), &val, 8); + } + + /* Get model name in string format */ + for (i = 0; i < MODEL_MAX; i++) { + val = cpuid(GET_MODEL, i); + memcpy(model_id + (i * 8), &val, 8); + } + + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "sw64/cpuinfo:online", + cpuinfo_cpu_online, NULL); + if (ret < 0) { + pr_err("cpuinfo: failed to register cpuinfo_cpu_online\n"); + return ret; + } + + return 0; +} +arch_initcall(sw64_cpuinfo_init); + +static int show_cpuinfo(struct seq_file *f, void *slot) +{ + int i; + unsigned int l3_cache_size, l3_cachline_size; + unsigned long freq; + + freq = cpuid(GET_CPU_FREQ, 0); + + for_each_online_cpu(i) { + l3_cache_size = get_cpu_cache_size(i, 3, CACHE_TYPE_UNIFIED); + l3_cachline_size = get_cpu_cacheline_size(i, 3, CACHE_TYPE_UNIFIED); + + /* + * glibc reads /proc/cpuinfo to determine the number of + * online processors, looking for lines beginning with + * "processor". Give glibc what it expects. + */ + seq_printf(f, "processor\t: %u\n" + "vendor_id\t: %s\n" + "cpu family\t: %d\n" + "model\t\t: %u\n" + "model name\t: %s CPU @ %lu.%lu%luGHz\n" + "cpu variation\t: %u\n" + "cpu revision\t: %u\n", + i, vendor_id, cpu_data[i].family, + cpu_data[i].model, model_id, + freq / 1000, (freq % 1000) / 100, + (freq % 100) / 10, + cpu_data[i].arch_var, cpu_data[i].arch_rev); + seq_printf(f, "cpu MHz\t\t: %lu.00\n" + "cache size\t: %u KB\n" + "physical id\t: %d\n" + "bogomips\t: %lu.%02lu\n", + get_cpu_freq() / 1000 / 1000, l3_cache_size >> 10, + cpu_topology[i].package_id, + loops_per_jiffy / (500000/HZ), + (loops_per_jiffy / (5000/HZ)) % 100); + + seq_printf(f, "flags\t\t: fpu simd vpn upn cpuid%s\n", + (cpuid(GET_FEATURES, 0) & CPU_FEAT_UNA) ? " una" : ""); + seq_printf(f, "page size\t: %d\n", 8192); + seq_printf(f, "cache_alignment\t: %d\n", l3_cachline_size); + seq_printf(f, "address sizes\t: %u bits physical, %u bits virtual\n\n", + cpu_data[i].pa_bits, cpu_data[i].va_bits); + } + + return 0; +} + +/* + * We show only CPU #0 info. + */ +static void *c_start(struct seq_file *f, loff_t *pos) +{ + return *pos < 1 ? (void *)1 : NULL; +} + +static void *c_next(struct seq_file *f, void *v, loff_t *pos) +{ + (*pos)++; + return NULL; +} + +static void c_stop(struct seq_file *f, void *v) +{ +} + +const struct seq_operations cpuinfo_op = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, +}; + +bool arch_match_cpu_phys_id(int cpu, u64 phys_id) +{ + return phys_id == cpu_physical_id(cpu); +} diff --git a/arch/sw_64/kernel/efi.c b/arch/sw_64/kernel/efi.c new file mode 100644 index 0000000000000000000000000000000000000000..8bf80b271581adeb4dcd9de5b591abd8c14c954a --- /dev/null +++ b/arch/sw_64/kernel/efi.c @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +#include + +bool efi_poweroff_required(void) +{ + /* VM has its own poweroff interface */ + if (!is_in_host()) + return false; + + /* Prefer ACPI S5 */ + if (acpi_sleep_state_supported(ACPI_STATE_S5)) + return false; + + return efi_enabled(EFI_RUNTIME_SERVICES); +} diff --git a/arch/sw_64/kernel/hmcall.c b/arch/sw_64/kernel/hmcall.c index d2054a930bd72f648c363bee4282ddddd0f36572..50aaa2b9b5b4ffb1ece30898c3996f134679f083 100644 --- a/arch/sw_64/kernel/hmcall.c +++ b/arch/sw_64/kernel/hmcall.c @@ -108,6 +108,14 @@ static inline void fixup_wrusp(void) entry[1] = 0x1ee00000; /* pri_ret $23 */ } +static inline void fixup_uwhami(void) +{ + unsigned int *entry = __va(HMCALL_ENTRY(uwhami)); + + entry[0] = 0x94161078; /* pri_ldl/p r0, VC__WHAMI(vcpucb) */ + entry[1] = 0x1ef00000; /* pri_ret/b $23 */ +} + void __init fixup_hmcall(void) { #if defined(CONFIG_SUBARCH_C3B) @@ -119,6 +127,7 @@ void __init fixup_hmcall(void) fixup_wrktp(); fixup_rdusp(); fixup_wrusp(); + fixup_uwhami(); imemb(); #endif } diff --git a/arch/sw_64/kernel/irq.c b/arch/sw_64/kernel/irq.c index 5706df471a8dc40455336c7a155bca969fe596e5..82854ba75a940b89a91a6b931adfb0f39a6dee9c 100644 --- a/arch/sw_64/kernel/irq.c +++ b/arch/sw_64/kernel/irq.c @@ -17,6 +17,7 @@ #include #include +#include #include volatile unsigned long irq_err_count; @@ -127,7 +128,7 @@ void __init init_IRQ(void) set_nmi(INT_PC); } - sw64_init_irq(); + sunway_init_pci_intx(); irqchip_init(); } diff --git a/arch/sw_64/kernel/machine_kexec.c b/arch/sw_64/kernel/machine_kexec.c index f0a2338ddcbd64ab101b0d72c699b9dba51daca8..4ef59d6022fcb9d571a7e6c85969d0c2d3359989 100644 --- a/arch/sw_64/kernel/machine_kexec.c +++ b/arch/sw_64/kernel/machine_kexec.c @@ -54,7 +54,7 @@ void __init kexec_control_page_init(void) phys_addr_t addr; addr = memblock_phys_alloc_range(KEXEC_CONTROL_PAGE_SIZE, PAGE_SIZE, - 0, KTEXT_MAX); + 0, 0); kexec_control_page = (void *)(__START_KERNEL_map + addr); } @@ -105,8 +105,8 @@ void __init reserve_crashkernel(void) pr_warn("Add crash kernel area [mem %#018llx-%#018llx] to memmap region failed.\n", crash_base, crash_base + crash_size - 1); - if (crash_base >= KERNEL_IMAGE_SIZE) - pr_warn("Crash base should be less than %#x\n", KERNEL_IMAGE_SIZE); + if (crash_base < PCI_LEGACY_IO_SIZE) + pr_warn("Crash base should be greater than or equal to %#lx\n", PCI_LEGACY_IO_SIZE); crashk_res.start = crash_base; crashk_res.end = crash_base + crash_size - 1; @@ -192,7 +192,6 @@ void machine_crash_shutdown(struct pt_regs *regs) cpu = smp_processor_id(); local_irq_disable(); - kernel_restart_prepare(NULL); atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); smp_call_function(machine_crash_nonpanic_core, NULL, false); msecs = 1000; /* Wait at most a second for the other cpus to stop */ diff --git a/arch/sw_64/kernel/pci-noop.c b/arch/sw_64/kernel/pci-noop.c index abfba92fa6a9c388542859b69884b208a424c9c3..9fc6bb3736057510a37e37ea75b0bda6887d0f79 100644 --- a/arch/sw_64/kernel/pci-noop.c +++ b/arch/sw_64/kernel/pci-noop.c @@ -135,4 +135,4 @@ void __init common_init_pci(void) } void __init sw64_init_arch(void) { } -void __init sw64_init_irq(void) { } +void __init sunway_init_pci_intx(void) { } diff --git a/arch/sw_64/kernel/perf_callchain.c b/arch/sw_64/kernel/perf_callchain.c new file mode 100644 index 0000000000000000000000000000000000000000..0c0a4c180919af26a22da40537e83f637788164a --- /dev/null +++ b/arch/sw_64/kernel/perf_callchain.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * sw64 callchain support + * + * Copyright (C) 2023 SW64 Limited + */ +#include +#include + +#include + +bool valid_utext_addr(unsigned long addr) +{ + return addr >= current->mm->start_code && addr <= current->mm->end_code; +} + +bool valid_dy_addr(unsigned long addr) +{ + bool ret = false; + struct vm_area_struct *vma; + struct mm_struct *mm = current->mm; + + if (addr > TASK_SIZE || addr < TASK_UNMAPPED_BASE) + return ret; + vma = find_vma(mm, addr); + if (vma && vma->vm_start <= addr && (vma->vm_flags & VM_EXEC)) + ret = true; + return ret; +} + +#ifdef CONFIG_FRAME_POINTER +void perf_callchain_user(struct perf_callchain_entry_ctx *entry, + struct pt_regs *regs) +{ + + struct stack_frame frame; + unsigned long __user *fp; + int err; + + perf_callchain_store(entry, regs->pc); + + fp = (unsigned long __user *)regs->regs[15]; + + while (entry->nr < entry->max_stack && + (unsigned long)fp < current->mm->start_stack) { + if (!access_ok(fp, sizeof(frame))) + break; + + pagefault_disable(); + err = __copy_from_user_inatomic(&frame, fp, sizeof(frame)); + pagefault_enable(); + + if (err) + break; + + if (valid_utext_addr(frame.return_address) || + valid_dy_addr(frame.return_address)) + perf_callchain_store(entry, frame.return_address); + else + break; + fp = (void __user *)frame.next_frame; + } +} +#else /* !CONFIG_FRAME_POINTER */ +void perf_callchain_user(struct perf_callchain_entry_ctx *entry, + struct pt_regs *regs) +{ + unsigned long usp = current_user_stack_pointer(); + unsigned long user_addr; + int err; + + perf_callchain_store(entry, regs->pc); + + while (entry->nr < entry->max_stack && usp < current->mm->start_stack) { + if (!access_ok((const void __user *)usp, 8)) + break; + + pagefault_disable(); + err = __get_user(user_addr, (unsigned long *)usp); + pagefault_enable(); + + if (err) + break; + + if (valid_utext_addr(user_addr) || valid_dy_addr(user_addr)) + perf_callchain_store(entry, user_addr); + usp = usp + 8; + } +} +#endif/* CONFIG_FRAME_POINTER */ + +/* + * Gets called by walk_stackframe() for every stackframe. This will be called + * whist unwinding the stackframe and is like a subroutine return so we use + * the PC. + */ +static int callchain_trace(unsigned long pc, void *data) +{ + struct perf_callchain_entry_ctx *entry = data; + + perf_callchain_store(entry, pc); + return 0; +} + +void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, + struct pt_regs *regs) +{ + walk_stackframe(NULL, regs, callchain_trace, entry); +} + +/* + * Gets the perf_instruction_pointer and perf_misc_flags for guest os. + */ +#undef is_in_guest + +unsigned long perf_instruction_pointer(struct pt_regs *regs) +{ + if (perf_guest_state()) + return perf_guest_get_ip(); + + return instruction_pointer(regs); +} + +unsigned long perf_misc_flags(struct pt_regs *regs) +{ + unsigned int guest_state = perf_guest_state(); + int misc = 0; + + if (guest_state) { + if (guest_state & PERF_GUEST_USER) + misc |= PERF_RECORD_MISC_GUEST_USER; + else + misc |= PERF_RECORD_MISC_GUEST_KERNEL; + } else { + if (user_mode(regs)) + misc |= PERF_RECORD_MISC_USER; + else + misc |= PERF_RECORD_MISC_KERNEL; + } + + return misc; +} diff --git a/arch/sw_64/kernel/perf_event.c b/arch/sw_64/kernel/perf_event.c index 7544814615a8893679be52ba4cabcb73d83b5e33..c0aede9321b47d8c0f6fa74d5986e61347383a2d 100644 --- a/arch/sw_64/kernel/perf_event.c +++ b/arch/sw_64/kernel/perf_event.c @@ -8,17 +8,6 @@ #include #include -/* For tracking PMCs and the hw events they monitor on each CPU. */ -struct cpu_hw_events { - /* - * Set the bit (indexed by the counter number) when the counter - * is used for an event. - */ - unsigned long used_mask[BITS_TO_LONGS(MAX_HWEVENTS)]; - /* Array of events current scheduled on this cpu. */ - struct perf_event *event[MAX_HWEVENTS]; -}; - DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events); struct sw64_perf_event { @@ -629,101 +618,6 @@ static void sw64_perf_event_irq_handler(unsigned long idx, } } -bool valid_utext_addr(unsigned long addr) -{ - return addr >= current->mm->start_code && addr <= current->mm->end_code; -} - -bool valid_dy_addr(unsigned long addr) -{ - bool ret = false; - struct vm_area_struct *vma; - struct mm_struct *mm = current->mm; - - if (addr > TASK_SIZE || addr < TASK_UNMAPPED_BASE) - return ret; - vma = find_vma(mm, addr); - if (vma && vma->vm_start <= addr && (vma->vm_flags & VM_EXEC)) - ret = true; - return ret; -} - -#ifdef CONFIG_FRAME_POINTER -void perf_callchain_user(struct perf_callchain_entry_ctx *entry, - struct pt_regs *regs) -{ - - struct stack_frame frame; - unsigned long __user *fp; - int err; - - perf_callchain_store(entry, regs->pc); - - fp = (unsigned long __user *)regs->regs[15]; - - while (entry->nr < entry->max_stack && (unsigned long)fp < current->mm->start_stack) { - if (!access_ok(fp, sizeof(frame))) - break; - - pagefault_disable(); - err = __copy_from_user_inatomic(&frame, fp, sizeof(frame)); - pagefault_enable(); - - if (err) - break; - - if (valid_utext_addr(frame.return_address) || valid_dy_addr(frame.return_address)) - perf_callchain_store(entry, frame.return_address); - fp = (void __user *)frame.next_frame; - } -} -#else /* !CONFIG_FRAME_POINTER */ -void perf_callchain_user(struct perf_callchain_entry_ctx *entry, - struct pt_regs *regs) -{ - unsigned long usp = rdusp(); - unsigned long user_addr; - int err; - - perf_callchain_store(entry, regs->pc); - - while (entry->nr < entry->max_stack && usp < current->mm->start_stack) { - if (!access_ok((const void __user *)usp, 8)) - break; - - pagefault_disable(); - err = __get_user(user_addr, (unsigned long *)usp); - pagefault_enable(); - - if (err) - break; - - if (valid_utext_addr(user_addr) || valid_dy_addr(user_addr)) - perf_callchain_store(entry, user_addr); - usp = usp + 8; - } -} -#endif/* CONFIG_FRAME_POINTER */ - -/* - * Gets called by walk_stackframe() for every stackframe. This will be called - * whist unwinding the stackframe and is like a subroutine return so we use - * the PC. - */ -static int callchain_trace(unsigned long pc, void *data) -{ - struct perf_callchain_entry_ctx *entry = data; - - perf_callchain_store(entry, pc); - return 0; -} - -void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, - struct pt_regs *regs) -{ - walk_stackframe(NULL, regs, callchain_trace, entry); -} - /* * Init call to initialise performance events at kernel startup. */ @@ -755,35 +649,3 @@ int __init init_hw_perf_events(void) return 0; } early_initcall(init_hw_perf_events); - -/* - * Gets the perf_instruction_pointer and perf_misc_flags for guest os. - */ - -unsigned long perf_instruction_pointer(struct pt_regs *regs) -{ - if (perf_guest_state()) - return perf_guest_get_ip(); - - return instruction_pointer(regs); -} - -unsigned long perf_misc_flags(struct pt_regs *regs) -{ - unsigned int guest_state = perf_guest_state(); - int misc = 0; - - if (guest_state) { - if (guest_state & PERF_GUEST_USER) - misc |= PERF_RECORD_MISC_GUEST_USER; - else - misc |= PERF_RECORD_MISC_GUEST_KERNEL; - } else { - if (user_mode(regs)) - misc |= PERF_RECORD_MISC_USER; - else - misc |= PERF_RECORD_MISC_KERNEL; - } - - return misc; -} diff --git a/arch/sw_64/kernel/perf_event_c4.c b/arch/sw_64/kernel/perf_event_c4.c index 7a5e8deba0ee2f1e17b4e4498a9212c5695955c2..302d3c65b61f25cec72fa08b517510e62c4031db 100644 --- a/arch/sw_64/kernel/perf_event_c4.c +++ b/arch/sw_64/kernel/perf_event_c4.c @@ -507,7 +507,7 @@ static void hw_perf_event_destroy(struct perf_event *event) /* Nothing to be done! */ } -static int __hw_perf_event_init(struct perf_event *event) +static void __hw_perf_event_init(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; @@ -523,8 +523,6 @@ static int __hw_perf_event_init(struct perf_event *event) hwc->last_period = hwc->sample_period; local64_set(&hwc->period_left, hwc->sample_period); } - - return 0; } /* @@ -632,6 +630,7 @@ static void sw64_perf_event_irq_handler(unsigned long perfmon_num, int idx; u64 val; + __this_cpu_inc(irq_pmi_count); cpuc = this_cpu_ptr(&cpu_hw_events); for (idx = 0; idx < sw64_pmu->num_pmcs; ++idx) { @@ -660,8 +659,6 @@ static void sw64_perf_event_irq_handler(unsigned long perfmon_num, if (perf_event_overflow(event, &data, regs)) sw64_pmu_stop(event, 0); } - - } /* @@ -669,12 +666,18 @@ static void sw64_perf_event_irq_handler(unsigned long perfmon_num, */ int __init init_hw_perf_events(void) { + pr_info("Performance Events: "); if (!supported_cpu()) { pr_info("Performance events: Unsupported CPU type!\n"); return 0; } - pr_info("Performance events: Supported CPU type!\n"); + if (is_in_guest()) { + pr_cont("No PMU driver, software events only.\n"); + return 0; + } + + pr_cont("Supported CPU type!\n"); /* Override performance counter IRQ vector */ diff --git a/arch/sw_64/kernel/process.c b/arch/sw_64/kernel/process.c index 1867abfe33804746afcccd795521b3a7b2a3ac63..eac26883cf690336a5ade0f239ea44802543b5b4 100644 --- a/arch/sw_64/kernel/process.c +++ b/arch/sw_64/kernel/process.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include diff --git a/arch/sw_64/kernel/ptrace.c b/arch/sw_64/kernel/ptrace.c index 0af3d35163f9fe3cb1534f0645a22359398b510f..9c5539f58ded7cc5540f46c0cb1fba5aa4e35e15 100644 --- a/arch/sw_64/kernel/ptrace.c +++ b/arch/sw_64/kernel/ptrace.c @@ -290,9 +290,33 @@ static int fpr_set(struct task_struct *target, sizeof(struct user_fpsimd_state)); } +static int syscall_get(struct task_struct *target, + const struct user_regset *regset, + struct membuf to) +{ + return membuf_store(&to, task_pt_regs(target)->orig_r0); +} + +static int syscall_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + unsigned long nr = task_pt_regs(target)->orig_r0; + int ret; + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &nr, 0, -1); + if (ret) + return ret; + + task_pt_regs(target)->orig_r0 = nr; + return ret; +} + enum sw64_regset { REGSET_GPR, REGSET_FPR, + REGSET_SYSCALL, }; static const struct user_regset sw64_regsets[] = { @@ -312,6 +336,14 @@ static const struct user_regset sw64_regsets[] = { .regset_get = fpr_get, .set = fpr_set }, + [REGSET_SYSCALL] = { + .core_note_type = NT_SW64_SYSTEM_CALL, + .n = 1, + .size = sizeof(u64), + .align = sizeof(u64), + .regset_get = syscall_get, + .set = syscall_set + } }; static const struct user_regset_view user_sw64_view = { diff --git a/arch/sw_64/kernel/relocate_kernel.S b/arch/sw_64/kernel/relocate_kernel.S index f1a160636212fed8e73dd32616edaea155c51154..a4b0d27778b93af909ba0eaaac33a81facf006be 100644 --- a/arch/sw_64/kernel/relocate_kernel.S +++ b/arch/sw_64/kernel/relocate_kernel.S @@ -16,11 +16,6 @@ relocate_new_kernel: .prologue 0 - ldl a0, arg0 - ldl a1, arg1 - ldl a2, arg2 - ldl a3, arg3 - ldl s0, kexec_indirection_page ldl s1, kexec_start_address @@ -100,10 +95,6 @@ done: .globl kexec_smp_wait .ent kexec_smp_wait kexec_smp_wait: - ldl a0, s_arg0 - ldl a1, s_arg1 - ldl a2, s_arg2 - ldl a3, s_arg3 ldl s1, kexec_start_address /* Non-relocated address works for args and kexec_start_address (old @@ -124,35 +115,6 @@ kexec_smp_wait: jmp ra, (s1) .end kexec_smp_wait .size kexec_smp_wait, .-kexec_smp_wait -#endif - - .align 3 - - /* All parameters to new kernel are passed in registers a0-a3. - * kexec_args[0..3] are uses to prepare register values. - */ - -kexec_args: - .globl kexec_args -arg0: .quad 0x0 -arg1: .quad 0x0 -arg2: .quad 0x0 -arg3: .quad 0x0 - .size kexec_args, 8*4 - -#ifdef CONFIG_CRASH_SMP - /* - * Secondary CPUs may have different kernel parameters in - * their registers a0-a3. secondary_kexec_args[0..3] are used - * to prepare register values. - */ -secondary_kexec_args: - .globl secondary_kexec_args -s_arg0: .quad 0x0 -s_arg1: .quad 0x0 -s_arg2: .quad 0x0 -s_arg3: .quad 0x0 - .size secondary_kexec_args, 8*4 kexec_flag: .quad 0x1 diff --git a/arch/sw_64/kernel/reset.c b/arch/sw_64/kernel/reset.c index 3f1961ce85dee6cb8f172fabd3dd48f3881b957e..8181923e676eb29d99ce3f486759d6ce008adc04 100644 --- a/arch/sw_64/kernel/reset.c +++ b/arch/sw_64/kernel/reset.c @@ -1,42 +1,30 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (C) 2020-2022 Sunway Technology Corporation Limited + * Copyright (C) 2020-2024 Sunway Technology Corporation Limited */ + #include #include #include #include #include #include -#include #include #include #include #include #include -#include - -void fix_jm585_reset(void) -{ - struct pci_dev *pdev; - struct pci_controller *hose; - int val; +#include - pdev = pci_get_device(PCI_VENDOR_ID_JMICRON, - 0x0585, NULL); - if (pdev) { - hose = pci_bus_to_pci_controller(pdev->bus); - val = readl(hose->rc_config_space_base + RC_PORT_LINK_CTL); - writel((val | 0x8), (hose->rc_config_space_base + RC_PORT_LINK_CTL)); - writel(val, (hose->rc_config_space_base + RC_PORT_LINK_CTL)); - - } +void (*pm_power_off)(void); +EXPORT_SYMBOL(pm_power_off); -} -static void default_halt(void) +void machine_halt(void) { + preempt_disable(); local_irq_disable(); + smp_send_stop(); pr_notice("\n\n** You can safely turn off the power now **\n\n"); @@ -44,75 +32,89 @@ static void default_halt(void) arch_cpu_idle(); } -static void default_poweroff(void) +void machine_power_off(void) { - /* No point in taking interrupts anymore. */ + preempt_disable(); local_irq_disable(); -#ifdef CONFIG_EFI - efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL); -#endif + smp_send_stop(); + + do_kernel_power_off(); + + /* VM cannot reach here */ + WARN_ON(!is_in_host()); + + /** + * Compatibility with old firmware, can be removed + * when no longer support SW3231. + */ + if (!sunway_bios_version) + cpld_write(0x64, 0x00, 0xf0); + while (true) arch_cpu_idle(); } -static void default_restart(void) +void machine_restart(char *command) { - /* No point in taking interrupts anymore. */ + preempt_disable(); local_irq_disable(); + smp_send_stop(); - fix_jm585_reset(); -#ifdef CONFIG_EFI - if (efi_capsule_pending(NULL)) - efi_reboot(REBOOT_WARM, NULL); - else - efi_reboot(REBOOT_COLD, NULL); -#endif - - while (true) - arch_cpu_idle(); -} + do_kernel_restart(command); -void (*pm_restart)(void); + /* VM cannot reach here */ + WARN_ON(!is_in_host()); -void (*pm_power_off)(void); -EXPORT_SYMBOL(pm_power_off); + acpi_reboot(); -void (*pm_halt)(void); + /** + * Compatibility with old firmware, can be removed + * when no longer support SW3231. + */ + if (!sunway_bios_version) + cpld_write(0x64, 0x00, 0xc3); + else if (efi_enabled(EFI_RUNTIME_SERVICES)) + efi_reboot(reboot_mode, NULL); -void machine_halt(void) -{ -#ifdef CONFIG_SMP - preempt_disable(); - smp_send_stop(); -#endif - pm_halt(); + while (true) + arch_cpu_idle(); } -void machine_power_off(void) +static int vm_restart(struct sys_off_data *data) { -#ifdef CONFIG_SMP - preempt_disable(); - smp_send_stop(); -#endif - pm_power_off(); + hcall(HCALL_SET_CLOCKEVENT, 0, 0, 0); + hcall(HCALL_RESTART, 0, 0, 0); + mb(); + + return NOTIFY_DONE; } -void machine_restart(char *command) +static int vm_power_off(struct sys_off_data *data) { -#ifdef CONFIG_SMP - preempt_disable(); - smp_send_stop(); -#endif - do_kernel_restart(command); - pm_restart(); + hcall(HCALL_SET_CLOCKEVENT, 0, 0, 0); + hcall(HCALL_SHUTDOWN, 0, 0, 0); + mb(); + + return NOTIFY_DONE; } -static int __init sw64_reboot_setup(void) +static int __init vm_power_init(void) { - pm_restart = default_restart; - pm_power_off = default_poweroff; - pm_halt = default_halt; + struct sys_off_handler *handler; + + if (is_in_host()) + return 0; + + handler = register_sys_off_handler(SYS_OFF_MODE_RESTART, + SYS_OFF_PRIO_DEFAULT, vm_restart, NULL); + if (WARN_ON(IS_ERR(handler))) + return PTR_ERR(handler); + + handler = register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, + SYS_OFF_PRIO_DEFAULT, vm_power_off, NULL); + if (WARN_ON(IS_ERR(handler))) + return PTR_ERR(handler); return 0; } -arch_initcall(sw64_reboot_setup); +arch_initcall(vm_power_init); diff --git a/arch/sw_64/kernel/setup.c b/arch/sw_64/kernel/setup.c index b735fe0e3e59f7015db66ca650d9e562d4477fa9..e3608c601cba2370fdbe60824abeb7c30004fa00 100644 --- a/arch/sw_64/kernel/setup.c +++ b/arch/sw_64/kernel/setup.c @@ -39,9 +39,6 @@ #define DBGDCONT(args...) #endif -int __cpu_to_rcid[NR_CPUS]; /* Map logical to physical */ -EXPORT_SYMBOL(__cpu_to_rcid); - DEFINE_PER_CPU(unsigned long, hard_node_id) = { 0 }; static DEFINE_PER_CPU(struct cpu, cpu_devices); @@ -52,7 +49,7 @@ static inline int phys_addr_valid(unsigned long addr) * and other physical address variables cannot be used, so let's * roughly judge physical address based on arch specific bit. */ - return !(addr >> (cpu_desc.pa_bits - 1)); + return !(addr >> (current_cpu_data.pa_bits - 1)); } extern struct atomic_notifier_head panic_notifier_list; @@ -63,9 +60,6 @@ static struct notifier_block sw64_panic_block = { INT_MAX /* try to do it first */ }; -/* the value is IOR: CORE_ONLIE*/ -cpumask_t core_start = CPU_MASK_NONE; - static struct resource data_resource = { .name = "Kernel data", .start = 0, @@ -87,24 +81,20 @@ static struct resource bss_resource = { .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM }; -/* A collection of per-processor data. */ -struct cpuinfo_sw64 cpu_data[NR_CPUS]; -EXPORT_SYMBOL(cpu_data); - DEFINE_STATIC_KEY_TRUE(run_mode_host_key); DEFINE_STATIC_KEY_FALSE(run_mode_guest_key); DEFINE_STATIC_KEY_FALSE(run_mode_emul_key); DEFINE_STATIC_KEY_FALSE(hw_una_enabled); +DEFINE_STATIC_KEY_FALSE(junzhang_v1_key); +DEFINE_STATIC_KEY_FALSE(junzhang_v2_key); +DEFINE_STATIC_KEY_FALSE(junzhang_v3_key); -struct cpu_desc_t cpu_desc; struct socket_desc_t socket_desc[MAX_NUMSOCKETS]; int memmap_nr; struct memmap_entry memmap_map[MAX_NUMMEMMAPS]; bool memblock_initialized; -cpumask_t cpu_offline = CPU_MASK_NONE; - /* boot_params */ /** * Keep sunway_boot_params for backward compatibility. All related code @@ -140,14 +130,6 @@ struct screen_info screen_info = { }; EXPORT_SYMBOL(screen_info); -/* - * Move global data into per-processor storage. - */ -void store_cpu_data(int cpu) -{ - cpu_data[cpu].last_asid = ASID_FIRST_VERSION; -} - #ifdef CONFIG_HARDLOCKUP_DETECTOR_PERF u64 hw_nmi_get_sample_period(int watchdog_thresh) { @@ -403,10 +385,6 @@ static int __init request_standard_resources(void) } subsys_initcall(request_standard_resources); -#ifdef CONFIG_NUMA -extern void cpu_set_node(void); -#endif - static int __init topology_init(void) { int i, ret; @@ -525,6 +503,20 @@ static void __init setup_firmware_fdt(void) pr_info("EXTCLK: %llu Hz\n", sunway_extclk_hz); } + if (sunway_machine_is_compatible("sunway,junzhang")) { + static_branch_enable(&junzhang_v1_key); + static_branch_disable(&junzhang_v2_key); + static_branch_disable(&junzhang_v3_key); + } else if (sunway_machine_is_compatible("sunway,junzhang_v2")) { + static_branch_enable(&junzhang_v2_key); + static_branch_disable(&junzhang_v1_key); + static_branch_disable(&junzhang_v3_key); + } else if (sunway_machine_is_compatible("sunway,junzhang_v3")) { + static_branch_enable(&junzhang_v3_key); + static_branch_disable(&junzhang_v1_key); + static_branch_disable(&junzhang_v2_key); + } + name = of_flat_dt_get_machine_name(); if (name) pr_info("DTB(from firmware): Machine model: %s\n", name); @@ -613,64 +605,6 @@ static void __init device_tree_init(void) unflatten_device_tree(); } -static void __init setup_cpu_info(void) -{ - int i; - struct cache_desc *c; - unsigned long val; - - val = cpuid(GET_TABLE_ENTRY, 0); - cpu_desc.model = CPUID_MODEL(val); - cpu_desc.family = CPUID_FAMILY(val); - cpu_desc.chip_var = CPUID_CHIP_VAR(val); - cpu_desc.arch_var = CPUID_ARCH_VAR(val); - cpu_desc.arch_rev = CPUID_ARCH_REV(val); - cpu_desc.pa_bits = CPUID_PA_BITS(val); - cpu_desc.va_bits = CPUID_VA_BITS(val); - - for (i = 0; i < VENDOR_ID_MAX; i++) { - val = cpuid(GET_VENDOR_ID, i); - memcpy(cpu_desc.vendor_id + (i * 8), &val, 8); - } - - for (i = 0; i < MODEL_MAX; i++) { - val = cpuid(GET_MODEL, i); - memcpy(cpu_desc.model_id + (i * 8), &val, 8); - } - - cpu_desc.frequency = cpuid(GET_CPU_FREQ, 0) * 1000UL * 1000UL; - - for (i = 0; i < NR_CPUS; i++) { - c = &(cpu_data[i].icache); - val = cpuid(GET_CACHE_INFO, L1_ICACHE); - c->size = CACHE_SIZE(val); - c->linesz = 1 << (CACHE_LINE_BITS(val)); - c->sets = 1 << (CACHE_INDEX_BITS(val)); - c->ways = c->size / c->sets / c->linesz; - - c = &(cpu_data[i].dcache); - val = cpuid(GET_CACHE_INFO, L1_DCACHE); - c->size = CACHE_SIZE(val); - c->linesz = 1 << (CACHE_LINE_BITS(val)); - c->sets = 1 << (CACHE_INDEX_BITS(val)); - c->ways = c->size / c->sets / c->linesz; - - c = &(cpu_data[i].scache); - val = cpuid(GET_CACHE_INFO, L2_CACHE); - c->size = CACHE_SIZE(val); - c->linesz = 1 << (CACHE_LINE_BITS(val)); - c->sets = 1 << (CACHE_INDEX_BITS(val)); - c->ways = c->size / c->sets / c->linesz; - - c = &(cpu_data[i].tcache); - val = cpuid(GET_CACHE_INFO, L3_CACHE); - c->size = CACHE_SIZE(val); - c->linesz = 1 << (CACHE_LINE_BITS(val)); - c->sets = 1 << (CACHE_INDEX_BITS(val)); - c->ways = c->size / c->sets / c->linesz; - } -} - #ifdef CONFIG_SUBARCH_C3B static void __init setup_run_mode(void) { @@ -727,7 +661,6 @@ setup_arch(char **cmdline_p) trap_init(); jump_label_init(); - setup_cpu_info(); setup_run_mode(); setup_chip_ops(); @@ -813,87 +746,8 @@ setup_arch(char **cmdline_p) /* Default root filesystem to sda2. */ ROOT_DEV = MKDEV(SCSI_DISK0_MAJOR, 2); - - if (acpi_disabled) { -#ifdef CONFIG_NUMA - cpu_set_node(); -#endif - } } -static int -show_cpuinfo(struct seq_file *f, void *slot) -{ - int i; - unsigned long cpu_freq; - - cpu_freq = cpuid(GET_CPU_FREQ, 0); - - for_each_online_cpu(i) { - /* - * glibc reads /proc/cpuinfo to determine the number of - * online processors, looking for lines beginning with - * "processor". Give glibc what it expects. - */ - seq_printf(f, "processor\t: %u\n" - "vendor_id\t: %s\n" - "cpu family\t: %d\n" - "model\t\t: %u\n" - "model name\t: %s CPU @ %lu.%lu%luGHz\n" - "cpu variation\t: %u\n" - "cpu revision\t: %u\n", - i, cpu_desc.vendor_id, cpu_desc.family, - cpu_desc.model, cpu_desc.model_id, - cpu_freq / 1000, (cpu_freq % 1000) / 100, - (cpu_freq % 100) / 10, - cpu_desc.arch_var, cpu_desc.arch_rev); - seq_printf(f, "cpu MHz\t\t: %lu.00\n" - "cache size\t: %u KB\n" - "physical id\t: %d\n" - "bogomips\t: %lu.%02lu\n", - get_cpu_freq() / 1000 / 1000, cpu_data[i].tcache.size >> 10, - cpu_topology[i].package_id, - loops_per_jiffy / (500000/HZ), - (loops_per_jiffy / (5000/HZ)) % 100); - - seq_printf(f, "flags\t\t: fpu simd vpn upn cpuid\n"); - seq_printf(f, "page size\t: %d\n", 8192); - seq_printf(f, "cache_alignment\t: %d\n", cpu_data[i].tcache.linesz); - seq_printf(f, "address sizes\t: %u bits physical, %u bits virtual\n\n", - cpu_desc.pa_bits, cpu_desc.va_bits); - } - return 0; -} - -/* - * We show only CPU #0 info. - */ -static void * -c_start(struct seq_file *f, loff_t *pos) -{ - return *pos < 1 ? (void *)1 : NULL; -} - -static void * -c_next(struct seq_file *f, void *v, loff_t *pos) -{ - (*pos)++; - return NULL; -} - -static void -c_stop(struct seq_file *f, void *v) -{ -} - -const struct seq_operations cpuinfo_op = { - .start = c_start, - .next = c_next, - .stop = c_stop, - .show = show_cpuinfo, -}; - - static int sw64_panic_event(struct notifier_block *this, unsigned long event, void *ptr) { diff --git a/arch/sw_64/kernel/smp.c b/arch/sw_64/kernel/smp.c index a9577cd915153e9f111f83471564811cb4751fc1..900a32747cfb9e0f9dd530e2f839575dff2c5458 100644 --- a/arch/sw_64/kernel/smp.c +++ b/arch/sw_64/kernel/smp.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -39,6 +40,7 @@ enum ipi_message_type { IPI_RESCHEDULE, IPI_CALL_FUNC, IPI_CPU_STOP, + IPI_IRQ_WORK, }; int smp_num_cpus = 1; /* Number that came online. */ @@ -98,10 +100,11 @@ static void downshift_freq(void) struct cpu_topology *sib_topo = &cpu_topology[cpu]; if ((cpu_topo->package_id == sib_topo->package_id) && - (cpu_topo->core_id == sib_topo->core_id)) + (cpu_topo->core_id == sib_topo->core_id)) return; } + core_id = rcid_to_core_id(cpu_to_rcid(cpuid)); node_id = rcid_to_domain_id(cpu_to_rcid(cpuid)); @@ -155,6 +158,9 @@ void smp_callin(void) current->active_mm = &init_mm; /* update csr:ptbr */ update_ptbr_sys(virt_to_phys(init_mm.pgd)); +#ifdef CONFIG_SUBARCH_C4 + update_ptbr_usr(__pa_symbol(empty_zero_page)); +#endif if (IS_ENABLED(CONFIG_SUBARCH_C4) && is_in_host()) { nmi_stack_page = alloc_pages_node( @@ -397,7 +403,7 @@ void __init setup_smp(void) init_cpu_present(cpu_none_mask); /* Legacy core detect */ - sw64_chip_init->early_init.setup_core_map(&core_start); + sw64_chip_init->early_init.setup_core_map(); /* For unified kernel, NR_CPUS is the maximum possible value */ for (i = 0; i < NR_CPUS; i++) { @@ -535,10 +541,11 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle) wmb(); smp_rcb->ready = 0; -#ifdef CONFIG_SUBARCH_C3B - /* send wake up signal */ - send_wakeup_interrupt(cpu); -#endif + if (!is_junzhang_v1()) { + /* send wake up signal */ + send_wakeup_interrupt(cpu); + } + smp_boot_one_cpu(cpu, tidle); #ifdef CONFIG_SUBARCH_C3B @@ -584,6 +591,13 @@ static void ipi_cpu_stop(int cpu) wait_for_interrupt(); } +#ifdef CONFIG_IRQ_WORK +void arch_irq_work_raise(void) +{ + send_ipi_message(cpumask_of(smp_processor_id()), IPI_IRQ_WORK); +} +#endif + void handle_ipi(struct pt_regs *regs) { int cpu = smp_processor_id(); @@ -613,6 +627,10 @@ void handle_ipi(struct pt_regs *regs) ipi_cpu_stop(cpu); break; + case IPI_IRQ_WORK: + irq_work_run(); + break; + default: pr_crit("Unknown IPI on CPU %d: %lu\n", cpu, which); break; @@ -823,17 +841,16 @@ void arch_cpu_idle_dead(void) } #ifdef CONFIG_SUSPEND - -#ifdef CONFIG_SUBARCH_C3B - sleepen(); - send_sleep_interrupt(smp_processor_id()); - while (1) - asm("nop"); -#else - asm volatile("halt"); - while (1) - asm("nop"); -#endif + if (!is_junzhang_v1()) { + sleepen(); + send_sleep_interrupt(smp_processor_id()); + while (1) + asm("nop"); + } else { + asm volatile("halt"); + while (1) + asm("nop"); + } #else asm volatile("memb"); diff --git a/arch/sw_64/kernel/suspend.c b/arch/sw_64/kernel/suspend.c index 97e5478a678feee93e4cc89fedd28eed0006dae3..955cf41fd8c98a8b3eeb265f777ef6df36c28357 100644 --- a/arch/sw_64/kernel/suspend.c +++ b/arch/sw_64/kernel/suspend.c @@ -38,14 +38,14 @@ void sw64_suspend_enter(void) disable_local_timer(); current_thread_info()->pcb.tp = rtid(); -#ifdef CONFIG_SUBARCH_C3B - sw64_suspend_deep_sleep(&suspend_state); -#else - pme_state = PME_WFW; - sw64_write_csr_imb(PME_EN, CSR_INT_EN); - asm("halt"); - local_irq_disable(); -#endif + if (!is_junzhang_v1()) + sw64_suspend_deep_sleep(&suspend_state); + else { + pme_state = PME_WFW; + sw64_write_csr_imb(PME_EN, CSR_INT_EN); + asm("halt"); + local_irq_disable(); + } wrtp(current_thread_info()->pcb.tp); diff --git a/arch/sw_64/kernel/sys_sw64.c b/arch/sw_64/kernel/sys_sw64.c index 31e6a8d65cf91411054d1c6f00d6a376d01cc791..7efebce4af11e634876f0f90cea3ed0f194d5101 100644 --- a/arch/sw_64/kernel/sys_sw64.c +++ b/arch/sw_64/kernel/sys_sw64.c @@ -154,53 +154,176 @@ SYSCALL_DEFINE0(sw64_pipe) #ifdef CONFIG_SUBARCH_C4 -struct pfh_val { - unsigned long pfh_ctl; - unsigned long pfh_cnt; -}; +static void local_set_pfh_ctl(void *info) +{ + unsigned long *kcsr = info; -static void local_set_pfh(void *info) + sw64_write_csr(*kcsr, CSR_PFH_CTL); +} + +static void local_set_pfh_cnt(void *info) { - struct pfh_val *kbuf = info; + unsigned long *kcsr = info; - if (kbuf->pfh_ctl) - sw64_write_csr(kbuf->pfh_ctl, CSR_PFH_CTL); - if (kbuf->pfh_cnt) - sw64_write_csr(kbuf->pfh_cnt, CSR_PFH_CNT); + sw64_write_csr(*kcsr, CSR_PFH_CNT); } -SYSCALL_DEFINE3(pfh_ops, unsigned long, op, - unsigned long __user *, pfh_ctl_p, - unsigned long __user *, pfh_cnt_p) +enum pfh_field_id { + L1_CCNT, + L1_RCNT, + L1_MCNT, + L2_CCNT, + L2_RCNT, + L2_MCNT, + L2_RAMP, + L3_CCNT, + L3_RCNT, + L3_MCNT, + L3_RAMP, + L1PFH_EN = 0x10, + L2PFH_EN, + L3PFH_EN, + PFH_FIELD_MAX +}; + +struct pfh_field { + unsigned long shift; + unsigned long mask; +}; + +struct pfh_field pfh_fields_c4[PFH_FIELD_MAX] = { + [L1_CCNT] = {0, 0x0f}, + [L1_RCNT] = {4, 0x0f}, + [L1_MCNT] = {8, 0x0f}, + [L2_CCNT] = {12, 0x0f}, + [L2_RCNT] = {16, 0x0f}, + [L2_MCNT] = {20, 0x0f}, + [L2_RAMP] = {24, 0x03}, + [L3_CCNT] = {26, 0x1f}, + [L3_RCNT] = {31, 0x1f}, + [L3_MCNT] = {36, 0x1f}, + [L3_RAMP] = {41, 0x03}, + [L1PFH_EN] = {0, 0x01}, + [L2PFH_EN] = {1, 0x01}, + [L3PFH_EN] = {2, 0x01} +}; + +struct pfh_field pfh_fields_c4b[PFH_FIELD_MAX] = { + [L1_CCNT] = {0, 0x3f}, + [L1_RCNT] = {6, 0x3f}, + [L1_MCNT] = {12, 0x3f}, + [L2_CCNT] = {18, 0x3f}, + [L2_RCNT] = {24, 0x3f}, + [L2_MCNT] = {30, 0x3f}, + [L2_RAMP] = {36, 0x03}, + [L3_CCNT] = {38, 0x7f}, + [L3_RCNT] = {45, 0x7f}, + [L3_MCNT] = {52, 0x7f}, + [L3_RAMP] = {59, 0x03}, + [L1PFH_EN] = {0, 0x01}, + [L2PFH_EN] = {1, 0x01}, + [L3PFH_EN] = {2, 0x01} +}; + +/* + * id: + * 0x00: PFH_CNT: L1_CCNT + * 0x01: PFH_CNT: L1_RCNT + * 0x02: PFH_CNT: L1_MCNT + * 0x03: PFH_CNT: L2_CCNT + * 0x04: PFH_CNT: L2_RCNT + * 0x05: PFH_CNT: L2_MCNT + * 0x06: PFH_CNT: L2_RAMP + * 0x07: PFH_CNT: L3_CCNT + * 0x08: PFH_CNT: L3_RCNT + * 0x09: PFH_CNT: L3_MCNT + * 0x0a: PFH_CNT: L3_RAMP + * 0x10: PFH_CTL: L1PFH_EN + * 0x11: PFH_CTL: L2PFH_EN + * 0x12: PFH_CTL: L3PFH_EN + * op: 0 for get, 1 for set + */ +SYSCALL_DEFINE3(pfh_ops, unsigned long, id, unsigned long, op, + unsigned long __user *, buf) { - struct pfh_val kbuf = {0, 0}; + unsigned long kcsr = 0; + unsigned long kbuf = 0; + unsigned long field_shift; + unsigned long field_mask; + unsigned long csr_idx; long error = 0; + struct pfh_field *pfh_fields_arr; + + if (!is_in_host()) + return -EPERM; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (op) { // op != 0, set - if (pfh_ctl_p) - error |= get_user(kbuf.pfh_ctl, pfh_ctl_p); - if (pfh_cnt_p) - error |= get_user(kbuf.pfh_cnt, pfh_cnt_p); + switch (id & 0xf0) { + case 0x00: + csr_idx = CSR_PFH_CNT; + break; + case 0x10: + csr_idx = CSR_PFH_CTL; + break; + default: + error = -EINVAL; + goto out; + } - if (!error && (kbuf.pfh_ctl || kbuf.pfh_cnt)) { - smp_call_function(local_set_pfh, &kbuf, 1); - local_set_pfh(&kbuf); - } - } else { // op == 0, get - if (pfh_ctl_p) { - kbuf.pfh_ctl = sw64_read_csr(CSR_PFH_CTL); - error |= put_user(kbuf.pfh_ctl, pfh_ctl_p); - } + if (!is_junzhang_v3()) + pfh_fields_arr = pfh_fields_c4; + else + pfh_fields_arr = pfh_fields_c4b; - if (pfh_cnt_p) { - kbuf.pfh_cnt = sw64_read_csr(CSR_PFH_CNT); - error |= put_user(kbuf.pfh_cnt, pfh_cnt_p); - } + field_shift = pfh_fields_arr[id].shift; + field_mask = pfh_fields_arr[id].mask << field_shift; + + switch (csr_idx) { + case CSR_PFH_CTL: + kcsr = sw64_read_csr(CSR_PFH_CTL); + break; + case CSR_PFH_CNT: + kcsr = sw64_read_csr(CSR_PFH_CNT); + break; + default: + /* should never reach here */ + BUG(); + } + + switch (op) { + case 0: // get + kbuf = (kcsr & field_mask) >> field_shift; + error = put_user(kbuf, buf); + goto out; + case 1: // set + error = get_user(kbuf, buf); + if (error) + goto out; + kcsr = (kcsr & (~field_mask)) | + ((kbuf << field_shift) & field_mask); + break; + default: + error = -EINVAL; + goto out; + } + + switch (csr_idx) { + case CSR_PFH_CTL: + smp_call_function(local_set_pfh_ctl, &kcsr, 1); + local_set_pfh_ctl(&kcsr); + break; + case CSR_PFH_CNT: + smp_call_function(local_set_pfh_cnt, &kcsr, 1); + local_set_pfh_cnt(&kcsr); + break; + default: + /* should never reach here */ + BUG(); } +out: return error; } diff --git a/arch/sw_64/kernel/syscalls/syscall.tbl b/arch/sw_64/kernel/syscalls/syscall.tbl index 3acd8b5ea7dbd2e992f87f5f13bd84259fbd0dc7..fe75af3652e322bbe5d86dbc07142214f7e68ae1 100644 --- a/arch/sw_64/kernel/syscalls/syscall.tbl +++ b/arch/sw_64/kernel/syscalls/syscall.tbl @@ -116,8 +116,8 @@ 106 common listen sys_listen #107 is unused #108 is unused -#109 is unused -110 common pfh_ops sys_pfh_ops +109 common pfh_ops sys_pfh_ops +110 common old_pfh_ops sys_ni_syscall 111 common sigsuspend sys_sigsuspend #112 is unused 113 common recvmsg sys_recvmsg diff --git a/arch/sw_64/kernel/time.c b/arch/sw_64/kernel/time.c index 533a6a14c20051da05469ed5bd1bf0d824c8c85d..503f9e1beb4399f353851d9912594c4352b4594d 100644 --- a/arch/sw_64/kernel/time.c +++ b/arch/sw_64/kernel/time.c @@ -5,8 +5,10 @@ #include #include +#include #include #include +#include #include "proto.h" @@ -24,26 +26,6 @@ EXPORT_SYMBOL(rtc_lock); unsigned long est_cycle_freq; -#ifdef CONFIG_IRQ_WORK - -DEFINE_PER_CPU(u8, irq_work_pending); - -#define set_irq_work_pending_flag() __this_cpu_write(irq_work_pending, 1) -#define test_irq_work_pending() __this_cpu_read(irq_work_pending) -#define clear_irq_work_pending() __this_cpu_write(irq_work_pending, 0) - -void arch_irq_work_raise(void) -{ - set_irq_work_pending_flag(); -} - -#else /* CONFIG_IRQ_WORK */ - -#define test_irq_work_pending() 0 -#define clear_irq_work_pending() - -#endif /* CONFIG_IRQ_WORK */ - void __init time_init(void) { @@ -61,3 +43,8 @@ time_init(void) /* Calibrate the delay loop directly */ lpj_fine = cycle_freq / HZ; } + +void clocksource_arch_init(struct clocksource *cs) +{ + cs->vdso_clock_mode = VDSO_CLOCKMODE_ARCHTIMER; +} diff --git a/arch/sw_64/kernel/topology.c b/arch/sw_64/kernel/topology.c index b00f083517c3130058b8a8376dbe2a086c7eb2bd..2758b563b119c4062e89a923995caf9c930d1a16 100644 --- a/arch/sw_64/kernel/topology.c +++ b/arch/sw_64/kernel/topology.c @@ -3,22 +3,14 @@ #include #include #include +#include +#include + #include #include #define OFFSET_SMP_INFO 0x80UL -static int __init parse_dt_topology(void) -{ - return 0; -} - -/* - * cpu topology table - */ -struct cpu_topology cpu_topology[NR_CPUS]; -EXPORT_SYMBOL_GPL(cpu_topology); - int topo_nr_threads, topo_nr_cores, topo_nr_maxcpus; static int topo_nr_cpus; @@ -91,126 +83,312 @@ static void __init init_topology_array(void) init_topo_packages(); } -const struct cpumask *cpu_coregroup_mask(int cpu) +/* + * This function returns the logic cpu number of the node. + * There are basically three kinds of return values: + * (1) logic cpu number which is > 0. + * (2) -ENODEV when the device tree(DT) node is valid and found in the DT but + * there is no possible logical CPU in the kernel to match. This happens + * when CONFIG_NR_CPUS is configure to be smaller than the number of + * CPU nodes in DT. We need to just ignore this case. + * (3) -1 if the node does not exist in the device tree + */ +static int __init get_cpu_for_node(struct device_node *node) { - return topology_llc_cpumask(cpu); -} + struct device_node *cpu_node; + int cpu; -static void update_siblings_masks(int cpu) -{ - struct cpu_topology *cpu_topo = &cpu_topology[cpu]; - int sib; + cpu_node = of_parse_phandle(node, "cpu", 0); + if (!cpu_node) + return -1; - /* update core and thread sibling masks */ - for_each_online_cpu(sib) { - struct cpu_topology *sib_topo = &cpu_topology[sib]; + cpu = of_cpu_node_to_id(cpu_node); + if (cpu >= 0) + topology_parse_cpu_capacity(cpu_node, cpu); + else + pr_info("CPU node for %pOF exist but the possible cpu range is :%*pbl\n", + cpu_node, cpumask_pr_args(cpu_possible_mask)); - if (cpu_topo->package_id == sib_topo->package_id) { - cpumask_set_cpu(cpu, &sib_topo->core_sibling); - cpumask_set_cpu(sib, &cpu_topo->core_sibling); - cpumask_set_cpu(cpu, &sib_topo->llc_sibling); - cpumask_set_cpu(sib, &cpu_topo->llc_sibling); + of_node_put(cpu_node); + return cpu; +} - if (cpu_topo->core_id == sib_topo->core_id) { - cpumask_set_cpu(cpu, &sib_topo->thread_sibling); - cpumask_set_cpu(sib, &cpu_topo->thread_sibling); +static int __init parse_core(struct device_node *core, int package_id, + int cluster_id, int core_id) +{ + char name[20]; + bool leaf = true; + int i = 0; + int cpu; + struct device_node *t; + + do { + snprintf(name, sizeof(name), "thread%d", i); + t = of_get_child_by_name(core, name); + if (t) { + leaf = false; + cpu = get_cpu_for_node(t); + if (cpu >= 0) { + cpu_topology[cpu].package_id = package_id; + cpu_topology[cpu].cluster_id = cluster_id; + cpu_topology[cpu].core_id = core_id; + cpu_topology[cpu].thread_id = i; + } else if (cpu != -ENODEV) { + pr_err("%pOF: Can't get CPU for thread\n", t); + of_node_put(t); + return -EINVAL; } + of_node_put(t); + } + i++; + } while (t); + + cpu = get_cpu_for_node(core); + if (cpu >= 0) { + if (!leaf) { + pr_err("%pOF: Core has both threads and CPU\n", + core); + return -EINVAL; } + + cpu_topology[cpu].package_id = package_id; + cpu_topology[cpu].cluster_id = cluster_id; + cpu_topology[cpu].core_id = core_id; + } else if (leaf && cpu != -ENODEV) { + pr_err("%pOF: Can't get CPU for leaf core\n", core); + return -EINVAL; } + + return 0; } -void store_cpu_topology(int cpu) +static int __init parse_cluster(struct device_node *cluster, int package_id, + int cluster_id, int depth) { - struct cpu_topology *cpu_topo = &cpu_topology[cpu]; + char name[20]; + bool leaf = true; + bool has_cores = false; + struct device_node *c; + int core_id = 0; + int i, ret; - if (cpu_topo->package_id != -1) - goto topology_populated; + /* + * First check for child clusters; we currently ignore any + * information about the nesting of clusters and present the + * scheduler with a flat list of them. + */ + i = 0; + do { + snprintf(name, sizeof(name), "cluster%d", i); + c = of_get_child_by_name(cluster, name); + if (c) { + leaf = false; + ret = parse_cluster(c, package_id, i, depth + 1); + if (depth > 0) + pr_warn("Topology for clusters of clusters not yet supported\n"); + of_node_put(c); + if (ret != 0) + return ret; + } + i++; + } while (c); + + /* Now check for cores */ + i = 0; + do { + snprintf(name, sizeof(name), "core%d", i); + c = of_get_child_by_name(cluster, name); + if (c) { + has_cores = true; + + if (depth == 0) { + pr_err("%pOF: cpu-map children should be clusters\n", + c); + of_node_put(c); + return -EINVAL; + } - if (is_guest_or_emul()) { - cpu_topo->package_id = topo_packages[cpu]; - cpu_topo->core_id = topo_cores[cpu]; - cpu_topo->thread_id = topo_threads[cpu]; - goto topology_populated; - } + if (leaf) { + ret = parse_core(c, package_id, cluster_id, + core_id++); + } else { + pr_err("%pOF: Non-leaf cluster with core %s\n", + cluster, name); + ret = -EINVAL; + } - cpu_topo->package_id = rcid_to_domain_id(cpu_to_rcid(cpu)); - cpu_topo->core_id = rcid_to_core_id(cpu_to_rcid(cpu)); - cpu_topo->thread_id = rcid_to_thread_id(cpu_to_rcid(cpu)); + of_node_put(c); + if (ret != 0) + return ret; + } + i++; + } while (c); - pr_debug("CPU%u: socket %d core %d thread %d\n", - cpu, cpu_topo->package_id, cpu_topo->core_id, - cpu_topo->thread_id); + if (leaf && !has_cores) + pr_warn("%pOF: empty cluster\n", cluster); -topology_populated: - update_siblings_masks(cpu); + return 0; } -static void clear_cpu_topology(int cpu) +static int __init parse_socket(struct device_node *socket) { - struct cpu_topology *cpu_topo = &cpu_topology[cpu]; + char name[20]; + struct device_node *c; + bool has_socket = false; + int package_id = 0, ret; + + do { + snprintf(name, sizeof(name), "socket%d", package_id); + c = of_get_child_by_name(socket, name); + if (c) { + has_socket = true; + ret = parse_cluster(c, package_id, -1, 0); + of_node_put(c); + if (ret != 0) + return ret; + } + package_id++; + } while (c); - cpumask_clear(&cpu_topo->llc_sibling); - cpumask_set_cpu(cpu, &cpu_topo->llc_sibling); + if (!has_socket) + ret = parse_cluster(socket, 0, -1, 0); - cpumask_clear(&cpu_topo->core_sibling); - cpumask_set_cpu(cpu, &cpu_topo->core_sibling); - cpumask_clear(&cpu_topo->thread_sibling); - cpumask_set_cpu(cpu, &cpu_topo->thread_sibling); + return ret; } -static void __init reset_cpu_topology(void) +static int __init parse_dt_topology(void) { + struct device_node *cn, *map; + int ret = 0; int cpu; - for_each_possible_cpu(cpu) { - struct cpu_topology *cpu_topo = &cpu_topology[cpu]; + cn = of_find_node_by_path("/cpus"); + if (!cn) { + pr_err("No CPU information found in DT\n"); + return 0; + } - cpu_topo->thread_id = -1; - cpu_topo->core_id = 0; - cpu_topo->package_id = -1; + /* + * When topology is provided cpu-map is essentially a root + * cluster with restricted subnodes. + */ + map = of_get_child_by_name(cn, "cpu-map"); + if (!map) + goto out; - clear_cpu_topology(cpu); - } -} + ret = parse_socket(map); + if (ret != 0) + goto out_map; -void remove_cpu_topology(int cpu) -{ - int sibling; + topology_normalize_cpu_scale(); - for_each_cpu(sibling, topology_core_cpumask(cpu)) - cpumask_clear_cpu(cpu, topology_core_cpumask(sibling)); - for_each_cpu(sibling, topology_sibling_cpumask(cpu)) - cpumask_clear_cpu(cpu, topology_sibling_cpumask(sibling)); - for_each_cpu(sibling, topology_llc_cpumask(cpu)) - cpumask_clear_cpu(cpu, topology_llc_cpumask(sibling)); + /* + * Check that all cores are in the topology; the SMP code will + * only mark cores described in the DT as possible. + */ + for_each_possible_cpu(cpu) + if (cpu_topology[cpu].package_id < 0) { + ret = -EINVAL; + break; + } - clear_cpu_topology(cpu); +out_map: + of_node_put(map); +out: + of_node_put(cn); + return ret; } #ifdef CONFIG_ACPI -static int __init parse_acpi_topology(void) +/* + * Propagate the topology information of the processor_topology_node tree to the + * cpu_topology array. + */ +int __init parse_acpi_topology(void) { + int cpu, topology_id; + + if (acpi_disabled) + return 0; + + for_each_possible_cpu(cpu) { + topology_id = find_acpi_cpu_topology(cpu, 0); + if (topology_id < 0) + return topology_id; + + if (acpi_pptt_cpu_is_thread(cpu) == 1) { + cpu_topology[cpu].thread_id = topology_id; + topology_id = find_acpi_cpu_topology(cpu, 1); + cpu_topology[cpu].core_id = topology_id; + } else { + cpu_topology[cpu].thread_id = -1; + cpu_topology[cpu].core_id = topology_id; + } + topology_id = find_acpi_cpu_topology_cluster(cpu); + cpu_topology[cpu].cluster_id = topology_id; + topology_id = find_acpi_cpu_topology_package(cpu); + cpu_topology[cpu].package_id = topology_id; + } + return 0; } -#else -static inline int __init parse_acpi_topology(void) -{ - return -EINVAL; -} #endif void __init init_cpu_topology(void) { + struct cpu_topology *boot_cpu_topo = &cpu_topology[0]; + int cpu, ret; + reset_cpu_topology(); + ret = parse_acpi_topology(); + if (!ret) + ret = of_have_populated_dt() && parse_dt_topology(); + + if (ret) { + /* + * Discard anything that was parsed if we hit an error so we + * don't use partial information. But do not return yet to give + * arch-specific early cache level detection a chance to run. + */ + reset_cpu_topology(); + } - if (is_guest_or_emul()) + /* Backward compatibility */ + if (is_guest_or_emul() && (boot_cpu_topo->package_id == -1)) init_topology_array(); - /* - * Discard anything that was parsed if we hit an error so we - * don't use partial information. - */ - if (!acpi_disabled && parse_acpi_topology()) - reset_cpu_topology(); - else if (of_have_populated_dt() && parse_dt_topology()) - reset_cpu_topology(); + + for_each_possible_cpu(cpu) { + ret = fetch_cache_info(cpu); + if (!ret) + continue; + else if (ret != -ENOENT) + pr_err("Early cacheinfo failed, ret = %d\n", ret); + return; + } +} + +void store_cpu_topology(unsigned int cpu) +{ + struct cpu_topology *cpu_topo = &cpu_topology[cpu]; + + if (cpu_topo->package_id != -1) + goto topology_populated; + + if (is_guest_or_emul()) { + cpu_topo->package_id = topo_packages[cpu]; + cpu_topo->core_id = topo_cores[cpu]; + cpu_topo->thread_id = topo_threads[cpu]; + goto topology_populated; + } + + cpu_topo->package_id = rcid_to_domain_id(cpu_to_rcid(cpu)); + cpu_topo->core_id = rcid_to_core_id(cpu_to_rcid(cpu)); + cpu_topo->thread_id = rcid_to_thread_id(cpu_to_rcid(cpu)); + + pr_debug("CPU%u: socket %d core %d thread %d\n", + cpu, cpu_topo->package_id, cpu_topo->core_id, + cpu_topo->thread_id); + +topology_populated: + update_siblings_masks(cpu); } diff --git a/arch/sw_64/kernel/traps.c b/arch/sw_64/kernel/traps.c index e54db9a41be6c8e6b4a6989a0b64fd016941c572..9a9b43c13286a80b9986576209dc0ff836088f72 100644 --- a/arch/sw_64/kernel/traps.c +++ b/arch/sw_64/kernel/traps.c @@ -386,22 +386,573 @@ do_entIF(unsigned long inst_type, unsigned long va, struct pt_regs *regs) force_sig_fault(SIGILL, ILL_ILLOPC, (void __user *)regs->pc); } +#define OP_INT_MASK (1L << 0x22 | 1L << 0x2a | /* ldw stw */ \ + 1L << 0x23 | 1L << 0x2b | /* ldl stl */ \ + 1L << 0x21 | 1L << 0x29 | /* ldhu sth */ \ + 1L << 0x20 | 1L << 0x28) /* ldbu stb */ + +#define FN_INT_MASK (1L << 0x0 | 1L << 0x6 | /* ldbu_a stb_a */ \ + 1L << 0x1 | 1L << 0x7 | /* ldhu_a sth_a */ \ + 1L << 0x2 | 1L << 0x8 | /* ldw_a stw_a */ \ + 1L << 0x3 | 1L << 0x9) /* ldl_a stl_a */ + asmlinkage void do_entUna(void *va, unsigned long opcode, unsigned long reg, struct pt_regs *regs) { long error, disp; unsigned int insn, fncode, rb; - unsigned long tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8; + unsigned long tmp, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, vb; + unsigned long fp[4]; + unsigned long fake_reg, *reg_addr = &fake_reg; unsigned long pc = regs->pc - 4; - /* - * We don't want to use the generic get/put unaligned macros as - * we want to trap exceptions. Only if we actually get an - * exception will we decide whether we should have caught it. - */ + insn = *(unsigned int *)pc; + fncode = (insn >> 12) & 0xf; + + if (((1L << opcode) & OP_INT_MASK) || + ((opcode == 0x1e) && ((1L << fncode) & FN_INT_MASK))) { + /* it's an integer load/store */ + if (reg < 31) { + reg_addr = ®s->regs[reg]; + } else { + /* zero "register" */ + fake_reg = 0; + } + } + + /* + * We don't want to use the generic get/put unaligned macros as + * we want to trap exceptions. Only if we actually get an + * exception will we decide whether we should have caught it. + */ + + switch (opcode) { + + case 0x0c: /* vlds */ + if ((unsigned long)va<<61 == 0) { + __asm__ __volatile__( + "1: ldl %1, 0(%5)\n" + "2: ldl %2, 8(%5)\n" + "3:\n" + ".section __ex_table, \"a\"\n" + " .long 1b - .\n" + " ldi %1, 3b-1b(%0)\n" + " .long 2b - .\n" + " ldi %2, 3b-2b(%0)\n" + ".previous" + : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), "=&r"(tmp4) + : "r"(va), "0"(0)); + + if (error) + goto got_exception; + + sw64_write_simd_fp_reg_s(reg, tmp1, tmp2); + + return; + } else { + __asm__ __volatile__( + "1: ldl_u %1, 0(%6)\n" + "2: ldl_u %2, 7(%6)\n" + "3: ldl_u %3, 15(%6)\n" + " extll %1, %6, %1\n" + " extll %2, %6, %5\n" + " exthl %2, %6, %4\n" + " exthl %3, %6, %3\n" + "4:\n" + ".section __ex_table, \"a\"\n" + " .long 1b - .\n" + " ldi %1, 4b-1b(%0)\n" + " .long 2b - .\n" + " ldi %2, 4b-2b(%0)\n" + " .long 3b - .\n" + " ldi %3, 4b-3b(%0)\n" + ".previous" + : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), + "=&r"(tmp4), "=&r"(tmp5) + : "r"(va), "0"(0)); + + if (error) + goto got_exception; + + tmp1 = tmp1 | tmp4; + tmp2 = tmp5 | tmp3; + + sw64_write_simd_fp_reg_s(reg, tmp1, tmp2); + + return; + } + + case 0x0d: /* vldd */ + if ((unsigned long)va<<61 == 0) { + __asm__ __volatile__( + "1: ldl %1, 0(%5)\n" + "2: ldl %2, 8(%5)\n" + "3: ldl %3, 16(%5)\n" + "4: ldl %4, 24(%5)\n" + "5:\n" + ".section __ex_table, \"a\"\n" + " .long 1b - .\n" + " ldi %1, 5b-1b(%0)\n" + " .long 2b - .\n" + " ldi %2, 5b-2b(%0)\n" + " .long 3b - .\n" + " ldi %3, 5b-3b(%0)\n" + " .long 4b - .\n" + " ldi %4, 5b-4b(%0)\n" + ".previous" + : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), "=&r"(tmp4) + : "r"(va), "0"(0)); + + if (error) + goto got_exception; + + sw64_write_simd_fp_reg_d(reg, tmp1, tmp2, tmp3, tmp4); + + return; + } else { + __asm__ __volatile__( + "1: ldl_u %1, 0(%6)\n" + "2: ldl_u %2, 7(%6)\n" + "3: ldl_u %3, 15(%6)\n" + " extll %1, %6, %1\n" + " extll %2, %6, %5\n" + " exthl %2, %6, %4\n" + " exthl %3, %6, %3\n" + "4:\n" + ".section __ex_table, \"a\"\n" + " .long 1b - .\n" + " ldi %1, 4b-1b(%0)\n" + " .long 2b - .\n" + " ldi %2, 4b-2b(%0)\n" + " .long 3b - .\n" + " ldi %3, 4b-3b(%0)\n" + ".previous" + : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), + "=&r"(tmp4), "=&r"(tmp5) + : "r"(va), "0"(0)); + + if (error) + goto got_exception; + + tmp7 = tmp1 | tmp4; //f0 + tmp8 = tmp5 | tmp3; //f1 + + vb = ((unsigned long)(va))+16; + + __asm__ __volatile__( + "1: ldl_u %1, 0(%6)\n" + "2: ldl_u %2, 7(%6)\n" + "3: ldl_u %3, 15(%6)\n" + " extll %1, %6, %1\n" + " extll %2, %6, %5\n" + " exthl %2, %6, %4\n" + " exthl %3, %6, %3\n" + "4:\n" + ".section __ex_table, \"a\"\n" + " .long 1b - .\n" + " ldi %1, 4b-1b(%0)\n" + " .long 2b - .\n" + " ldi %2, 4b-2b(%0)\n" + " .long 3b - .\n" + " ldi %3, 4b-3b(%0)\n" + ".previous" + : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), + "=&r"(tmp4), "=&r"(tmp5) + : "r"(vb), "0"(0)); + + if (error) + goto got_exception; + + tmp = tmp1 | tmp4; // f2 + tmp2 = tmp5 | tmp3; // f3 + + sw64_write_simd_fp_reg_d(reg, tmp7, tmp8, tmp, tmp2); + return; + } + + case 0x0e: /* vsts */ + sw64_read_simd_fp_m_s(reg, fp); + if ((unsigned long)va<<61 == 0) { + __asm__ __volatile__( + " bis %4, %4, %1\n" + " bis %5, %5, %2\n" + "1: stl %1, 0(%3)\n" + "2: stl %2, 8(%3)\n" + "3:\n" + ".section __ex_table, \"a\"\n\t" + " .long 1b - .\n" + " ldi $31, 3b-1b(%0)\n" + " .long 2b - .\n" + " ldi $31, 3b-2b(%0)\n" + ".previous" + : "=r"(error), "=&r"(tmp1), "=&r"(tmp2) + : "r"(va), "r"(fp[0]), "r"(fp[1]), "0"(0)); + + if (error) + goto got_exception; + + return; + } else { + __asm__ __volatile__( + " zapnot %10, 0x1, %1\n" + " srl %10, 8, %2\n" + " zapnot %2, 0x1, %2\n" + " srl %10, 16, %3\n" + " zapnot %3, 0x1, %3\n" + " srl %10, 24, %4\n" + " zapnot %4, 0x1, %4\n" + " srl %10, 32, %5\n" + " zapnot %5, 0x1, %5\n" + " srl %10, 40, %6\n" + " zapnot %6, 0x1, %6\n" + " srl %10, 48, %7\n" + " zapnot %7, 0x1, %7\n" + " srl %10, 56, %8\n" + " zapnot %8, 0x1, %8\n" + "1: stb %1, 0(%9)\n" + "2: stb %2, 1(%9)\n" + "3: stb %3, 2(%9)\n" + "4: stb %4, 3(%9)\n" + "5: stb %5, 4(%9)\n" + "6: stb %6, 5(%9)\n" + "7: stb %7, 6(%9)\n" + "8: stb %8, 7(%9)\n" + "9:\n" + ".section __ex_table, \"a\"\n\t" + " .long 1b - .\n" + " ldi $31, 9b-1b(%0)\n" + " .long 2b - .\n" + " ldi $31, 9b-2b(%0)\n" + " .long 3b - .\n" + " ldi $31, 9b-3b(%0)\n" + " .long 4b - .\n" + " ldi $31, 9b-4b(%0)\n" + " .long 5b - .\n" + " ldi $31, 9b-5b(%0)\n" + " .long 6b - .\n" + " ldi $31, 9b-6b(%0)\n" + " .long 7b - .\n" + " ldi $31, 9b-7b(%0)\n" + " .long 8b - .\n" + " ldi $31, 9b-8b(%0)\n" + ".previous" + : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), + "=&r"(tmp4), "=&r"(tmp5), "=&r"(tmp6), "=&r"(tmp7), "=&r"(tmp8) + : "r"(va), "r"(fp[0]), "0"(0)); + + if (error) + goto got_exception; + + + vb = ((unsigned long)va) + 8; + + __asm__ __volatile__( + " zapnot %10, 0x1, %1\n" + " srl %10, 8, %2\n" + " zapnot %2, 0x1, %2\n" + " srl %10, 16, %3\n" + " zapnot %3, 0x1, %3\n" + " srl %10, 24, %4\n" + " zapnot %4, 0x1, %4\n" + " srl %10, 32, %5\n" + " zapnot %5, 0x1, %5\n" + " srl %10, 40, %6\n" + " zapnot %6, 0x1, %6\n" + " srl %10, 48, %7\n" + " zapnot %7, 0x1, %7\n" + " srl %10, 56, %8\n" + " zapnot %8, 0x1, %8\n" + "1: stb %1, 0(%9)\n" + "2: stb %2, 1(%9)\n" + "3: stb %3, 2(%9)\n" + "4: stb %4, 3(%9)\n" + "5: stb %5, 4(%9)\n" + "6: stb %6, 5(%9)\n" + "7: stb %7, 6(%9)\n" + "8: stb %8, 7(%9)\n" + "9:\n" + ".section __ex_table, \"a\"\n\t" + " .long 1b - .\n" + " ldi $31, 9b-1b(%0)\n" + " .long 2b - .\n" + " ldi $31, 9b-2b(%0)\n" + " .long 3b - .\n" + " ldi $31, 9b-3b(%0)\n" + " .long 4b - .\n" + " ldi $31, 9b-4b(%0)\n" + " .long 5b - .\n" + " ldi $31, 9b-5b(%0)\n" + " .long 6b - .\n" + " ldi $31, 9b-6b(%0)\n" + " .long 7b - .\n" + " ldi $31, 9b-7b(%0)\n" + " .long 8b - .\n" + " ldi $31, 9b-8b(%0)\n" + ".previous" + : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), + "=&r"(tmp4), "=&r"(tmp5), "=&r"(tmp6), "=&r"(tmp7), "=&r"(tmp8) + : "r"(vb), "r"(fp[1]), "0"(0)); + + if (error) + goto got_exception; + + return; + } + + case 0x0f: /* vstd */ + sw64_read_simd_fp_m_d(reg, fp); + if ((unsigned long)va<<61 == 0) { + __asm__ __volatile__( + " bis %4, %4, %1\n" + " bis %5, %5, %2\n" + "1: stl %1, 0(%3)\n" + "2: stl %2, 8(%3)\n" + "3:\n" + ".section __ex_table, \"a\"\n\t" + " .long 1b - .\n" + " ldi $31, 3b-1b(%0)\n" + " .long 2b - .\n" + " ldi $31, 3b-2b(%0)\n" + ".previous" + : "=r"(error), "=&r"(tmp1), "=&r"(tmp2) + : "r"(va), "r"(fp[0]), "r"(fp[1]), "0"(0)); + + if (error) + goto got_exception; + + vb = ((unsigned long)va)+16; + + + __asm__ __volatile__( + " bis %4, %4, %1\n" + " bis %5, %5, %2\n" + "1: stl %1, 0(%3)\n" + "2: stl %2, 8(%3)\n" + "3:\n" + ".section __ex_table, \"a\"\n\t" + " .long 1b - .\n" + " ldi $31, 3b-1b(%0)\n" + " .long 2b - .\n" + " ldi $31, 3b-2b(%0)\n" + ".previous" + : "=r"(error), "=&r"(tmp1), "=&r"(tmp2) + : "r"(vb), "r"(fp[2]), "r"(fp[3]), "0"(0)); + + if (error) + goto got_exception; + + return; + } else { + __asm__ __volatile__( + " zapnot %10, 0x1, %1\n" + " srl %10, 8, %2\n" + " zapnot %2, 0x1, %2\n" + " srl %10, 16, %3\n" + " zapnot %3, 0x1, %3\n" + " srl %10, 24, %4\n" + " zapnot %4, 0x1, %4\n" + " srl %10, 32, %5\n" + " zapnot %5, 0x1, %5\n" + " srl %10, 40, %6\n" + " zapnot %6, 0x1, %6\n" + " srl %10, 48, %7\n" + " zapnot %7, 0x1, %7\n" + " srl %10, 56, %8\n" + " zapnot %8, 0x1, %8\n" + "1: stb %1, 0(%9)\n" + "2: stb %2, 1(%9)\n" + "3: stb %3, 2(%9)\n" + "4: stb %4, 3(%9)\n" + "5: stb %5, 4(%9)\n" + "6: stb %6, 5(%9)\n" + "7: stb %7, 6(%9)\n" + "8: stb %8, 7(%9)\n" + "9:\n" + ".section __ex_table, \"a\"\n\t" + " .long 1b - .\n" + " ldi $31, 9b-1b(%0)\n" + " .long 2b - .\n" + " ldi $31, 9b-2b(%0)\n" + " .long 3b - .\n" + " ldi $31, 9b-3b(%0)\n" + " .long 4b - .\n" + " ldi $31, 9b-4b(%0)\n" + " .long 5b - .\n" + " ldi $31, 9b-5b(%0)\n" + " .long 6b - .\n" + " ldi $31, 9b-6b(%0)\n" + " .long 7b - .\n" + " ldi $31, 9b-7b(%0)\n" + " .long 8b - .\n" + " ldi $31, 9b-8b(%0)\n" + ".previous" + : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), + "=&r"(tmp4), "=&r"(tmp5), "=&r"(tmp6), "=&r"(tmp7), "=&r"(tmp8) + : "r"(va), "r"(fp[0]), "0"(0)); + + if (error) + goto got_exception; + + vb = ((unsigned long)va) + 8; + + __asm__ __volatile__( + " zapnot %10, 0x1, %1\n" + " srl %10, 8, %2\n" + " zapnot %2, 0x1, %2\n" + " srl %10, 16, %3\n" + " zapnot %3, 0x1, %3\n" + " srl %10, 24, %4\n" + " zapnot %4, 0x1, %4\n" + " srl %10, 32, %5\n" + " zapnot %5, 0x1, %5\n" + " srl %10, 40, %6\n" + " zapnot %6, 0x1, %6\n" + " srl %10, 48, %7\n" + " zapnot %7, 0x1, %7\n" + " srl %10, 56, %8\n" + " zapnot %8, 0x1, %8\n" + "1: stb %1, 0(%9)\n" + "2: stb %2, 1(%9)\n" + "3: stb %3, 2(%9)\n" + "4: stb %4, 3(%9)\n" + "5: stb %5, 4(%9)\n" + "6: stb %6, 5(%9)\n" + "7: stb %7, 6(%9)\n" + "8: stb %8, 7(%9)\n" + "9:\n" + ".section __ex_table, \"a\"\n\t" + " .long 1b - .\n" + " ldi $31, 9b-1b(%0)\n" + " .long 2b - .\n" + " ldi $31, 9b-2b(%0)\n" + " .long 3b - .\n" + " ldi $31, 9b-3b(%0)\n" + " .long 4b - .\n" + " ldi $31, 9b-4b(%0)\n" + " .long 5b - .\n" + " ldi $31, 9b-5b(%0)\n" + " .long 6b - .\n" + " ldi $31, 9b-6b(%0)\n" + " .long 7b - .\n" + " ldi $31, 9b-7b(%0)\n" + " .long 8b - .\n" + " ldi $31, 9b-8b(%0)\n" + ".previous" + : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), + "=&r"(tmp4), "=&r"(tmp5), "=&r"(tmp6), "=&r"(tmp7), "=&r"(tmp8) + : "r"(vb), "r"(fp[1]), "0"(0)); + + if (error) + goto got_exception; + + vb = vb + 8; + + __asm__ __volatile__( + " zapnot %10, 0x1, %1\n" + " srl %10, 8, %2\n" + " zapnot %2, 0x1, %2\n" + " srl %10, 16, %3\n" + " zapnot %3, 0x1, %3\n" + " srl %10, 24, %4\n" + " zapnot %4, 0x1, %4\n" + " srl %10, 32, %5\n" + " zapnot %5, 0x1, %5\n" + " srl %10, 40, %6\n" + " zapnot %6, 0x1, %6\n" + " srl %10, 48, %7\n" + " zapnot %7, 0x1, %7\n" + " srl %10, 56, %8\n" + " zapnot %8, 0x1, %8\n" + "1: stb %1, 0(%9)\n" + "2: stb %2, 1(%9)\n" + "3: stb %3, 2(%9)\n" + "4: stb %4, 3(%9)\n" + "5: stb %5, 4(%9)\n" + "6: stb %6, 5(%9)\n" + "7: stb %7, 6(%9)\n" + "8: stb %8, 7(%9)\n" + "9:\n" + ".section __ex_table, \"a\"\n\t" + " .long 1b - .\n" + " ldi $31, 9b-1b(%0)\n" + " .long 2b - .\n" + " ldi $31, 9b-2b(%0)\n" + " .long 3b - .\n" + " ldi $31, 9b-3b(%0)\n" + " .long 4b - .\n" + " ldi $31, 9b-4b(%0)\n" + " .long 5b - .\n" + " ldi $31, 9b-5b(%0)\n" + " .long 6b - .\n" + " ldi $31, 9b-6b(%0)\n" + " .long 7b - .\n" + " ldi $31, 9b-7b(%0)\n" + " .long 8b - .\n" + " ldi $31, 9b-8b(%0)\n" + ".previous" + : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), + "=&r"(tmp4), "=&r"(tmp5), "=&r"(tmp6), "=&r"(tmp7), "=&r"(tmp8) + : "r"(vb), "r"(fp[2]), "0"(0)); + + if (error) + goto got_exception; + + vb = vb + 8; + + __asm__ __volatile__( + " zapnot %10, 0x1, %1\n" + " srl %10, 8, %2\n" + " zapnot %2, 0x1, %2\n" + " srl %10, 16, %3\n" + " zapnot %3, 0x1, %3\n" + " srl %10, 24, %4\n" + " zapnot %4, 0x1, %4\n" + " srl %10, 32, %5\n" + " zapnot %5, 0x1, %5\n" + " srl %10, 40, %6\n" + " zapnot %6, 0x1, %6\n" + " srl %10, 48, %7\n" + " zapnot %7, 0x1, %7\n" + " srl %10, 56, %8\n" + " zapnot %8, 0x1, %8\n" + "1: stb %1, 0(%9)\n" + "2: stb %2, 1(%9)\n" + "3: stb %3, 2(%9)\n" + "4: stb %4, 3(%9)\n" + "5: stb %5, 4(%9)\n" + "6: stb %6, 5(%9)\n" + "7: stb %7, 6(%9)\n" + "8: stb %8, 7(%9)\n" + "9:\n" + ".section __ex_table, \"a\"\n\t" + " .long 1b - .\n" + " ldi $31, 9b-1b(%0)\n" + " .long 2b - .\n" + " ldi $31, 9b-2b(%0)\n" + " .long 3b - .\n" + " ldi $31, 9b-3b(%0)\n" + " .long 4b - .\n" + " ldi $31, 9b-4b(%0)\n" + " .long 5b - .\n" + " ldi $31, 9b-5b(%0)\n" + " .long 6b - .\n" + " ldi $31, 9b-6b(%0)\n" + " .long 7b - .\n" + " ldi $31, 9b-7b(%0)\n" + " .long 8b - .\n" + " ldi $31, 9b-8b(%0)\n" + ".previous" + : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), + "=&r"(tmp4), "=&r"(tmp5), "=&r"(tmp6), "=&r"(tmp7), "=&r"(tmp8) + : "r"(vb), "r"(fp[3]), "0"(0)); + + if (error) + goto got_exception; + + return; + } - switch (opcode) { case 0x1e: insn = *(unsigned int *)pc; fncode = (insn >> 12) & 0xf; @@ -491,7 +1042,7 @@ do_entUna(void *va, unsigned long opcode, unsigned long reg, ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), "=&r"(tmp4) - : "r"(va), "r"(regs->regs[reg]), "0"(0)); + : "r"(va), "r"(*reg_addr), "0"(0)); if (error) goto got_exception; @@ -524,7 +1075,7 @@ do_entUna(void *va, unsigned long opcode, unsigned long reg, ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), "=&r"(tmp4) - : "r"(va), "r"(regs->regs[reg]), "0"(0)); + : "r"(va), "r"(*reg_addr), "0"(0)); if (error) goto got_exception; @@ -577,7 +1128,7 @@ do_entUna(void *va, unsigned long opcode, unsigned long reg, ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), "=&r"(tmp4), "=&r"(tmp5), "=&r"(tmp6), "=&r"(tmp7), "=&r"(tmp8) - : "r"(va), "r"(regs->regs[reg]), "0"(0)); + : "r"(va), "r"(*reg_addr), "0"(0)); if (error) goto got_exception; @@ -664,7 +1215,7 @@ do_entUna(void *va, unsigned long opcode, unsigned long reg, ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), "=&r"(tmp4) - : "r"(va), "r"(regs->regs[reg]), "0"(0)); + : "r"(va), "r"(*reg_addr), "0"(0)); if (error) goto got_exception; @@ -696,7 +1247,7 @@ do_entUna(void *va, unsigned long opcode, unsigned long reg, ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), "=&r"(tmp4) - : "r"(va), "r"(regs->regs[reg]), "0"(0)); + : "r"(va), "r"(*reg_addr), "0"(0)); if (error) goto got_exception; @@ -748,7 +1299,7 @@ do_entUna(void *va, unsigned long opcode, unsigned long reg, ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), "=&r"(tmp4), "=&r"(tmp5), "=&r"(tmp6), "=&r"(tmp7), "=&r"(tmp8) - : "r"(va), "r"(regs->regs[reg]), "0"(0)); + : "r"(va), "r"(*reg_addr), "0"(0)); if (error) goto got_exception; @@ -796,16 +1347,6 @@ do_entUna(void *va, unsigned long opcode, unsigned long reg, * uses them as temporary storage for integer memory to memory copies. * However, we need to deal with stt/ldt and sts/lds only. */ -#define OP_INT_MASK (1L << 0x22 | 1L << 0x2a | /* ldw stw */ \ - 1L << 0x23 | 1L << 0x2b | /* ldl stl */ \ - 1L << 0x21 | 1L << 0x29 | /* ldhu sth */ \ - 1L << 0x20 | 1L << 0x28) /* ldbu stb */ - -#define FN_INT_MASK (1L << 0x0 | 1L << 0x6 | /* ldbu_a stb_a */ \ - 1L << 0x1 | 1L << 0x7 | /* ldhu_a sth_a */ \ - 1L << 0x2 | 1L << 0x8 | /* ldw_a stw_a */ \ - 1L << 0x3 | 1L << 0x9) /* ldl_a stl_a */ - asmlinkage void do_entUnaUser(void __user *va, unsigned long opcode, unsigned long reg, struct pt_regs *regs) diff --git a/arch/sw_64/kernel/vdso.c b/arch/sw_64/kernel/vdso.c index 15f1f244a82f2bc4585a64857900004489fa8145..7e8030d32e15a865b8bba1e514dc3f20766917cf 100644 --- a/arch/sw_64/kernel/vdso.c +++ b/arch/sw_64/kernel/vdso.c @@ -36,6 +36,41 @@ struct vdso_data *vdso_data = &vdso_data_store.data; static struct vm_special_mapping vdso_spec[2]; +#ifdef CONFIG_SUBARCH_C3B +#define V_NODE_SHIFT 6 +static void init_cpu_map(void) +{ + + int i, whami, domain; + unsigned int shift, mask; + + if (is_in_host()) + shift = DOMAIN_ID_SHIFT; + else + shift = V_NODE_SHIFT; + mask = (1 << shift) - 1; + + vdso_data_write_begin(vdso_data); + for (i = 0; i < num_possible_cpus(); i++) { + domain = cpu_to_rcid(i) >> shift; + whami = (domain << DOMAIN_ID_SHIFT) | (cpu_to_rcid(i) & mask); + vdso_data->vdso_whami_to_cpu[whami] = i; + vdso_data->vdso_whami_to_node[whami] = domain; + } + vdso_data_write_end(vdso_data); +} +#else +static void init_cpu_map(void) +{ + int i; + + vdso_data_write_begin(vdso_data); + for (i = 0; i < num_possible_cpus(); i++) + vdso_data->vdso_cpu_to_node[i] = (cpu_to_rcid(i) & DOMAIN_ID_MASK) >> DOMAIN_ID_SHIFT; + vdso_data_write_end(vdso_data); +} +#endif + static int __init vdso_init(void) { int i; @@ -73,6 +108,8 @@ static int __init vdso_init(void) .pages = &vdso_pagelist[1], }; + init_cpu_map(); + return 0; } arch_initcall(vdso_init); @@ -118,26 +155,3 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, up_write(&mm->mmap_lock); return PTR_ERR(ret); } - -void update_vsyscall(struct timekeeper *tk) -{ - vdso_data_write_begin(vdso_data); - - vdso_data->xtime_sec = tk->xtime_sec; - vdso_data->xtime_nsec = tk->tkr_mono.xtime_nsec; - vdso_data->wall_to_mono_sec = tk->wall_to_monotonic.tv_sec; - vdso_data->wall_to_mono_nsec = tk->wall_to_monotonic.tv_nsec; - vdso_data->cs_shift = tk->tkr_mono.shift; - - vdso_data->cs_mult = tk->tkr_mono.mult; - vdso_data->cs_cycle_last = tk->tkr_mono.cycle_last; - vdso_data->cs_mask = tk->tkr_mono.mask; - - vdso_data_write_end(vdso_data); -} - -void update_vsyscall_tz(void) -{ - vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; - vdso_data->tz_dsttime = sys_tz.tz_dsttime; -} diff --git a/arch/sw_64/kernel/vdso/Makefile b/arch/sw_64/kernel/vdso/Makefile index 190cc345dbb909a618467d85aedc7761cbb5bd33..899f57aba588d5edeecbb8b81c38f4bfe0fef7f7 100644 --- a/arch/sw_64/kernel/vdso/Makefile +++ b/arch/sw_64/kernel/vdso/Makefile @@ -1,10 +1,16 @@ # SPDX-License-Identifier: GPL-2.0 # Symbols present in the vdso -vdso-syms = rt_sigreturn gettimeofday +ARCH_REL_TYPE_ABS := R_SW64_REFLONG|R_SW64_REFQUAD|R_SW64_JMP_SLOT +include $(srctree)/lib/vdso/Makefile +vdso-syms = rt_sigreturn gettimeofday getcpu # Files to link into the vdso obj-vdso = $(patsubst %, v%.o, $(vdso-syms)) +ifneq ($(c-gettimeofday-y),) + CFLAGS_vgettimeofday.o += -include $(c-gettimeofday-y) +endif + # Build rules targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.lds vdso-syms.S obj-vdso := $(addprefix $(obj)/, $(obj-vdso)) @@ -17,12 +23,14 @@ CPPFLAGS_vdso.lds += -P -C -U$(ARCH) CFLAGS_REMOVE_vdso.o = -pg CFLAGS_REMOVE_vrt_sigreturn.o = -pg CFLAGS_REMOVE_vgettimeofday.o = -pg +CFLAGS_REMOVE_vgetcpu = -pg ifdef CONFIG_FEEDBACK_COLLECT # vDSO code runs in userspace, not collecting feedback data. CFLAGS_REMOVE_vdso.o = -ffeedback-generate CFLAGS_REMOVE_vrt_sigreturn.o = -ffeedback-generate CFLAGS_REMOVE_vgettimeofday.o = -ffeedback-generate +CFLAGS_REMOVE_vgetcpu.o = -ffeedback-generate endif # Disable gcov profiling for VDSO code @@ -33,7 +41,7 @@ $(obj)/vdso.o: $(obj)/vdso.so # link rule for the .so file, .lds has to be first SYSCFLAGS_vdso.so.dbg = $(c_flags) -$(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso) FORCE +$(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso) $(call if_changed,vdsold) SYSCFLAGS_vdso.so.dbg = -shared -s -Wl,-soname=linux-vdso.so.1 \ $(call cc-ldoption, -Wl$(comma)--hash-style=both) @@ -61,14 +69,3 @@ quiet_cmd_vdsold = VDSOLD $@ # that contains the same symbols at the same offsets. quiet_cmd_so2s = SO2S $@ cmd_so2s = $(NM) -D $< | $(srctree)/$(src)/so2s.sh > $@ - -# install commands for the unstripped file -quiet_cmd_vdso_install = INSTALL $@ - cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ - -vdso.so: $(obj)/vdso.so.dbg - @mkdir -p $(MODLIB)/vdso - $(call cmd,vdso_install) - - -vdso_install: vdso.so diff --git a/arch/sw_64/kernel/vdso/vdso.lds.S b/arch/sw_64/kernel/vdso/vdso.lds.S index de1782ccb7b678c44497377f2a7985355b94a4a4..08134a86f66ce8becfd1407a0412281cadc42aa6 100644 --- a/arch/sw_64/kernel/vdso/vdso.lds.S +++ b/arch/sw_64/kernel/vdso/vdso.lds.S @@ -84,6 +84,7 @@ VERSION __vdso_rt_sigreturn; __vdso_gettimeofday; __vdso_clock_gettime; + __vdso_getcpu; local: *; }; } diff --git a/arch/sw_64/kernel/vdso/vgetcpu.c b/arch/sw_64/kernel/vdso/vgetcpu.c new file mode 100644 index 0000000000000000000000000000000000000000..6437ac6f94d51c5269a9224f066ea73806b34b04 --- /dev/null +++ b/arch/sw_64/kernel/vdso/vgetcpu.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include + +static void __getcpu(unsigned int *cpu, unsigned int *node, + const struct vdso_data *data) +{ + unsigned int cpuid; +#ifdef CONFIG_SUBARCH_C3B + asm volatile ("sys_call %1\n" + "mov $0, %0\n" + : "=&r"(cpuid) + : "i"(HMC_uwhami)); + *cpu = data->vdso_whami_to_cpu[cpuid]; + *node = data->vdso_whami_to_node[cpuid]; +#else + asm volatile ("csrr %0, %1" : "=&r"(cpuid) : "i"(CSR_SOFTCID)); + *cpu = cpuid; + *node = data->vdso_cpu_to_node[*cpu]; +#endif +} + + +long __vdso_getcpu(unsigned int *cpu, unsigned int *node, + struct getcpu_cache *unused) +{ + const struct vdso_data *data = get_vdso_data(); + + __getcpu(cpu, node, data); + return 0; +} diff --git a/arch/sw_64/kernel/vdso/vgettimeofday.c b/arch/sw_64/kernel/vdso/vgettimeofday.c index 69dcab66cb10a56285db65d251d7c7ede0bc88c1..ae40d4e5b68eb45d48f28805e501066bf74df0cc 100644 --- a/arch/sw_64/kernel/vdso/vgettimeofday.c +++ b/arch/sw_64/kernel/vdso/vgettimeofday.c @@ -13,192 +13,25 @@ */ #include +#include -#include -#include -#include -#include - -static __always_inline int syscall_fallback(clockid_t clkid, struct timespec64 *ts) -{ - long retval; - long error; - asm volatile( - " mov %2, $16\n" - " mov %3, $17\n" - " ldi $0, %4\n" - " sys_call %5\n" - " mov $0, %0\n" - " mov $19, %1" - : "=r"(retval), "=r"(error) - : "r"(clkid), "r"(ts), "i"(__NR_clock_gettime), "i"(HMC_callsys) - : "$0", "$16", "$17", "$19"); - if (unlikely(error)) - return -retval; - else - return retval; -} - -static __always_inline int do_realtime_coarse(struct timespec64 *ts, - const struct vdso_data *data) -{ - u32 start_seq; - - do { - start_seq = vdso_data_read_begin(data); - - ts->tv_sec = data->xtime_sec; - ts->tv_nsec = data->xtime_nsec >> data->cs_shift; - } while (vdso_data_read_retry(data, start_seq)); - - return 0; -} - - -static __always_inline int do_monotonic_coarse(struct timespec64 *ts, - const struct vdso_data *data) -{ - u32 start_seq; - u64 to_mono_sec; - u64 to_mono_nsec; - - do { - start_seq = vdso_data_read_begin(data); - - ts->tv_sec = data->xtime_sec; - ts->tv_nsec = data->xtime_nsec >> data->cs_shift; - - to_mono_sec = data->wall_to_mono_sec; - to_mono_nsec = data->wall_to_mono_nsec; - } while (vdso_data_read_retry(data, start_seq)); - - ts->tv_sec += to_mono_sec; - timespec64_add_ns(ts, to_mono_nsec); - - return 0; -} - -#if defined(CONFIG_SUBARCH_C3B) -static __always_inline u64 read_longtime(void) -{ - register unsigned long __r0 __asm__("$0"); - - __asm__ __volatile__( - "sys_call %1" : "=r"(__r0) : "i" (HMC_longtime)); - - return __r0; -} -#elif defined(CONFIG_SUBARCH_C4) -static __always_inline u64 read_longtime(void) -{ - return sw64_read_csr(CSR_SHTCLOCK); -} -#endif - -static __always_inline u64 get_ns(const struct vdso_data *data) +extern +int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts); +int __vdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) { - u64 cycle_now, delta, nsec; - - cycle_now = read_longtime(); - delta = (cycle_now - data->cs_cycle_last) & data->cs_mask; - - nsec = (delta * data->cs_mult) + data->xtime_nsec; - nsec >>= data->cs_shift; - - return nsec; -} - - -static __always_inline int do_realtime(struct timespec64 *ts, - const struct vdso_data *data) -{ - u32 start_seq; - u64 ns; - - do { - start_seq = vdso_data_read_begin(data); - - ts->tv_sec = data->xtime_sec; - ns = get_ns(data); - } while (vdso_data_read_retry(data, start_seq)); - - ts->tv_nsec = 0; - timespec64_add_ns(ts, ns); - - return 0; -} - -static __always_inline int do_monotonic(struct timespec64 *ts, - const struct vdso_data *data) -{ - u32 start_seq; - u64 ns; - u64 to_mono_sec; - u64 to_mono_nsec; - - do { - start_seq = vdso_data_read_begin(data); - - ts->tv_sec = data->xtime_sec; - ns = get_ns(data); - - to_mono_sec = data->wall_to_mono_sec; - to_mono_nsec = data->wall_to_mono_nsec; - } while (vdso_data_read_retry(data, start_seq)); - - ts->tv_sec += to_mono_sec; - ts->tv_nsec = 0; - timespec64_add_ns(ts, ns + to_mono_nsec); - - return 0; + return __cvdso_clock_gettime(clock, ts); } - +extern +int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz); int __vdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) { - const struct vdso_data *data = get_vdso_data(); - struct timespec64 ts; - int ret; - - ret = do_realtime(&ts, data); - if (ret) - return ret; - - if (tv) { - tv->tv_sec = ts.tv_sec; - tv->tv_usec = ts.tv_nsec / 1000; - } - - if (tz) { - tz->tz_minuteswest = data->tz_minuteswest; - tz->tz_dsttime = data->tz_dsttime; - } - - return 0; + return __cvdso_gettimeofday(tv, tz); } -int __vdso_clock_gettime(clockid_t clkid, struct timespec64 *ts) +extern +int __vdso_clock_getres(clockid_t clock_id, struct __kernel_timespec *res); +int __vdso_clock_getres(clockid_t clock_id, struct __kernel_timespec *res) { - const struct vdso_data *data = get_vdso_data(); - int ret; - - switch (clkid) { - case CLOCK_REALTIME_COARSE: - ret = do_realtime_coarse(ts, data); - break; - case CLOCK_MONOTONIC_COARSE: - ret = do_monotonic_coarse(ts, data); - break; - case CLOCK_REALTIME: - ret = do_realtime(ts, data); - break; - case CLOCK_MONOTONIC: - ret = do_monotonic(ts, data); - break; - default: - /* fall back to a syscall */ - ret = syscall_fallback(clkid, ts); - } - - return ret; + return __cvdso_clock_getres(clock_id, res); } diff --git a/arch/sw_64/kvm/emulate.c b/arch/sw_64/kvm/emulate.c index 9f2ededd5a1e925df39a5088b771b8ee4a607709..f103a5f3b9d4e96271548497b4847a2a2ba2424c 100644 --- a/arch/sw_64/kvm/emulate.c +++ b/arch/sw_64/kvm/emulate.c @@ -4,6 +4,7 @@ * Author: fire3 yangzh * linhn */ +#include #include #include #include @@ -75,6 +76,12 @@ unsigned int interrupt_pending(struct kvm_vcpu *vcpu, bool *more) bitmap_copy(blk, vcpu->arch.irqs_pending, SWVM_IRQS); + if (test_bit(INT_RTC, blk)) + return INT_RTC; + + if (test_bit(INT_IPI, blk)) + return INT_IPI; + irq = find_last_bit(blk, SWVM_IRQS); return irq; diff --git a/arch/sw_64/kvm/mmu.c b/arch/sw_64/kvm/mmu.c index b161b2ed8c8c5409b2f5b5af06bacacc14ca2ebb..24f6bc3545b484f7b44277e463625e39612c81b6 100644 --- a/arch/sw_64/kvm/mmu.c +++ b/arch/sw_64/kvm/mmu.c @@ -70,21 +70,35 @@ enum { * * Function clears a PMD entry, flushes TLBs. */ -static void apt_dissolve_pmd(struct kvm *kvm, phys_addr_t addr, pmd_t *pmd) +static void apt_dissolve_pmd(struct kvm *kvm, pmd_t *pmd) { - int i; - if (!pmd_trans_huge(*pmd)) return; - if (pmd_cont(*pmd)) { - for (i = 0; i < CONT_PMDS; i++, pmd++) - pmd_clear(pmd); - } else + pmd_clear(pmd); + kvm_flush_remote_tlbs(kvm); + put_page(virt_to_page(pmd)); +} + +/** + * apt_dissolve_cont_pmd() - clear and flush huge cont PMD entry + * @kvm: pointer to kvm structure. + * @addr: IPA + * @pmd: pmd pointer for IPA + * + * Function clears a cont PMD entry, flushes TLBs. + */ +static void apt_dissolve_cont_pmd(struct kvm *kvm, pmd_t *pmd) +{ + int i; + pmd_t *start_pmd; + + start_pmd = pmd; + for (i = 0; i < CONT_PMDS; i++, pmd++) pmd_clear(pmd); kvm_flush_remote_tlbs(kvm); - put_page(virt_to_page(pmd)); + put_page(virt_to_page(start_pmd)); } /** @@ -95,7 +109,7 @@ static void apt_dissolve_pmd(struct kvm *kvm, phys_addr_t addr, pmd_t *pmd) * * Function clears a PUD entry, flushes TLBs. */ -static void apt_dissolve_pud(struct kvm *kvm, phys_addr_t addr, pud_t *pudp) +static void apt_dissolve_pud(struct kvm *kvm, pud_t *pudp) { if (!pud_huge(*pudp)) return; @@ -146,8 +160,10 @@ static void unmap_apt_pmds(struct kvm *kvm, pud_t *pud, if (!pmd_none(*pmd)) { if (pmd_trans_huge(*pmd)) { if (pmd_cont(*pmd)) { - for (i = 0; i < CONT_PMDS; i++, pmd++) - pmd_clear(pmd); + for (i = 0; i < CONT_PMDS; i++) + pmd_clear(pmd + i); + pmd += CONT_PMDS - 1; + next += CONT_PMD_SIZE - PMD_SIZE; } else pmd_clear(pmd); /* Do we need flush tlb???? edited by lff */ @@ -802,7 +818,7 @@ static int apt_set_pte_fast(struct kvm_vcpu *vcpu, * on to allocate page. */ if (logging_active) - apt_dissolve_pud(kvm, addr, pud); + apt_dissolve_pud(kvm, pud); find_pud: if (pud_none(*pud)) { @@ -826,8 +842,13 @@ static int apt_set_pte_fast(struct kvm_vcpu *vcpu, * While dirty page logging - dissolve huge PMD, then continue on to * allocate page. */ - if (logging_active) - apt_dissolve_pmd(kvm, addr, pmd); + if (logging_active) { + if (pmd_cont(*pmd)) + apt_dissolve_cont_pmd(kvm, + pmd_offset(pud, addr & CONT_PMD_MASK)); + else + apt_dissolve_pmd(kvm, pmd); + } find_pmd: /* Create stage-2 page mappings - Level 2 */ @@ -891,7 +912,7 @@ static int apt_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, * on to allocate page. */ if (logging_active) - apt_dissolve_pud(kvm, addr, pud); + apt_dissolve_pud(kvm, pud); if (pud_none(*pud)) { if (!cache) @@ -914,8 +935,13 @@ static int apt_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, * While dirty page logging - dissolve huge PMD, then continue on to * allocate page. */ - if (logging_active) - apt_dissolve_pmd(kvm, addr, pmd); + if (logging_active) { + if (pmd_cont(*pmd)) + apt_dissolve_cont_pmd(kvm, + pmd_offset(pud, addr & CONT_PMD_MASK)); + else + apt_dissolve_pmd(kvm, pmd); + } /* Create stage-2 page mappings - Level 2 */ if (pmd_none(*pmd)) { @@ -954,10 +980,11 @@ static int apt_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache, static int apt_set_pmd_huge(struct kvm *kvm, struct kvm_mmu_memory_cache - *cache, phys_addr_t addr, const pmd_t *new_pmd, unsigned long sz) + *cache, phys_addr_t addr, pmd_t *new_pmd, unsigned long sz) { pmd_t *pmd, old_pmd, *ori_pmd; int i; + unsigned long dpfn; retry: pmd = apt_get_pmd(kvm, cache, addr, sz); VM_BUG_ON(!pmd); @@ -1020,8 +1047,11 @@ static int apt_set_pmd_huge(struct kvm *kvm, struct kvm_mmu_memory_cache /* Do we need WRITE_ONCE(pmd, new_pmd)? */ if (sz == CONT_PMD_SIZE) { - for (i = 0; i < CONT_PMDS; i++, ori_pmd++) + dpfn = 1UL << (_PFN_SHIFT + PMD_SHIFT - PAGE_SHIFT); + for (i = 0; i < CONT_PMDS; i++, ori_pmd++) { set_pmd(ori_pmd, *new_pmd); + new_pmd->pmd += dpfn; + } } else set_pmd(pmd, *new_pmd); return 0; @@ -1191,7 +1221,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, /* Let's check if we will get back a huge page backed by hugetlbfs */ down_read(¤t->mm->mmap_lock); - vma = find_vma_intersection(current->mm, hva, hva + 1); + vma = vma_lookup(current->mm, hva); if (unlikely(!vma)) { kvm_err("Failed to find VMA for hva 0x%lx\n", hva); up_read(¤t->mm->mmap_lock); @@ -1352,7 +1382,6 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, out_unlock: spin_unlock(&kvm->mmu_lock); - kvm_set_pfn_accessed(pfn); kvm_release_pfn_clean(pfn); return ret; } @@ -1404,7 +1433,7 @@ int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, * needs emulation. */ - if (hva == KVM_HVA_ERR_BAD) { + if (hva == KVM_HVA_ERR_BAD || (write_fault && !writable)) { hargs->arg1 = fault_gpa | (hargs->arg1 & 0x1fffUL); ret = io_mem_abort(vcpu, run, hargs); goto out_unlock; @@ -1507,18 +1536,19 @@ bool kvm_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range) return false; } -/** - * kvm_mmu_write_protect_pt_masked() - write protect dirty pages + +/* + * kvm_arch_mmu_enable_log_dirty_pt_masked - enable dirty logging for selected pages. * @kvm: The KVM pointer * @slot: The memory slot associated with mask * @gfn_offset: The gfn offset in memory slot - * @mask: The mask of dirty pages at offset 'gfn_offset' in this memory - * slot to be write protected + * @mask: The mask of pages at offset 'gfn_offset' in this memory + * slot to enable dirty logging on * - * Walks bits set in mask write protects the associated pte's. Caller must + * Write protect selected pages to enable dirty logging for them. Caller must * acquire kvm_mmu_lock. */ -static void kvm_mmu_write_protect_pt_masked(struct kvm *kvm, +void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm, struct kvm_memory_slot *slot, gfn_t gfn_offset, unsigned long mask) { @@ -1528,17 +1558,3 @@ static void kvm_mmu_write_protect_pt_masked(struct kvm *kvm, apt_wp_range(kvm, start, end); } - -/* - * kvm_arch_mmu_enable_log_dirty_pt_masked - enable dirty logging for selected - * dirty pages. - * - * It calls kvm_mmu_write_protect_pt_masked to write protect selected pages to - * enable dirty logging for them. - */ -void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm, - struct kvm_memory_slot *slot, - gfn_t gfn_offset, unsigned long mask) -{ - kvm_mmu_write_protect_pt_masked(kvm, slot, gfn_offset, mask); -} diff --git a/arch/sw_64/kvm/sw64.c b/arch/sw_64/kvm/sw64.c index d0510e567c326050777a98a344c35135acce00b4..b70f50e5610f94c77d92497243ea7928598e99da 100644 --- a/arch/sw_64/kvm/sw64.c +++ b/arch/sw_64/kvm/sw64.c @@ -15,6 +15,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include "trace.h" @@ -231,6 +232,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_IRQCHIP: case KVM_CAP_IOEVENTFD: case KVM_CAP_SYNC_MMU: + case KVM_CAP_READONLY_MEM: + case KVM_CAP_SET_GUEST_DEBUG: r = 1; break; case KVM_CAP_NR_VCPUS: @@ -605,13 +608,6 @@ vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf) return VM_FAULT_SIGBUS; } -void kvm_arch_flush_remote_tlbs_memslot(struct kvm *kvm, - struct kvm_memory_slot *memslot) -{ - /* Let implementation handle TLB/GVA invalidation */ - kvm_arch_flush_shadow_memslot(kvm, memslot); -} - int kvm_dev_ioctl_check_extension(long ext) { int r; diff --git a/arch/sw_64/lib/copy_simd_align_template.S b/arch/sw_64/lib/copy_simd_align_template.S index fbb5912e121394fe29fdf297fc9a817a5287e204..aa648b7c822a7ebbb9f4d86b3ef9ae73e414b995 100644 --- a/arch/sw_64/lib/copy_simd_align_template.S +++ b/arch/sw_64/lib/copy_simd_align_template.S @@ -15,7 +15,9 @@ * */ +#ifdef CONFIG_SUBARCH_C3B #define NC_STORE_THRESHOLD 2048 +#endif #define SAVE_SIMD_REGS \ ldi $sp, -0x60($sp); \ @@ -97,6 +99,7 @@ $dest_aligned_32: $prep_simd_loop: SAVE_SIMD_REGS +#ifdef CONFIG_SUBARCH_C3B ldi $1, NC_STORE_THRESHOLD($31) cmple $18, $1, $1 bne $1, $simd_loop @@ -114,6 +117,7 @@ $simd_loop_nc: beq $1, $simd_loop_nc memb # required for _nc store instructions br $31, $simd_loop_end +#endif .align 4 $simd_loop: @@ -207,6 +211,7 @@ $prep_simd_u_loop: ifmovd $1, $f1 ifmovd $2, $f2 FIXUP_LDST( vldd $f4, 0($3) ) +#ifdef CONFIG_SUBARCH_C3B ldi $1, NC_STORE_THRESHOLD($31) cmple $18, $1, $1 bne $1, $simd_u_loop @@ -230,6 +235,7 @@ $simd_u_loop_nc: beq $1, $simd_u_loop_nc memb # required for _nc store instructions br $31, $simd_u_loop_end +#endif .align 4 $simd_u_loop: diff --git a/arch/sw_64/lib/set_simd_align_template.S b/arch/sw_64/lib/set_simd_align_template.S index fa77cacf684fbb3564221cd2ed098d3b74227504..6a8b4118f2a030f774b337da35760b2037281000 100644 --- a/arch/sw_64/lib/set_simd_align_template.S +++ b/arch/sw_64/lib/set_simd_align_template.S @@ -13,7 +13,9 @@ * */ +#ifdef CONFIG_SUBARCH_C3B #define NC_STORE_THRESHOLD 2048 +#endif #define SAVE_SIMD_REGS \ ldi $sp, -0x40($sp); \ @@ -65,6 +67,7 @@ $prep_simd_loop: SAVE_SIMD_REGS ifmovd $17, $f1 vcpyf $f1, $f1 +#ifdef CONFIG_SUBARCH_C3B ldi $1, NC_STORE_THRESHOLD($31) cmple $18, $1, $1 bne $1, $simd_loop @@ -79,6 +82,7 @@ $simd_loop_nc: beq $1, $simd_loop_nc memb # required for _nc store instructions br $31, $simd_loop_end +#endif .align 3 $simd_loop: diff --git a/arch/sw_64/lib/udelay.c b/arch/sw_64/lib/udelay.c index 59ca8a97d748895a49e4fbaf83a85eee99f0d459..c60601d56b0e1994ce2bc653610a791bd6645eeb 100644 --- a/arch/sw_64/lib/udelay.c +++ b/arch/sw_64/lib/udelay.c @@ -7,6 +7,8 @@ #include +#include + /* * Use only for very small delays (< 1 msec). * diff --git a/arch/sw_64/mm/hugetlbpage_c4.c b/arch/sw_64/mm/hugetlbpage_c4.c index 913389cd257704f67f0bdaa9be97754d15a9b8a9..2611af9cf7807140a5740783ff45e96b18ebba91 100644 --- a/arch/sw_64/mm/hugetlbpage_c4.c +++ b/arch/sw_64/mm/hugetlbpage_c4.c @@ -88,6 +88,19 @@ static pte_t get_and_clear(struct mm_struct *mm, return orig_pte; } +static void clear_flush(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, unsigned long pgsize, + unsigned long ncontig) +{ + struct vm_area_struct vma = TLB_FLUSH_VMA(mm, 0); + unsigned long i, saddr = addr; + + for (i = 0; i < ncontig; i++, addr += pgsize, ptep++) + pte_clear(mm, addr, ptep); + + flush_tlb_range(&vma, saddr, addr); +} + static pte_t get_clear_contig_flush(struct mm_struct *mm, unsigned long addr, pte_t *ptep, unsigned long pgsize, unsigned long ncontig) @@ -202,7 +215,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, size_t pgsize; int i; int ncontig; - unsigned long pfn; + unsigned long pfn, dpfn; pgprot_t hugeprot; /* @@ -218,11 +231,12 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, ncontig = num_contig_ptes(sz, &pgsize); pfn = pte_pfn(pte); + dpfn = PMD_SIZE >> PAGE_SHIFT; hugeprot = pte_pgprot(pte); - get_and_clear(mm, addr, ptep, pgsize, ncontig); + clear_flush(mm, addr, ptep, pgsize, ncontig); - for (i = 0; i < ncontig; i++, ptep++, addr += pgsize) + for (i = 0; i < ncontig; i++, ptep++, addr += pgsize, pfn += dpfn) set_pte_at(mm, addr, ptep, pfn_pte(pfn, hugeprot)); } @@ -241,7 +255,7 @@ void set_huge_swap_pte_at(struct mm_struct *mm, unsigned long addr, void huge_ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - unsigned long pfn; + unsigned long pfn, dpfn; pgprot_t hugeprot; int ncontig, i; size_t pgsize; @@ -253,6 +267,7 @@ void huge_ptep_set_wrprotect(struct mm_struct *mm, } ncontig = CONT_PMDS; + dpfn = PMD_SIZE >> PAGE_SHIFT; pte = get_and_clear(mm, addr, ptep, pgsize, ncontig); pte = pte_wrprotect(pte); @@ -260,7 +275,7 @@ void huge_ptep_set_wrprotect(struct mm_struct *mm, hugeprot = pte_pgprot(pte); pfn = pte_pfn(pte); - for (i = 0; i < ncontig; i++, ptep++, addr += pgsize) + for (i = 0; i < ncontig; i++, ptep++, addr += pgsize, pfn += dpfn) set_pte_at(mm, addr, ptep, pfn_pte(pfn, hugeprot)); } @@ -319,7 +334,7 @@ int huge_ptep_set_access_flags(struct vm_area_struct *vma, { int ncontig, i; size_t pgsize = 0; - unsigned long pfn = pte_pfn(pte); + unsigned long pfn = pte_pfn(pte), dpfn; pgprot_t hugeprot; pte_t orig_pte; @@ -327,6 +342,7 @@ int huge_ptep_set_access_flags(struct vm_area_struct *vma, return ptep_set_access_flags(vma, addr, ptep, pte, dirty); ncontig = CONT_PMDS; + dpfn = PMD_SIZE >> PAGE_SHIFT; if (!__cont_access_flags_changed(ptep, pte, ncontig)) return 0; @@ -342,7 +358,7 @@ int huge_ptep_set_access_flags(struct vm_area_struct *vma, pte = pte_mkyoung(pte); hugeprot = pte_pgprot(pte); - for (i = 0; i < ncontig; i++, ptep++, addr += pgsize) + for (i = 0; i < ncontig; i++, ptep++, addr += pgsize, pfn += dpfn) set_pte_at(vma->vm_mm, addr, ptep, pfn_pte(pfn, hugeprot)); return 1; @@ -433,20 +449,14 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr, } #endif /* CONFIG_HUGETLB_PAGE */ -static __init int setup_hugepagesz(char *opt) +bool __init arch_hugetlb_valid_size(unsigned long size) { - unsigned long ps = memparse(opt, &opt); - - switch (ps) { + switch (size) { case PUD_SIZE: case PMD_SIZE * CONT_PMDS: case PMD_SIZE: - hugetlb_add_hstate(ilog2(ps) - PAGE_SHIFT); - return 1; + return true; } - pr_err("hugepagesz: Unsupported page size %lu M\n", - ps >> 20); - return 0; + return false; } -__setup("hugepagesz=", setup_hugepagesz); diff --git a/arch/sw_64/mm/init.c b/arch/sw_64/mm/init.c index 6e976d7b20e473ad1bb8b3b4cab9ef68f6f4eaba..d5e1baf23f72b790c4c9436f22d183d6eb87c455 100644 --- a/arch/sw_64/mm/init.c +++ b/arch/sw_64/mm/init.c @@ -68,9 +68,9 @@ static int __init setup_mem_size(char *p) mem_size_limit = size; if (mem_start < NODE0_START) { - mem_start = NODE0_START; mem_size_limit -= min(mem_size_limit, NODE0_START - mem_start); + mem_start = NODE0_START; } return 0; @@ -109,6 +109,9 @@ switch_to_system_map(void) { memset(swapper_pg_dir, 0, PAGE_SIZE); update_ptbr_sys(virt_to_phys(swapper_pg_dir)); +#ifdef CONFIG_SUBARCH_C4 + update_ptbr_usr(__pa_symbol(empty_zero_page)); +#endif tbiv(); } @@ -385,6 +388,8 @@ void __init sw64_memblock_init(void) } } + early_init_fdt_scan_reserved_mem(); + /* end of DRAM range may have been changed */ max_pfn = max_low_pfn = PFN_DOWN(memblock_end_of_DRAM()); } @@ -468,23 +473,21 @@ void arch_remove_memory(u64 start, u64 size, struct vmem_altmap *altmap) #endif static const pgprot_t protection_map[16] = { - [VM_NONE] = _PAGE_P(_PAGE_FOE | _PAGE_FOW | - _PAGE_FOR), - [VM_READ] = _PAGE_P(_PAGE_FOE | _PAGE_FOW), - [VM_WRITE] = _PAGE_P(_PAGE_FOE), - [VM_WRITE | VM_READ] = _PAGE_P(_PAGE_FOE), - [VM_EXEC] = _PAGE_P(_PAGE_FOW | _PAGE_FOR), - [VM_EXEC | VM_READ] = _PAGE_P(_PAGE_FOW), - [VM_EXEC | VM_WRITE] = _PAGE_P(0), - [VM_EXEC | VM_WRITE | VM_READ] = _PAGE_P(0), - [VM_SHARED] = _PAGE_S(_PAGE_FOE | _PAGE_FOW | - _PAGE_FOR), - [VM_SHARED | VM_READ] = _PAGE_S(_PAGE_FOE | _PAGE_FOW), - [VM_SHARED | VM_WRITE] = _PAGE_S(_PAGE_FOE), - [VM_SHARED | VM_WRITE | VM_READ] = _PAGE_S(_PAGE_FOE), - [VM_SHARED | VM_EXEC] = _PAGE_S(_PAGE_FOW | _PAGE_FOR), - [VM_SHARED | VM_EXEC | VM_READ] = _PAGE_S(_PAGE_FOW), - [VM_SHARED | VM_EXEC | VM_WRITE] = _PAGE_S(0), - [VM_SHARED | VM_EXEC | VM_WRITE | VM_READ] = _PAGE_S(0) + [VM_NONE] = PAGE_NONE, + [VM_READ] = PAGE_READONLY_NOEXEC, + [VM_WRITE] = PAGE_COPY_NOEXEC, + [VM_WRITE | VM_READ] = PAGE_COPY_NOEXEC, + [VM_EXEC] = PAGE_EXEC, + [VM_EXEC | VM_READ] = PAGE_READONLY_EXEC, + [VM_EXEC | VM_WRITE] = PAGE_COPY_EXEC, + [VM_EXEC | VM_WRITE | VM_READ] = PAGE_COPY_EXEC, + [VM_SHARED] = PAGE_NONE, + [VM_SHARED | VM_READ] = PAGE_READONLY_NOEXEC, + [VM_SHARED | VM_WRITE] = PAGE_SHARED_NOEXEC, + [VM_SHARED | VM_WRITE | VM_READ] = PAGE_SHARED_NOEXEC, + [VM_SHARED | VM_EXEC] = PAGE_EXEC, + [VM_SHARED | VM_EXEC | VM_READ] = PAGE_READONLY_EXEC, + [VM_SHARED | VM_EXEC | VM_WRITE] = PAGE_SHARED_EXEC, + [VM_SHARED | VM_EXEC | VM_WRITE | VM_READ] = PAGE_SHARED_EXEC }; DECLARE_VM_GET_PAGE_PROT diff --git a/arch/sw_64/mm/numa.c b/arch/sw_64/mm/numa.c index 2793718c66f6629bc517bc51b109f7d5d89af38b..8736a49e54ee73fa1dfbd05c16a9e033f14e63cf 100644 --- a/arch/sw_64/mm/numa.c +++ b/arch/sw_64/mm/numa.c @@ -289,6 +289,28 @@ static void __init get_numa_info_socket(void) } } +static void cpu_set_node(void) +{ + int i; + + if (numa_off) { + for (i = 0; i < nr_cpu_ids; i++) + cpu_to_node_map[i] = 0; + } else { + for (i = 0; i < nr_cpu_ids; i++) { + int nid = rcid_to_domain_id(cpu_to_rcid(i)); + + cpu_to_node_map[i] = nid; + node_set(nid, numa_nodes_parsed); + } + } + /* + * Setup numa_node for cpu 0 before per_cpu area for booting. + * Actual setup of numa_node will be done in native_smp_prepare_cpus(). + */ + set_cpu_numa_node(0, cpu_to_node_map[0]); +} + static int __init manual_numa_init(void) { int ret, nid; @@ -350,6 +372,8 @@ static int __init manual_numa_init(void) } } + cpu_set_node(); + return 0; } @@ -385,37 +409,6 @@ void __init sw64_numa_init(void) numa_init(manual_numa_init); } -void cpu_set_node(void) -{ - int i; - - if (numa_off) { - for (i = 0; i < nr_cpu_ids; i++) - cpu_to_node_map[i] = 0; - } else { - int rr, default_node, cid; - - rr = first_node(node_online_map); - for (i = 0; i < nr_cpu_ids; i++) { - cid = cpu_to_rcid(i); - default_node = rcid_to_domain_id(cid); - if (node_online(default_node)) { - cpu_to_node_map[i] = default_node; - } else { - cpu_to_node_map[i] = rr; - rr = next_node(rr, node_online_map); - if (rr == MAX_NUMNODES) - rr = first_node(node_online_map); - } - } - } - /* - * Setup numa_node for cpu 0 before per_cpu area for booting. - * Actual setup of numa_node will be done in native_smp_prepare_cpus(). - */ - set_cpu_numa_node(0, cpu_to_node_map[0]); -} - void numa_store_cpu_info(unsigned int cpu) { set_cpu_numa_node(cpu, cpu_to_node_map[cpu]); diff --git a/arch/sw_64/net/bpf_jit_comp.c b/arch/sw_64/net/bpf_jit_comp.c index 31202dd0f9cf8dd8fd51d0d30c94ea422d74c8b7..477ec889d217a30635a5d5749c2f25ce86270202 100644 --- a/arch/sw_64/net/bpf_jit_comp.c +++ b/arch/sw_64/net/bpf_jit_comp.c @@ -661,7 +661,8 @@ static int add_exception_handler(const struct bpf_insn *insn, * >0 - successfully JITed a 16-byte eBPF instruction. * <0 - failed to JIT. */ -static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) +static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, + bool extra_pass) { const u8 code = insn->code; u8 dst = bpf2sw64[insn->dst_reg]; @@ -672,7 +673,6 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) const s32 imm = insn->imm; const int bpf_idx = insn - ctx->prog->insnsi; s32 jmp_offset; - u64 func; struct bpf_insn insn1; u64 imm64; int ret; @@ -1142,13 +1142,18 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) break; case BPF_JMP | BPF_CALL: - func = (u64)__bpf_call_base + imm; - if ((func & ~(KERNEL_IMAGE_SIZE - 1)) != __START_KERNEL_map) - /* calling bpf program, switch to vmalloc addr */ - func = (func & U32_MAX) | VMALLOC_START; + { + bool fixed; + u64 func; + + ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass, &func, &fixed); + if (ret < 0) + return ret; + emit_sw64_ldu64(SW64_BPF_REG_PV, func, ctx); emit(SW64_BPF_CALL(SW64_BPF_REG_RA, SW64_BPF_REG_PV), ctx); break; + } case BPF_JMP | BPF_TAIL_CALL: if (emit_bpf_tail_call(ctx)) @@ -1212,6 +1217,13 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) return ret; break; + /* speculation barrier */ + case BPF_ST | BPF_NOSPEC: + /* + * Nothing required here. + */ + break; + /* ST: *(size *)(dst + off) = imm */ case BPF_ST | BPF_MEM | BPF_W: case BPF_ST | BPF_MEM | BPF_H: @@ -1269,7 +1281,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) return 0; } -static int build_body(struct jit_ctx *ctx) +static int build_body(struct jit_ctx *ctx, bool extra_pass) { const struct bpf_prog *prog = ctx->prog; int i; @@ -1280,7 +1292,7 @@ static int build_body(struct jit_ctx *ctx) if (ctx->image == NULL) ctx->insn_offset[i] = ctx->idx; - ret = build_insn(insn, ctx); + ret = build_insn(insn, ctx, extra_pass); if (ret < 0) return ret; while (ret > 0) { @@ -1371,7 +1383,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) /* Fake pass to fill in ctx->offset. */ build_prologue(&ctx, was_classic); - if (build_body(&ctx)) { + if (build_body(&ctx, extra_pass)) { prog = orig_prog; goto out_off; } @@ -1405,7 +1417,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) build_prologue(&ctx, was_classic); - if (build_body(&ctx)) { + if (build_body(&ctx, extra_pass)) { bpf_jit_binary_free(header); prog = orig_prog; goto out_off; diff --git a/arch/sw_64/pci/pci-legacy.c b/arch/sw_64/pci/pci-legacy.c index 8a9ac6f1146be050ca1c119b799399f0194f89e8..417852cbfe952efb3ed9a9cce188134e8b5170aa 100644 --- a/arch/sw_64/pci/pci-legacy.c +++ b/arch/sw_64/pci/pci-legacy.c @@ -227,6 +227,20 @@ static bool __init is_any_rc_linkup_one_node(unsigned long node) return false; } +static bool __init is_sunway_legacy_pci(void) +{ + if (IS_ENABLED(CONFIG_SUBARCH_C3B)) + return true; + + if (sunway_machine_is_compatible("sunway,chip4")) + return true; + + if (is_in_host() && sunway_machine_is_compatible("sunway,junzhang")) + return true; + + return false; +} + void __init sw64_init_arch(void) { if (IS_ENABLED(CONFIG_PCI)) { @@ -238,8 +252,7 @@ void __init sw64_init_arch(void) if (!acpi_disabled) return; - if (!sunway_machine_is_compatible("sunway,chip3") && - !sunway_machine_is_compatible("sunway,junzhang")) + if (!is_sunway_legacy_pci()) return; sunway_legacy_pci = true; diff --git a/arch/sw_64/pci/pci-sysfs.c b/arch/sw_64/pci/pci-sysfs.c index fd097d52b16af6938c06ed0bc59ac733bc3181ad..4b9a29f2f3486e401e1881e57c5e2cfb2ee9bb6c 100644 --- a/arch/sw_64/pci/pci-sysfs.c +++ b/arch/sw_64/pci/pci-sysfs.c @@ -58,6 +58,7 @@ static int pci_mmap_resource(struct kobject *kobj, struct vm_area_struct *vma, int sparse) { struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj)); + struct pci_controller *hose = pci_bus_to_pci_controller(pdev->bus); struct resource *res = attr->private; enum pci_mmap_state mmap_type; struct pci_bus_region bar; @@ -79,7 +80,7 @@ static int pci_mmap_resource(struct kobject *kobj, vma->vm_pgoff += bar.start >> (PAGE_SHIFT - (sparse ? 5 : 0)); mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; - return hose_mmap_page_range(pdev->sysdata, vma, mmap_type, sparse); + return hose_mmap_page_range(hose, vma, mmap_type, sparse); } static int pci_mmap_resource_sparse(struct file *filp, struct kobject *kobj, diff --git a/arch/sw_64/pci/pci.c b/arch/sw_64/pci/pci.c index 841ec3ea9f752a9e17c3ec059c234aef2933a6f5..de0c7c4a45c1dae86ef1207f2a836ed8e22e3134 100644 --- a/arch/sw_64/pci/pci.c +++ b/arch/sw_64/pci/pci.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -265,6 +266,35 @@ static void enable_sw_dca(struct pci_dev *dev) DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, enable_sw_dca); #endif +static int jm585_restart_notify(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct pci_dev *pdev; + struct pci_controller *hose; + int val; + + pdev = pci_get_device(PCI_VENDOR_ID_JMICRON, 0x0585, NULL); + if (pdev) { + hose = pci_bus_to_pci_controller(pdev->bus); + val = readl(hose->rc_config_space_base + RC_PORT_LINK_CTL); + writel((val | 0x8), (hose->rc_config_space_base + RC_PORT_LINK_CTL)); + writel(val, (hose->rc_config_space_base + RC_PORT_LINK_CTL)); + } + + return NOTIFY_DONE; +} + +static void quirk_jm585_restart(struct pci_dev *dev) +{ + static struct notifier_block jm585_restart_nb = { + .notifier_call = jm585_restart_notify, + .priority = 128, + }; + + register_restart_handler(&jm585_restart_nb); +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_JMICRON, 0x0585, quirk_jm585_restart); + /** * There are some special aspects to the Root Complex of Sunway: * 1. Root Complex config space base addr is different diff --git a/arch/sw_64/platform/cpufreq.c b/arch/sw_64/platform/cpufreq.c index 69d7611a2fb0cad8abf9768650596688a7c9520c..e18201069f6756e314c22f2908e3cd1fe24b2add 100644 --- a/arch/sw_64/platform/cpufreq.c +++ b/arch/sw_64/platform/cpufreq.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include #include @@ -136,12 +136,20 @@ EXPORT_SYMBOL(sw64_clk_get); unsigned int __sw64_cpufreq_get(struct cpufreq_policy *policy) { - int i; + int i, clu_lv1_sel; u64 val; void __iomem *spbu_base = misc_platform_get_spbu_base(0); struct cpufreq_frequency_table *ft = policy->freq_table; - val = readq(spbu_base + OFFSET_CLK_CTL) >> CORE_PLL2_CFG_SHIFT; + clu_lv1_sel = (readq(spbu_base + OFFSET_CLU_LV1_SEL) >> 2) & 0x3; + + if (clu_lv1_sel == 0) + val = readq(spbu_base + OFFSET_CLK_CTL) >> CORE_PLL0_CFG_SHIFT; + else if (clu_lv1_sel == 2) + val = readq(spbu_base + OFFSET_CLK_CTL) >> CORE_PLL1_CFG_SHIFT; + else + val = readq(spbu_base + OFFSET_CLK_CTL) >> CORE_PLL2_CFG_SHIFT; + val &= CORE_PLL2_CFG_MASK; for (i = 0; ft[i].frequency != CPUFREQ_TABLE_END; i++) { diff --git a/drivers/clocksource/timer-sw64.c b/drivers/clocksource/timer-sw64.c index 5dad3496c0a02e022097968e2a9ed4baa09f0a47..8b022f455c784636add3efcf17b2fffd7ac25239 100644 --- a/drivers/clocksource/timer-sw64.c +++ b/drivers/clocksource/timer-sw64.c @@ -8,9 +8,9 @@ #include #include +#include #include #include -#include #include #define DEFAULT_MCLK 25000 /* Khz */ @@ -94,7 +94,7 @@ static int longtime_enable(struct clocksource *cs) void __iomem *spbu_base = misc_platform_get_spbu_base(0); void __iomem *gpio_base = misc_platform_get_gpio_base(0); - switch (cpu_desc.model) { + switch (current_cpu_data.model) { case CPU_SW3231: writeq(0, gpio_base + OFFSET_GPIO_SWPORTA_DR); writeq(0xff, gpio_base + OFFSET_GPIO_SWPORTA_DDR); diff --git a/drivers/cpufreq/sw64_cpufreq.c b/drivers/cpufreq/sw64_cpufreq.c index f4bf5f3cc550d9ce0788707c2f8cb7eef11d77b2..93163da904a2b2605eb2a18a719477c891737424 100644 --- a/drivers/cpufreq/sw64_cpufreq.c +++ b/drivers/cpufreq/sw64_cpufreq.c @@ -66,13 +66,16 @@ static unsigned int sw64_cpufreq_get(unsigned int cpu) static int sw64_cpufreq_target(struct cpufreq_policy *policy, unsigned int index) { + int ret; unsigned int cpu = policy->cpu; if (!cpu_online(cpu)) return -ENODEV; /* setting the cpu frequency */ - sw64_set_rate(index); + ret = sw64_set_rate(index); + if (ret) + return ret; update_cpu_freq(freq_table[index].frequency); return 0; diff --git a/drivers/firmware/efi/sunway-init.c b/drivers/firmware/efi/sunway-init.c index 8557c181c28c9b9045bffd03f9ab4742cfda8444..ec678b403270b0edb63ad36fcc2afc3a1bb8a045 100644 --- a/drivers/firmware/efi/sunway-init.c +++ b/drivers/firmware/efi/sunway-init.c @@ -27,7 +27,7 @@ #include unsigned long entSuspend; -unsigned long bios_version; +unsigned long sunway_bios_version; static int __init is_memory(efi_memory_desc_t *md) { @@ -38,7 +38,7 @@ static int __init is_memory(efi_memory_desc_t *md) static efi_config_table_type_t arch_tables[] __initdata = { {SMBIOS3_TABLE_GUID, NULL, ""}, {SLEEP_ENTRY_GUID, &entSuspend, "SLEEP ENTRY"}, - {BIOS_VERSION_GUID, &bios_version, "BIOS VERSION"}, + {BIOS_VERSION_GUID, &sunway_bios_version, "BIOS VERSION"}, {}, }; @@ -107,7 +107,7 @@ static int __init uefi_init(u64 efi_system_table) out: early_memunmap(systab, sizeof(efi_system_table_t)); - if (!bios_version) + if (!sunway_bios_version) retval = -EINVAL; return retval; diff --git a/drivers/iommu/sw64/iommu_v2.c b/drivers/iommu/sw64/iommu_v2.c index d9e3b75e6c9e77be047c2b2b004078a1eb53fe80..bf4ff7d16d2af48650a11b00c7cf14e39023b61b 100644 --- a/drivers/iommu/sw64/iommu_v2.c +++ b/drivers/iommu/sw64/iommu_v2.c @@ -971,6 +971,10 @@ static int sunway_iommu_acpi_init(void) return ret; for_each_iommu(iommu) { + hose = find_hose_by_rcid(iommu->node, iommu->index); + if (!hose) + continue; + if (!iommu->enabled || hose->iommu_enable) continue; @@ -978,7 +982,6 @@ static int sunway_iommu_acpi_init(void) iommu_index); iommu_device_register(&iommu->iommu, &sunway_iommu_ops, NULL); iommu_index++; - hose = find_hose_by_rcid(iommu->node, iommu->index); sunway_enable_iommu_func(hose); hose->iommu_enable = true; piu_flush_all(iommu); diff --git a/drivers/irqchip/irq-sunway-cpu.c b/drivers/irqchip/irq-sunway-cpu.c index 4947805c33ab6ad17657c7b3225fc15c493039b4..5aeda6a673aa3273128b6c512601ee60f060a3be 100644 --- a/drivers/irqchip/irq-sunway-cpu.c +++ b/drivers/irqchip/irq-sunway-cpu.c @@ -39,60 +39,7 @@ struct fwnode_handle *cintc_handle; -static void handle_intx(unsigned int offset) -{ - struct pci_controller *hose; - unsigned long value; - void __iomem *piu_ior0_base; - - hose = hose_head; - offset <<= 7; - for (hose = hose_head; hose; hose = hose->next) { - piu_ior0_base = hose->piu_ior0_base; - - value = readq(piu_ior0_base + INTACONFIG + offset); - if (value >> 63) { - value = value & (~(1UL << 62)); - writeq(value, (piu_ior0_base + INTACONFIG + offset)); - handle_irq(hose->int_irq); - value = value | (1UL << 62); - writeq(value, (piu_ior0_base + INTACONFIG + offset)); - } - - if (IS_ENABLED(CONFIG_PCIE_PME)) { - value = readq(piu_ior0_base + PMEINTCONFIG); - if (value >> 63) { - handle_irq(hose->service_irq); - writeq(value, (piu_ior0_base + PMEINTCONFIG)); - } - } - - if (IS_ENABLED(CONFIG_PCIEAER)) { - value = readq(piu_ior0_base + AERERRINTCONFIG); - if (value >> 63) { - handle_irq(hose->service_irq); - writeq(value, (piu_ior0_base + AERERRINTCONFIG)); - } - } - - if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE_SUNWAY)) { - value = readq(piu_ior0_base + HPINTCONFIG); - if (value >> 63) { - handle_irq(hose->service_irq); - writeq(value, (piu_ior0_base + HPINTCONFIG)); - } - - } - - if (hose->iommu_enable) { - value = readq(piu_ior0_base + IOMMUEXCPT_STATUS); - if (value >> 63) - handle_irq(hose->int_irq); - } - } -} - -static void handle_device_interrupt(unsigned long irq_info) +static void handle_pci_intx_interrupt(unsigned long irq_info) { unsigned int i; @@ -101,7 +48,7 @@ static void handle_device_interrupt(unsigned long irq_info) return; } - for (i = 0; i < 4; i++) { + for (i = 0; i < PCI_NUM_INTX; i++) { if ((irq_info >> i) & 0x1) handle_intx(i); } @@ -144,15 +91,17 @@ asmlinkage void do_entInt(unsigned long type, unsigned long vector, nmi_enter(); old_regs = set_irq_regs(regs); -#ifdef CONFIG_SUBARCH_C4 - if (pme_state == PME_WFW) { - pme_state = PME_PENDING; - goto out; - } +#ifdef CONFIG_PM + if (is_junzhang_v1()) { + if (pme_state == PME_WFW) { + pme_state = PME_PENDING; + goto out; + } - if (pme_state == PME_PENDING) { - handle_device_interrupt(vector); - pme_state = PME_CLEAR; + if (pme_state == PME_PENDING) { + handle_pci_intx_interrupt(vector); + pme_state = PME_CLEAR; + } } #endif @@ -174,7 +123,7 @@ asmlinkage void do_entInt(unsigned long type, unsigned long vector, handle_pci_msi_interrupt(type, vector, irq_arg); goto out; case INT_INTx: - handle_device_interrupt(vector); + handle_pci_intx_interrupt(vector); goto out; case INT_IPI: diff --git a/drivers/irqchip/irq-sunway-pci-intx.c b/drivers/irqchip/irq-sunway-pci-intx.c index a60262fafeb301ca4271972192685c3481f45a99..bd108d58ff534152acad275022079c36549f852c 100644 --- a/drivers/irqchip/irq-sunway-pci-intx.c +++ b/drivers/irqchip/irq-sunway-pci-intx.c @@ -7,8 +7,27 @@ #include #include #include +#include + +#define PCI_INTXCONFIG_OFFSET 7 +#define PCI_INTTYPE_OFFSET 10 + +#if defined(CONFIG_SUBARCH_C3B) + #define PCI_INTDST_DOMAIN_ID_SHIFT 6 +#elif defined(CONFIG_SUBARCH_C4) + #define PCI_INTDST_DOMAIN_ID_SHIFT 7 +#endif + +#define PCI_INTDST_THREAD_ID_SHIFT 6 static DEFINE_RAW_SPINLOCK(legacy_lock); + +struct intx_chip_data { + struct pci_controller *hose; + unsigned long intxconfig[PCI_NUM_INTX]; + unsigned int offset; +}; + static void lock_legacy_lock(void) { raw_spin_lock(&legacy_lock); @@ -19,33 +38,31 @@ static void unlock_legacy_lock(void) raw_spin_unlock(&legacy_lock); } -static void set_intx(struct pci_controller *hose, unsigned long intx_conf) +struct intx_chip_data *alloc_intx_chip_data(u32 node) { - void __iomem *piu_ior0_base; + struct intx_chip_data *chip_data; - if (is_guest_or_emul()) - return; + if (WARN_ON(node >= MAX_NUMNODES)) + return NULL; - piu_ior0_base = hose->piu_ior0_base; + chip_data = kzalloc_node(sizeof(struct intx_chip_data), + GFP_KERNEL, node); - if (IS_ENABLED(CONFIG_SUBARCH_C3B)) { - writeq(intx_conf | (0x8UL << 10), (piu_ior0_base + INTACONFIG)); - writeq(intx_conf | (0x4UL << 10), (piu_ior0_base + INTBCONFIG)); - writeq(intx_conf | (0x2UL << 10), (piu_ior0_base + INTCCONFIG)); - writeq(intx_conf | (0x1UL << 10), (piu_ior0_base + INTDCONFIG)); - } else { - writeq(intx_conf | (0x8UL << 10), (piu_ior0_base + INTDCONFIG)); - writeq(intx_conf | (0x4UL << 10), (piu_ior0_base + INTCCONFIG)); - writeq(intx_conf | (0x2UL << 10), (piu_ior0_base + INTBCONFIG)); - writeq(intx_conf | (0x1UL << 10), (piu_ior0_base + INTACONFIG)); - } + return chip_data; } -static int __assign_piu_intx_config(struct pci_controller *hose, cpumask_t *targets) +static int __assign_piu_intx_config(struct intx_chip_data *chip_data, + cpumask_t *targets) { - unsigned long intx_conf; + struct pci_controller *hose; + unsigned long intxconfig; + void __iomem *piu_ior0_base; unsigned int cpu; int thread, node, core, rcid; + unsigned int i; + + if (is_guest_or_emul()) + return 0; /* Use the last cpu in valid cpus to avoid core 0. */ cpu = cpumask_last(targets); @@ -55,89 +72,83 @@ static int __assign_piu_intx_config(struct pci_controller *hose, cpumask_t *targ node = rcid_to_domain_id(rcid); core = rcid_to_core_id(rcid); - if (IS_ENABLED(CONFIG_SUBARCH_C3B)) - intx_conf = core | (node << 6); - else - intx_conf = core | (thread << 6) | (node << 7); + hose = chip_data->hose; + piu_ior0_base = hose->piu_ior0_base; - set_intx(hose, intx_conf); + for (i = 0; i < PCI_NUM_INTX; i++) { + intxconfig = chip_data->intxconfig[i]; + intxconfig &= ~PCI_INTX_INTDST_MASK; + if (IS_ENABLED(CONFIG_SUBARCH_C3B)) + intxconfig |= core | (node << PCI_INTDST_DOMAIN_ID_SHIFT); + else + intxconfig |= core | (thread << PCI_INTDST_THREAD_ID_SHIFT) + | (node << PCI_INTDST_DOMAIN_ID_SHIFT); + + writeq(intxconfig, piu_ior0_base + INTACONFIG + + (i << PCI_INTXCONFIG_OFFSET)); + chip_data->intxconfig[i] = intxconfig; + } return 0; } -static int assign_piu_intx_config(struct pci_controller *hose, cpumask_t *targets) +static int assign_piu_intx_config(struct intx_chip_data *chip_data, + cpumask_t *targets) { int ret; lock_legacy_lock(); - ret = __assign_piu_intx_config(hose, targets); + ret = __assign_piu_intx_config(chip_data, targets); unlock_legacy_lock(); return ret; } -static void intx_irq_enable(struct irq_data *irq_data) +static void set_intx_enable(struct irq_data *irq_data, u32 flag) { - struct pci_controller *hose = irq_data->chip_data; - unsigned long intx_conf; + struct intx_chip_data *chip_data = irq_data->chip_data; + struct pci_controller *hose; void __iomem *piu_ior0_base; + unsigned long intxconfig; + unsigned int i; - if (is_guest_or_emul()) + if (!chip_data) return; - BUG_ON(!hose); + hose = chip_data->hose; piu_ior0_base = hose->piu_ior0_base; - intx_conf = readq(piu_ior0_base + INTACONFIG); - intx_conf |= PCI_INTX_ENABLE; - writeq(intx_conf, (piu_ior0_base + INTACONFIG)); - - intx_conf = readq(piu_ior0_base + INTBCONFIG); - intx_conf |= PCI_INTX_ENABLE; - writeq(intx_conf, (piu_ior0_base + INTBCONFIG)); + for (i = 0; i < PCI_NUM_INTX; i++) { + intxconfig = chip_data->intxconfig[i]; + if (flag) + intxconfig |= PCI_INTX_ENABLE; + else + intxconfig &= PCI_INTX_DISABLE; + writeq(intxconfig, piu_ior0_base + INTACONFIG + + (i << PCI_INTXCONFIG_OFFSET)); + } +} - intx_conf = readq(piu_ior0_base + INTCCONFIG); - intx_conf |= PCI_INTX_ENABLE; - writeq(intx_conf, (piu_ior0_base + INTCCONFIG)); +static void intx_irq_enable(struct irq_data *irq_data) +{ + if (is_guest_or_emul()) + return; - intx_conf = readq(piu_ior0_base + INTDCONFIG); - intx_conf |= PCI_INTX_ENABLE; - writeq(intx_conf, (piu_ior0_base + INTDCONFIG)); + set_intx_enable(irq_data, 1); } static void intx_irq_disable(struct irq_data *irq_data) { - struct pci_controller *hose = irq_data->chip_data; - unsigned long intx_conf; - void __iomem *piu_ior0_base; - if (is_guest_or_emul()) return; - BUG_ON(!hose); - piu_ior0_base = hose->piu_ior0_base; - - intx_conf = readq(piu_ior0_base + INTACONFIG); - intx_conf &= PCI_INTX_DISABLE; - writeq(intx_conf, (piu_ior0_base + INTACONFIG)); - - intx_conf = readq(piu_ior0_base + INTBCONFIG); - intx_conf &= PCI_INTX_DISABLE; - writeq(intx_conf, (piu_ior0_base + INTBCONFIG)); - - intx_conf = readq(piu_ior0_base + INTCCONFIG); - intx_conf &= PCI_INTX_DISABLE; - writeq(intx_conf, (piu_ior0_base + INTCCONFIG)); - - intx_conf = readq(piu_ior0_base + INTDCONFIG); - intx_conf &= PCI_INTX_DISABLE; - writeq(intx_conf, (piu_ior0_base + INTDCONFIG)); + set_intx_enable(irq_data, 0); } static int intx_set_affinity(struct irq_data *irq_data, const struct cpumask *dest, bool force) { - struct pci_controller *hose = irq_data->chip_data; + struct intx_chip_data *chip_data = irq_data->chip_data; cpumask_t targets; int ret = 0; @@ -147,20 +158,63 @@ static int intx_set_affinity(struct irq_data *irq_data, cpumask_copy(&targets, dest); intx_irq_disable(irq_data); - ret = assign_piu_intx_config(hose, &targets); + ret = assign_piu_intx_config(chip_data, &targets); intx_irq_enable(irq_data); return ret; } +static void intx_mask_irq(struct irq_data *irq_data, u32 flag) +{ + struct intx_chip_data *chip_data = irq_data->chip_data; + struct pci_controller *hose; + void __iomem *piu_ior0_base; + unsigned long intxconfig; + unsigned int offset; + + if (!chip_data) + return; + + hose = chip_data->hose; + piu_ior0_base = hose->piu_ior0_base; + offset = chip_data->offset; + intxconfig = chip_data->intxconfig[offset]; + + if (flag) + intxconfig &= PCI_INTX_DISABLE; + else + intxconfig |= PCI_INTX_ENABLE; + + writeq(intxconfig, piu_ior0_base + INTACONFIG + + (offset << PCI_INTXCONFIG_OFFSET)); +} + +static void intx_irq_mask(struct irq_data *irq_data) +{ + if (is_guest_or_emul()) + return; + + intx_mask_irq(irq_data, 1); +} + +static void intx_irq_unmask(struct irq_data *irq_data) +{ + if (is_guest_or_emul()) + return; + + intx_mask_irq(irq_data, 0); +} + static void noop(struct irq_data *d) {} static struct irq_chip sw64_intx_chip = { - .name = "PCI_INTX", + .name = "PCI-INTX", .irq_enable = intx_irq_enable, .irq_disable = intx_irq_disable, - .irq_set_affinity = intx_set_affinity, - .irq_ack = noop, + .irq_mask = intx_irq_mask, + .irq_unmask = intx_irq_unmask, + .irq_set_affinity = intx_set_affinity, + .irq_ack = noop, .flags = IRQCHIP_SKIP_SET_WAKE, }; @@ -169,8 +223,12 @@ void __weak set_pcieport_service_irq(struct pci_controller *hose) {} void setup_intx_irqs(struct pci_controller *hose) { unsigned long irq, node, val_node; + struct intx_chip_data *chip_data; + void __iomem *piu_ior0_base; + int i = 0; node = hose->node; + piu_ior0_base = hose->piu_ior0_base; if (!node_online(node)) val_node = next_node_in(node, node_online_map); @@ -181,18 +239,90 @@ void setup_intx_irqs(struct pci_controller *hose) WARN_ON(irq < 0); irq_set_chip_and_handler(irq, &sw64_intx_chip, handle_level_irq); irq_set_status_flags(irq, IRQ_LEVEL); - irq_set_chip_data(irq, hose); + + chip_data = alloc_intx_chip_data(val_node); + if (!chip_data) + return; + + chip_data->hose = hose; + + for (i = 0; i < PCI_NUM_INTX; i++) { + if (IS_ENABLED(CONFIG_SUBARCH_C3B)) + chip_data->intxconfig[i] = (0x1UL << (3 - i)) << PCI_INTTYPE_OFFSET; + else + chip_data->intxconfig[i] = (0x1UL << i) << PCI_INTTYPE_OFFSET; + } + + irq_set_chip_data(irq, chip_data); hose->int_irq = irq; + irq_set_chip_and_handler(irq + 1, &dummy_irq_chip, handle_level_irq); hose->service_irq = irq + 1; set_pcieport_service_irq(hose); } -void __init sw64_init_irq(void) +void __init sunway_init_pci_intx(void) { struct pci_controller *hose = hose_head; for (hose = hose_head; hose; hose = hose->next) setup_intx_irqs(hose); } + +void handle_intx(unsigned int offset) +{ + struct irq_data *irq_data; + struct intx_chip_data *chip_data; + struct pci_controller *hose; + unsigned long value; + void __iomem *piu_ior0_base; + + hose = hose_head; + for (hose = hose_head; hose; hose = hose->next) { + piu_ior0_base = hose->piu_ior0_base; + + value = readq(piu_ior0_base + INTACONFIG + + (offset << PCI_INTXCONFIG_OFFSET)); + + if ((value & (PCI_INTX_VALID)) && (value & PCI_INTX_ENABLE)) { + irq_data = irq_get_irq_data(hose->int_irq); + if (irq_data) { + chip_data = irq_data->chip_data; + if (chip_data) + chip_data->offset = offset; + } + handle_irq(hose->int_irq); + } + + if (hose->iommu_enable) { + value = readq(piu_ior0_base + IOMMUEXCPT_STATUS); + if (value & PCI_INTX_VALID) + handle_irq(hose->int_irq); + } + + if (IS_ENABLED(CONFIG_PCIE_PME)) { + value = readq(piu_ior0_base + PMEINTCONFIG); + if (value & PCI_INTX_VALID) { + handle_irq(hose->service_irq); + writeq(value, (piu_ior0_base + PMEINTCONFIG)); + } + } + + if (IS_ENABLED(CONFIG_PCIEAER)) { + value = readq(piu_ior0_base + AERERRINTCONFIG); + if (value & PCI_INTX_VALID) { + handle_irq(hose->service_irq); + writeq(value, (piu_ior0_base + AERERRINTCONFIG)); + } + } + + if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE_SUNWAY)) { + value = readq(piu_ior0_base + HPINTCONFIG); + if (value & PCI_INTX_VALID) { + handle_irq(hose->service_irq); + writeq(value, (piu_ior0_base + HPINTCONFIG)); + } + } + } +} diff --git a/drivers/irqchip/irq-sunway-pintc.c b/drivers/irqchip/irq-sunway-pintc.c index eb7128b79c6fed4af5307bfc1d11bf1d976ed50d..934ad3d60607f99696b7c272006b0452b9ceeb87 100644 --- a/drivers/irqchip/irq-sunway-pintc.c +++ b/drivers/irqchip/irq-sunway-pintc.c @@ -84,6 +84,8 @@ struct pintc_chip_data { void __iomem *mcu_base; /* MCU/SPBU base address */ struct irq_chip *mcu_chip; u32 mcu_irq_num; + raw_spinlock_t pintc_lock; + raw_spinlock_t mcu_lock; }; static struct pintc_chip_data *chip_datas[MAX_NUMNODES]; @@ -97,9 +99,6 @@ static struct pintc_chip_data *pintc_alloc_chip_data(u32 node) chip_data = kzalloc_node(sizeof(struct pintc_chip_data), GFP_KERNEL, node); - if (!chip_data) - chip_data = kzalloc(sizeof(struct pintc_chip_data), - GFP_KERNEL); chip_datas[node] = chip_data; @@ -119,59 +118,82 @@ static void pintc_free_chip_data(struct pintc_chip_data *chip_data) kfree(chip_data); } -static DEFINE_RAW_SPINLOCK(pintc_lock); -static void lock_dev_lock(void) -{ - raw_spin_lock(&pintc_lock); -} - -static void unlock_dev_lock(void) -{ - raw_spin_unlock(&pintc_lock); -} - -static void mcu_irq_mask(struct irq_data *data) +static void mcu_irq_disable(struct irq_data *data) { struct pintc_chip_data *chip_data = data->chip_data; - unsigned long mask; + unsigned long mask, flags; int hwirq = data->hwirq; + raw_spin_lock_irqsave(&chip_data->mcu_lock, flags); + mask = readq(chip_data->mcu_base + OFFSET_MCU_DVC_INT_EN); mask &= ~(0x1UL << hwirq); writeq(mask, chip_data->mcu_base + OFFSET_MCU_DVC_INT_EN); + + raw_spin_unlock_irqrestore(&chip_data->mcu_lock, flags); } -static void mcu_irq_unmask(struct irq_data *data) +static void mcu_irq_enable(struct irq_data *data) { struct pintc_chip_data *chip_data = data->chip_data; - unsigned long mask; + unsigned long mask, flags; int hwirq = data->hwirq; + raw_spin_lock_irqsave(&chip_data->mcu_lock, flags); + mask = readq(chip_data->mcu_base + OFFSET_MCU_DVC_INT_EN); mask |= (0x1UL << hwirq); writeq(mask, chip_data->mcu_base + OFFSET_MCU_DVC_INT_EN); + + raw_spin_unlock_irqrestore(&chip_data->mcu_lock, flags); } -static void mcu_irq_enable(struct irq_data *irq_data) +static void pintc_mcu_enable(void __iomem *pintc_base) { - struct pintc_chip_data *chip_data = irq_data->chip_data; unsigned long devint_conf; - devint_conf = readq(chip_data->pintc_base + OFFSET_DEV_INT_CONFIG); + devint_conf = readq(pintc_base + OFFSET_DEV_INT_CONFIG); devint_conf |= (1UL << 8); - writeq(devint_conf, chip_data->pintc_base + OFFSET_DEV_INT_CONFIG); - mcu_irq_unmask(irq_data); + writeq(devint_conf, pintc_base + OFFSET_DEV_INT_CONFIG); } -static void mcu_irq_disable(struct irq_data *irq_data) +static void pintc_mcu_disable(void __iomem *pintc_base) { - struct pintc_chip_data *chip_data = irq_data->chip_data; unsigned long devint_conf; - devint_conf = readq(chip_data->pintc_base + OFFSET_DEV_INT_CONFIG); + devint_conf = readq(pintc_base + OFFSET_DEV_INT_CONFIG); devint_conf &= ~(1UL << 8); - writeq(devint_conf, chip_data->pintc_base + OFFSET_DEV_INT_CONFIG); - mcu_irq_mask(irq_data); + writeq(devint_conf, pintc_base + OFFSET_DEV_INT_CONFIG); +} + +static unsigned long +pintc_mcu_disable_and_save(struct pintc_chip_data *chip_data) +{ + unsigned long val; + + raw_spin_lock(&chip_data->pintc_lock); + + val = readq(chip_data->pintc_base + OFFSET_DEV_INT_CONFIG); + pintc_mcu_disable(chip_data->pintc_base); + + raw_spin_unlock(&chip_data->pintc_lock); + + return val & (1UL << 8); +} + +static void +pintc_mcu_restore(struct pintc_chip_data *chip_data, unsigned long val) +{ + unsigned long current_val; + + raw_spin_lock(&chip_data->pintc_lock); + + current_val = readq(chip_data->pintc_base + OFFSET_DEV_INT_CONFIG); + current_val &= ~(1UL << 8); + current_val |= val; + writeq(current_val, chip_data->pintc_base + OFFSET_DEV_INT_CONFIG); + + raw_spin_unlock(&chip_data->pintc_lock); } static unsigned long make_pintc_int_target(u32 version, int rcid) @@ -198,10 +220,30 @@ static unsigned long make_pintc_int_target(u32 version, int rcid) return target; } -static int __assign_mcu_irq_config(const struct pintc_chip_data *chip_data, +static void update_pintc_mcu_target(struct pintc_chip_data *chip_data, + unsigned long target) +{ + unsigned long val, flags; + + raw_spin_lock_irqsave(&chip_data->pintc_lock, flags); + + val = readq(chip_data->pintc_base + OFFSET_DEV_INT_CONFIG); + + /* Disable MCU irqs until affinity setting is completed */ + pintc_mcu_disable(chip_data->pintc_base); + + val &= 0xffff; + val |= (target << 16); + + writeq(val, chip_data->pintc_base + OFFSET_DEV_INT_CONFIG); + + raw_spin_unlock_irqrestore(&chip_data->pintc_lock, flags); +} + +static int assign_mcu_irq_config(struct pintc_chip_data *chip_data, cpumask_t *targets) { - unsigned long dev_int_tar, val; + unsigned long dev_int_tar; unsigned int cpu; int rcid; @@ -222,52 +264,32 @@ static int __assign_mcu_irq_config(const struct pintc_chip_data *chip_data, rcid = cpu_to_rcid(cpu); - val = readq(chip_data->pintc_base + OFFSET_DEV_INT_CONFIG); dev_int_tar = make_pintc_int_target(chip_data->version, rcid); - val &= 0xffff; - val |= dev_int_tar << 16; - writeq(val, chip_data->pintc_base + OFFSET_DEV_INT_CONFIG); + update_pintc_mcu_target(chip_data, dev_int_tar); return 0; } -static int assign_mcu_irq_config(const struct pintc_chip_data *chip_data, - cpumask_t *targets) -{ - int ret; - - lock_dev_lock(); - ret = __assign_mcu_irq_config(chip_data, targets); - unlock_dev_lock(); - - return ret; -} - static int mcu_irq_set_affinity(struct irq_data *irq_data, const struct cpumask *dest, bool force) { struct pintc_chip_data *chip_data = irq_data->chip_data; cpumask_t targets; - int ret = 0; if (cpumask_any_and(dest, cpu_online_mask) >= nr_cpu_ids) return -EINVAL; cpumask_and(&targets, dest, cpu_online_mask); - mcu_irq_disable(irq_data); - ret = assign_mcu_irq_config(chip_data, &targets); - mcu_irq_enable(irq_data); - - return ret; + return assign_mcu_irq_config(chip_data, &targets); } static struct irq_chip pintc_mcu_chip = { .name = "MCU-INT", .irq_enable = mcu_irq_enable, .irq_disable = mcu_irq_disable, - .irq_mask = mcu_irq_mask, - .irq_unmask = mcu_irq_unmask, + .irq_mask = mcu_irq_disable, + .irq_unmask = mcu_irq_enable, .irq_set_affinity = mcu_irq_set_affinity, }; @@ -381,6 +403,10 @@ static int __init pintc_init_mcu(struct pintc_chip_data *chip_data, &pintc_mcu_domain_ops, chip_data); /* Mask all interrupts for now */ writeq(0x0, chip_data->mcu_base + OFFSET_MCU_DVC_INT_EN); + + /* When building the root domain, move it to a better location */ + if (mcu_irq_domain) + pintc_mcu_enable(chip_data->pintc_base); } if (!mcu_irq_domain) { @@ -388,26 +414,25 @@ static int __init pintc_init_mcu(struct pintc_chip_data *chip_data, return -ENOMEM; } + raw_spin_lock_init(&chip_data->pintc_lock); + raw_spin_lock_init(&chip_data->mcu_lock); + pr_info(PREFIX "MCU version [%u] on node [%u] initialized\n", chip_data->version, chip_data->node); return 0; } +/* Currently, only MCU controller on node 0 is supported */ void handle_dev_int(struct pt_regs *regs) { - void __iomem *mcu_base, *intpu_base; - unsigned long config_val, val, stat; + unsigned long stat, val; unsigned int hwirq; - /* Currently, only MCU controller on node 0 is supported */ - mcu_base = chip_datas[0]->mcu_base; - intpu_base = chip_datas[0]->pintc_base; + /* Disable global irq of MCU due to some hardware reasons */ + val = pintc_mcu_disable_and_save(chip_datas[0]); - config_val = readq(intpu_base + OFFSET_DEV_INT_CONFIG); - val = config_val & (~(1UL << 8)); - writeq(val, intpu_base + OFFSET_DEV_INT_CONFIG); - stat = readq(mcu_base + OFFSET_MCU_DVC_INT); + stat = readq(chip_datas[0]->mcu_base + OFFSET_MCU_DVC_INT); while (stat) { hwirq = ffs(stat) - 1; @@ -415,7 +440,7 @@ void handle_dev_int(struct pt_regs *regs) stat &= ~(1UL << hwirq); } - writeq(config_val, intpu_base + OFFSET_DEV_INT_CONFIG); + pintc_mcu_restore(chip_datas[0], val); } void handle_fault_int(void) diff --git a/drivers/mfd/lpc_sunway.c b/drivers/mfd/lpc_sunway.c index a70971e7912d7d57dd43b3d0214d918f152d9d28..ebad6f2021454645ab65c5e1faf3b9550180757e 100644 --- a/drivers/mfd/lpc_sunway.c +++ b/drivers/mfd/lpc_sunway.c @@ -78,6 +78,10 @@ struct lpc_chip3_adapter { static struct resource superio_chip3_resources[] = { { .flags = IORESOURCE_IO, +#ifdef CONFIG_SUBARCH_C4 + .start = LPC_MEM_IO, + .end = LPC_MEM_IO + 0x10, +#endif } }; diff --git a/drivers/mfd/sunway_ast2400.c b/drivers/mfd/sunway_ast2400.c index 4e1e3e3d21e2938fcbb17f9996a912ba855065f9..5fd7fc951c967a5e0616feeeb4f42f6060e632d4 100644 --- a/drivers/mfd/sunway_ast2400.c +++ b/drivers/mfd/sunway_ast2400.c @@ -163,7 +163,7 @@ static int superio_ast2400_probe(struct platform_device *pdev) return err; } - res = platform_get_resource(pdev, IORESOURCE_IO, 1); + res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (res) { physaddr = res->start; dev_info(&pdev->dev, "request memory region %pR\n", res); @@ -171,8 +171,8 @@ static int superio_ast2400_probe(struct platform_device *pdev) superio_device->dev = &pdev->dev; superio_device->enabled = 1; - superio_device->superio_ast2400_efir = physaddr + SUPERIO_PNP_PORT; - superio_device->superio_ast2400_efdr = physaddr + SUPERIO_PNP_PORT + 1; + superio_device->superio_ast2400_efir = physaddr + (SUPERIO_PNP_PORT << PORT_OFFSET); + superio_device->superio_ast2400_efdr = physaddr + ((SUPERIO_PNP_PORT + 1) << PORT_OFFSET); superio_uart0_irq = platform_get_irq_byname(pdev, "uart0_irq"); superio_uart1_irq = platform_get_irq_byname(pdev, "uart1_irq"); diff --git a/drivers/platform/sw64/Makefile b/drivers/platform/sw64/Makefile index 84ba9957a9ce955ce48fcd0545393bae53fcdc32..65dead29600ec6e0061650dd689551800fd543da 100644 --- a/drivers/platform/sw64/Makefile +++ b/drivers/platform/sw64/Makefile @@ -1,4 +1,2 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_PLATFORM_XUELANG) += legacy_xuelang.o -obj-$(CONFIG_PLATFORM_JUNZHANG) += legacy_junzhang.o obj-y += misc-platform.o diff --git a/drivers/platform/sw64/legacy_junzhang.c b/drivers/platform/sw64/legacy_junzhang.c deleted file mode 100644 index 17d6d151d0b8a51b049041c7d5205db1d655ede7..0000000000000000000000000000000000000000 --- a/drivers/platform/sw64/legacy_junzhang.c +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include -#include - -static void vt_mode_kill_arch(int mode) -{ - hcall(HCALL_SET_CLOCKEVENT, 0, 0, 0); - - switch (mode) { - case LINUX_REBOOT_CMD_RESTART: - hcall(HCALL_RESTART, 0, 0, 0); - mb(); - break; - case LINUX_REBOOT_CMD_HALT: - case LINUX_REBOOT_CMD_POWER_OFF: - hcall(HCALL_SHUTDOWN, 0, 0, 0); - mb(); - break; - default: - break; - } -} - -void sw64_halt(void) -{ - if (is_in_host()) - cpld_write(0x64, 0x00, 0xf0); - else - vt_mode_kill_arch(LINUX_REBOOT_CMD_HALT); -} - -void sw64_poweroff(void) -{ - if (is_in_host()) - cpld_write(0x64, 0x00, 0xf0); - else - vt_mode_kill_arch(LINUX_REBOOT_CMD_POWER_OFF); -} - -void sw64_restart(void) -{ - if (is_in_host()) { - fix_jm585_reset(); - cpld_write(0x64, 0x00, 0xc3); - } else - vt_mode_kill_arch(LINUX_REBOOT_CMD_RESTART); -} - -static int sw64_reset_init(void) -{ -#ifdef CONFIG_EFI - if (BIOS_SUPPORT_RESET_CLALLBACK((void *)bios_version)) - return 0; -#endif - pm_restart = sw64_restart; - pm_power_off = sw64_poweroff; - pm_halt = sw64_halt; - return 0; -} -subsys_initcall(sw64_reset_init); diff --git a/drivers/platform/sw64/legacy_xuelang.c b/drivers/platform/sw64/legacy_xuelang.c deleted file mode 100644 index 8a63d9edf9f230a6137c28e641c966aa5b72d16b..0000000000000000000000000000000000000000 --- a/drivers/platform/sw64/legacy_xuelang.c +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -#include -#include - -static void vt_mode_kill_arch(int mode) -{ - hcall(HCALL_SET_CLOCKEVENT, 0, 0, 0); - - switch (mode) { - case LINUX_REBOOT_CMD_RESTART: - hcall(HCALL_RESTART, 0, 0, 0); - mb(); - break; - case LINUX_REBOOT_CMD_HALT: - case LINUX_REBOOT_CMD_POWER_OFF: - hcall(HCALL_SHUTDOWN, 0, 0, 0); - mb(); - break; - default: - break; - } -} - -void sw64_halt(void) -{ - if (is_in_host()) - cpld_write(0x64, 0x00, 0xf0); - else - vt_mode_kill_arch(LINUX_REBOOT_CMD_HALT); -} - -void sw64_poweroff(void) -{ - if (is_in_host()) - cpld_write(0x64, 0x00, 0xf0); - else - vt_mode_kill_arch(LINUX_REBOOT_CMD_POWER_OFF); -} - -void sw64_restart(void) -{ - if (is_in_host()) { - fix_jm585_reset(); - cpld_write(0x64, 0x00, 0xc3); - } else - vt_mode_kill_arch(LINUX_REBOOT_CMD_RESTART); -} - -static int sw64_reset_init(void) -{ -#ifdef CONFIG_EFI - if (BIOS_SUPPORT_RESET_CLALLBACK((void *)bios_version)) - return 0; -#endif - pm_restart = sw64_restart; - pm_power_off = sw64_poweroff; - pm_halt = sw64_halt; - return 0; -} -subsys_initcall(sw64_reset_init); diff --git a/drivers/spi/spi-sunway.c b/drivers/spi/spi-sunway.c index 6133173ea09aefa1d91c9744ecf70f191b54950a..37de04209c3b09a01ca009df5795a06f8a3adeb3 100644 --- a/drivers/spi/spi-sunway.c +++ b/drivers/spi/spi-sunway.c @@ -350,7 +350,7 @@ int spi_chip_add_host(struct device *dev, struct spi_chip *spi_chip) master->handle_err = spi_chip_handle_err; master->max_speed_hz = spi_chip->max_freq; master->dev.of_node = dev->of_node; - master->flags = SPI_MASTER_GPIO_SS; + master->flags = SPI_CONTROLLER_GPIO_SS; master->max_transfer_size = spi_chip_max_length; master->max_message_size = spi_chip_max_length; diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h index 9b731976ce2fde51d7a3c54358d9c1380604212c..52a2ea81256e3df68777998313a806bedc820870 100644 --- a/include/uapi/linux/elf.h +++ b/include/uapi/linux/elf.h @@ -454,6 +454,7 @@ typedef struct elf64_shdr { #define NT_LOONGARCH_LBT 0xa04 /* LoongArch Loongson Binary Translation registers */ #define NT_LOONGARCH_HW_BREAK 0xa05 /* LoongArch hardware breakpoint registers */ #define NT_LOONGARCH_HW_WATCH 0xa06 /* LoongArch hardware watchpoint registers */ +#define NT_SW64_SYSTEM_CALL 0x7f00 /* SW64 system call number */ /* Note types with note name "GNU" */ #define NT_GNU_PROPERTY_TYPE_0 5 diff --git a/tools/arch/sw_64/include/uapi/asm/bpf_perf_event.h b/tools/arch/sw_64/include/uapi/asm/bpf_perf_event.h new file mode 100644 index 0000000000000000000000000000000000000000..52f6f1e555f162ef7668965386cc758125726224 --- /dev/null +++ b/tools/arch/sw_64/include/uapi/asm/bpf_perf_event.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _UAPI_ASM_SW64_BPF_PERF_EVENT_H +#define _UAPI_ASM_SW64_BPF_PERF_EVENT_H + +#include + +typedef struct user_pt_regs bpf_user_pt_regs_t; + +#endif /* _UAPI_ASM_SW64_BPF_PERF_EVENT_H */ diff --git a/tools/include/uapi/asm/bpf_perf_event.h b/tools/include/uapi/asm/bpf_perf_event.h index ff52668abf8cfbc5103fc203a25b8ffe9fdb15c7..8f95170bf4d58ba7072b08d7b164db5c988f3711 100644 --- a/tools/include/uapi/asm/bpf_perf_event.h +++ b/tools/include/uapi/asm/bpf_perf_event.h @@ -8,6 +8,8 @@ #include "../../arch/riscv/include/uapi/asm/bpf_perf_event.h" #elif defined(__loongarch__) #include "../../arch/loongarch/include/uapi/asm/bpf_perf_event.h" +#elif defined(__sw_64__) +#include "../../arch/sw_64/include/uapi/asm/bpf_perf_event.h" #else #include #endif diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c index af46488e4ea9530b1478ae4932c5b89275e90f7c..04ccbd5b2d0dde18067244ca55b634dc3e5aafcd 100644 --- a/tools/lib/bpf/bpf.c +++ b/tools/lib/bpf/bpf.c @@ -59,6 +59,8 @@ # define __NR_bpf 6319 # elif defined(__mips__) && defined(_ABI64) # define __NR_bpf 5315 +# elif defined(__sw_64__) +# define __NR_bpf 170 # else # error __NR_bpf not defined. libbpf does not support your arch. # endif diff --git a/tools/lib/bpf/bpf_tracing.h b/tools/lib/bpf/bpf_tracing.h index 1c13f8e88833b445f48ff05fb04bfaf7deeeb6b6..8d34cb534ca672ac46931372b027e8d78f9929ee 100644 --- a/tools/lib/bpf/bpf_tracing.h +++ b/tools/lib/bpf/bpf_tracing.h @@ -35,6 +35,9 @@ #elif defined(__TARGET_ARCH_loongarch) #define bpf_target_loongarch #define bpf_target_defined +#elif defined(__TARGET_ARCH_sw_64) + #define bpf_target_sw64 + #define bpf_target_defined #else /* Fall back to what the compiler says */ @@ -68,6 +71,9 @@ #elif defined(__loongarch__) #define bpf_target_loongarch #define bpf_target_defined +#elif defined(__sw_64__) + #define bpf_target_sw64 + #define bpf_target_defined #endif /* no compiler target */ #endif @@ -441,6 +447,34 @@ struct pt_regs___arm64 { #define __PT_SP_REG regs[3] #define __PT_IP_REG csr_era +#elif defined(bpf_target_sw64) + +/* sw64 provides struct user_pt_regs instead of struct pt_regs to userspace */ +struct pt_regs; +#define PT_REGS_SW64 const volatile struct user_pt_regs +#define PT_REGS_PARM1(x) (((PT_REGS_SW64 *)(x))->regs[16]) +#define PT_REGS_PARM2(x) (((PT_REGS_SW64 *)(x))->regs[17]) +#define PT_REGS_PARM3(x) (((PT_REGS_SW64 *)(x))->regs[18]) +#define PT_REGS_PARM4(x) (((PT_REGS_SW64 *)(x))->regs[19]) +#define PT_REGS_PARM5(x) (((PT_REGS_SW64 *)(x))->regs[20]) +#define PT_REGS_RET(x) (((PT_REGS_SW64 *)(x))->regs[26]) +/* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_FP(x) (((PT_REGS_SW64 *)(x))->regs[15]) +#define PT_REGS_RC(x) (((PT_REGS_SW64 *)(x))->regs[0]) +#define PT_REGS_SP(x) (((PT_REGS_SW64 *)(x))->regs[30]) +#define PT_REGS_IP(x) (((PT_REGS_SW64 *)(x))->pc) + +#define PT_REGS_PARM1_CORE(x) BPF_CORE_READ((PT_REGS_SW64 *)(x), regs[16]) +#define PT_REGS_PARM2_CORE(x) BPF_CORE_READ((PT_REGS_SW64 *)(x), regs[17]) +#define PT_REGS_PARM3_CORE(x) BPF_CORE_READ((PT_REGS_SW64 *)(x), regs[18]) +#define PT_REGS_PARM4_CORE(x) BPF_CORE_READ((PT_REGS_SW64 *)(x), regs[19]) +#define PT_REGS_PARM5_CORE(x) BPF_CORE_READ((PT_REGS_SW64 *)(x), regs[20]) +#define PT_REGS_RET_CORE(x) BPF_CORE_READ((PT_REGS_SW64 *)(x), regs[26]) +#define PT_REGS_FP_CORE(x) BPF_CORE_READ((PT_REGS_SW64 *)(x), regs[15]) +#define PT_REGS_RC_CORE(x) BPF_CORE_READ((PT_REGS_SW64 *)(x), regs[0]) +#define PT_REGS_SP_CORE(x) BPF_CORE_READ((PT_REGS_SW64 *)(x), regs[30]) +#define PT_REGS_IP_CORE(x) BPF_CORE_READ((PT_REGS_SW64 *)(x), pc) + #endif #if defined(bpf_target_defined)