diff --git a/arch/sw_64/Kconfig b/arch/sw_64/Kconfig index 5d14dde720f5cd6ac350fdab6f897d99e763402d..a5a6c0fd87bdcbae6163f57751a04278779c98ae 100644 --- a/arch/sw_64/Kconfig +++ b/arch/sw_64/Kconfig @@ -43,6 +43,7 @@ config SW64 select ARCH_INLINE_WRITE_UNLOCK_BH select ARCH_INLINE_WRITE_UNLOCK_IRQ select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE + select ARCH_KEEP_MEMBLOCK select ARCH_NO_PREEMPT select ARCH_SUPPORTS_ACPI select ARCH_SUPPORTS_ATOMIC_RMW @@ -67,6 +68,7 @@ config SW64 select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNLEN_USER select GENERIC_TIME_VSYSCALL + select GPIOLIB if ACPI select HANDLE_DOMAIN_IRQ select HARDIRQS_SW_RESEND select HAVE_ARCH_AUDITSYSCALL @@ -448,6 +450,7 @@ config NUMA bool "NUMA Support" depends on SMP && !FLATMEM select ACPI_NUMA if ACPI + select OF_NUMA help Say Y to compile the kernel to support NUMA (Non-Uniform Memory Access). This option is for configuring high-end multiprocessor @@ -533,6 +536,7 @@ menu "Boot options" config BUILTIN_DTB bool "Embed DTB in kernel image" depends on OF + depends on SUBARCH_C3B default n help Embeds a device tree binary in the kernel image. diff --git a/arch/sw_64/boot/dts/chip3.dts b/arch/sw_64/boot/dts/chip3.dts index 8e93c76fe6d1665c6e2bcc9e1d8810a031ac7f90..fecb0f0f3be7510a2364ffbd68ea9f33558b0a7d 100644 --- a/arch/sw_64/boot/dts/chip3.dts +++ b/arch/sw_64/boot/dts/chip3.dts @@ -140,7 +140,7 @@ pvt: pvt@0x8030 { spi: spi@0x8032 { #address-cells = <1>; #size-cells = <0>; - compatible = "sunway,chip3-spi"; + compatible = "sunway,chip-spi"; reg = <0x8032 0x0 0x0 0x8000>; clocks = <&spiclk>; poll_mode = <1>; /* poll_mode:1 interrupt mode: 0 */ diff --git a/arch/sw_64/configs/junzhang_defconfig b/arch/sw_64/configs/junzhang_defconfig index 0dbd636daabd2a28c46a78f7ea63bdff6f7480d8..f639cbb17e430d9d6b2e543993d1eb2e66881993 100644 --- a/arch/sw_64/configs/junzhang_defconfig +++ b/arch/sw_64/configs/junzhang_defconfig @@ -541,9 +541,13 @@ CONFIG_VIRTIO_CONSOLE=y # CONFIG_HW_RANDOM is not set # CONFIG_DEVPORT 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_SPI=y +CONFIG_SPI_CHIP=y +CONFIG_SPI_CHIP_MMIO=y CONFIG_SPI_SPIDEV=y CONFIG_SENSORS_PVT=y CONFIG_SENSORS_LM75=y diff --git a/arch/sw_64/include/asm/core.h b/arch/sw_64/include/asm/core.h index 3f4df6d6c92deb6167212f3d18056956228982f0..2d579b50323578a69a604ec791af5349ad34ec6f 100644 --- a/arch/sw_64/include/asm/core.h +++ b/arch/sw_64/include/asm/core.h @@ -78,6 +78,7 @@ static inline bool core_is_ht(void) extern void entArith(void); extern void entIF(void); extern void entInt(void); +extern void entNMI(void); extern void entMM(void); extern void entSys(void); extern void entUna(void); diff --git a/arch/sw_64/include/asm/csr.h b/arch/sw_64/include/asm/csr.h index 9a089f9d4ad016ecdc8872aaf7dad6ec7b28a5ba..dac5b6a29b47e79215eaef027fe6a2c2c27b4a7e 100644 --- a/arch/sw_64/include/asm/csr.h +++ b/arch/sw_64/include/asm/csr.h @@ -55,6 +55,9 @@ #define CSR_IDA_MATCH 0xc5 #define CSR_IDA_MASK 0xc6 #define CSR_BASE_KREGS 0xe0 +#define CSR_NMI_STACK 0xe5 +#define CSR_NMI_SCRATCH 0xe6 +#define CSR_NMI_MASK 0xe7 #define CSR_PS 0xe8 #define CSR_PC 0xe9 #define CSR_EARG0 0xea @@ -63,6 +66,7 @@ #define CSR_SCRATCH 0xed #define CSR_SP 0xee #define CSR_KTP 0xef +#define CSR_CAUSE 0xf0 #define DA_MATCH_EN_S 4 #define DV_MATCH_EN_S 6 @@ -82,7 +86,8 @@ static inline unsigned long sw64_read_csr(unsigned long x) { unsigned long __val; - __asm__ __volatile__("csrr %0,%1" : "=r"(__val) : "i"(x)); + + __asm__ __volatile__("csrr %0,%1; csrr %0,%1" : "=r"(__val) : "i"(x)); return __val; } diff --git a/arch/sw_64/include/asm/hmcall.h b/arch/sw_64/include/asm/hmcall.h index ae52b220fa38ae4b50be13bb13fafe5947b36e85..dcb654173e82ac903fcf65125d2085d20684c746 100644 --- a/arch/sw_64/include/asm/hmcall.h +++ b/arch/sw_64/include/asm/hmcall.h @@ -44,6 +44,9 @@ #define HMC_sendii 0x3E #define HMC_rti 0x3F +/* 0x40 - 0x7F : Hypervisor Level HMC routine */ +#define HMC_rti_nmi 0x40 +#define HMC_setup_nmi 0x41 /* 0x80 - 0xBF : User Level HMC routine */ #include @@ -185,6 +188,7 @@ __CALL_HMC_RW1(rdio64, unsigned long, unsigned long); __CALL_HMC_RW1(rdio32, unsigned int, unsigned long); __CALL_HMC_W2(wrent, void*, unsigned long); __CALL_HMC_W2(tbisasid, unsigned long, unsigned long); +__CALL_HMC_W2(setup_nmi, unsigned long, unsigned long); __CALL_HMC_W1(wrkgp, unsigned long); __CALL_HMC_RW2(wrperfmon, unsigned long, unsigned long, unsigned long); __CALL_HMC_RW3(sendii, unsigned long, unsigned long, unsigned long, unsigned long); diff --git a/arch/sw_64/include/asm/kvm_host.h b/arch/sw_64/include/asm/kvm_host.h index c664bf232ccc53b797cabe23ffc979bebb683474..48d0c0bea7033da9394be3755389e8e6bb99cdfc 100644 --- a/arch/sw_64/include/asm/kvm_host.h +++ b/arch/sw_64/include/asm/kvm_host.h @@ -33,18 +33,19 @@ #ifdef CONFIG_SUBARCH_C3B #define VPN_BITS 8 #define GUEST_RESET_PC 0xffffffff80011100 +#define KVM_MAX_VCPUS 64 #endif #ifdef CONFIG_SUBARCH_C4 #define VPN_BITS 10 #define GUEST_RESET_PC 0xfff0000000011002 +#define KVM_MAX_VCPUS 256 #endif #define VPN_FIRST_VERSION (1UL << VPN_BITS) #define VPN_MASK ((1UL << VPN_BITS) - 1) #define VPN_SHIFT (64 - VPN_BITS) -#define KVM_MAX_VCPUS 64 #define KVM_USER_MEM_SLOTS 512 #define KVM_HALT_POLL_NS_DEFAULT 0 diff --git a/arch/sw_64/include/asm/ptrace.h b/arch/sw_64/include/asm/ptrace.h index 83d9a256b0a98ab8775e0d1ab1c5f5fbf8d773b0..1f9371722488615541d9d04d645ff7f538be839b 100644 --- a/arch/sw_64/include/asm/ptrace.h +++ b/arch/sw_64/include/asm/ptrace.h @@ -27,6 +27,7 @@ struct pt_regs { }; unsigned long orig_r0; unsigned long orig_r19; + unsigned long cause; /* These are saved by HMcode: */ unsigned long hm_ps; unsigned long hm_pc; diff --git a/arch/sw_64/include/asm/smp.h b/arch/sw_64/include/asm/smp.h index 097f22b72c2575d5b2e3cd6773eb5e3887a6247c..33a73ca25a6b28c3f6c9f1134f892dde24ba3df8 100644 --- a/arch/sw_64/include/asm/smp.h +++ b/arch/sw_64/include/asm/smp.h @@ -36,6 +36,8 @@ struct smp_rcb_struct { unsigned long init_done; }; +extern bool __init is_rcid_duplicate(int rcid); + #ifdef CONFIG_SMP /* SMP initialization hook for setup_arch */ void __init setup_smp(void); @@ -90,6 +92,9 @@ extern int get_thread_id_from_rcid(int rcid); extern int get_domain_id_from_rcid(int rcid); #else /* CONFIG_SMP */ + +static inline void __init setup_smp(void) { store_cpu_data(0); } + #define hard_smp_processor_id() 0 #define smp_call_function_on_cpu(func, info, wait, cpu) ({ 0; }) /* The map from sequential logical cpu number to hard cid. */ @@ -108,6 +113,7 @@ static inline void rcid_information_init(int core_version) { } static inline int get_core_id_from_rcid(int rcid) { return 0; } static inline int get_thread_id_from_rcid(int rcid) { return 0; } static inline int get_domain_id_from_rcid(int rcid) { return 0; } + #endif /* CONFIG_SMP */ #define NO_PROC_ID (-1) @@ -116,12 +122,12 @@ static inline void send_ipi(int cpu, unsigned long type) { int rcid; - rcid = cpu_to_rcid(cpu); - if (is_in_guest()) - hcall(HCALL_IVI, rcid, type, 0); - else + hcall(HCALL_IVI, cpu, type, 0); + else { + rcid = cpu_to_rcid(cpu); sendii(rcid, type, 0); + } } #define reset_cpu(cpu) send_ipi((cpu), II_RESET) diff --git a/arch/sw_64/include/asm/uncore_io_junzhang.h b/arch/sw_64/include/asm/uncore_io_junzhang.h index 8c14890e5c1dd585c83e2d04cb4a92b3160643e8..f553d2f61e64a1a34b3a35a73cfe20452b927572 100644 --- a/arch/sw_64/include/asm/uncore_io_junzhang.h +++ b/arch/sw_64/include/asm/uncore_io_junzhang.h @@ -62,9 +62,12 @@ #define LPC_FIRMWARE_IO (0x3UL << 28 | IO_BASE | LPC_BASE) #define PCI_VT_LEGACY_IO (IO_BASE | PCI_BASE | PCI_LEGACY_IO) -#define PME_ENABLE_INTD_CORE0 (0x1UL << 62 | 0x8UL << 10) -#define AER_ENABLE_INTD_CORE0 (0x1UL << 62 | 0x8UL << 10) -#define HP_ENABLE_INTD_CORE0 (0x1UL << 62 | 0x8UL << 10) +#define CORE0_CID (rcid_to_domain_id(cpu_to_rcid(0)) << 7 | \ + rcid_to_thread_id(cpu_to_rcid(0)) << 6 | \ + rcid_to_core_id(cpu_to_rcid(0))) +#define PME_ENABLE_INTD_CORE0 (0x1UL << 62 | 0x8UL << 10 | CORE0_CID) +#define AER_ENABLE_INTD_CORE0 (0x1UL << 62 | 0x8UL << 10 | CORE0_CID) +#define HP_ENABLE_INTD_CORE0 (0x1UL << 62 | 0x8UL << 10 | CORE0_CID) #define PIUCONFIG0_INIT_VAL 0x38016 @@ -97,6 +100,7 @@ enum { /* SPBU CSR */ enum { SMP_INFO = SPBU_BASE | 0x80UL, + VT_ONLINE_CPU = SPBU_BASE | 0x100UL, INIT_CTL = SPBU_BASE | 0x680UL, CORE_ONLINE = SPBU_BASE | 0x780UL, DLI_RLTD_FAULT = SPBU_BASE | 0x980UL, diff --git a/arch/sw_64/include/asm/uncore_io_xuelang.h b/arch/sw_64/include/asm/uncore_io_xuelang.h index 695ce68dded9c32ca14704a4f15155125a02f5a0..7a8c9edc8bfb46d8cae786c4c17b1c05147668bd 100644 --- a/arch/sw_64/include/asm/uncore_io_xuelang.h +++ b/arch/sw_64/include/asm/uncore_io_xuelang.h @@ -66,8 +66,10 @@ #define DLI_PHY_CTL (0x10UL << 24) #define PCI_VT_LEGACY_IO (IO_BASE | PCI_BASE | PCI_LEGACY_IO) -#define PME_ENABLE_INTD_CORE0 (0x1UL << 62 | 0x1UL << 10) -#define AER_ENABLE_INTD_CORE0 (0x1UL << 62 | 0x1UL << 10) +#define CORE0_CID (rcid_to_domain_id(cpu_to_rcid(0)) << 6 | \ + rcid_to_core_id(cpu_to_rcid(0))) +#define PME_ENABLE_INTD_CORE0 (0x1UL << 62 | 0x1UL << 10 | CORE0_CID) +#define AER_ENABLE_INTD_CORE0 (0x1UL << 62 | 0x1UL << 10 | CORE0_CID) #define PIUCONFIG0_INIT_VAL 0x38056 diff --git a/arch/sw_64/include/asm/vcpu.h b/arch/sw_64/include/asm/vcpu.h index 8227166d6998030d6a66798cc1b4670a7778967e..b2ab8c7f8b865bf0b40cd99023df466367021bcb 100644 --- a/arch/sw_64/include/asm/vcpu.h +++ b/arch/sw_64/include/asm/vcpu.h @@ -97,9 +97,9 @@ struct vcpucb { unsigned long exit_reason; unsigned long fault_gpa; /* CSR:EXC_GPA */ unsigned long vcpu_pc_save; - unsigned long shtclock_offset; unsigned long migration_mark; unsigned long shtclock; + unsigned long shtclock_offset; unsigned long csr_pc; unsigned long csr_ps; unsigned long csr_sp; diff --git a/arch/sw_64/kernel/acpi.c b/arch/sw_64/kernel/acpi.c index 70be2cf59f856994779d50574a02f01d4147b7ad..0126bf7290b70fb30e9eed294fd980374b766dd7 100644 --- a/arch/sw_64/kernel/acpi.c +++ b/arch/sw_64/kernel/acpi.c @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -223,7 +224,7 @@ int acpi_unmap_cpu(int cpu) EXPORT_SYMBOL(acpi_unmap_cpu); #endif /* CONFIG_ACPI_HOTPLUG_CPU */ -static bool __init is_rcid_duplicate(int rcid) +bool __init is_rcid_duplicate(int rcid) { int i; @@ -246,14 +247,14 @@ setup_rcid_and_core_mask(struct acpi_madt_sw_cintc *sw_cintc) * represents the maximum number of cores in the system. */ if (possible_cores >= nr_cpu_ids) { - pr_err(PREFIX "Max core num [%u] reached, core [0x%x] ignored\n", - nr_cpu_ids, rcid); + pr_err(PREFIX "Core [0x%x] exceeds max core num [%u]\n", + rcid, nr_cpu_ids); return -ENODEV; } /* The rcid of each core is unique */ if (is_rcid_duplicate(rcid)) { - pr_err(PREFIX "Duplicate core [0x%x] in MADT\n", rcid); + pr_err(PREFIX "Duplicate core [0x%x]\n", rcid); return -EINVAL; } @@ -328,6 +329,17 @@ static int __init acpi_process_madt_sw_cintc(void) init_cpu_possible(cpu_none_mask); init_cpu_present(cpu_none_mask); +#ifdef CONFIG_SUBARCH_C4 + /* Set cpu_offline mask */ + if (is_guest_or_emul()) { + int vt_smp_cpu_num; + + vt_smp_cpu_num = sw64_io_read(0, VT_ONLINE_CPU); + for (i = vt_smp_cpu_num; i < KVM_MAX_VCPUS; i++) + cpumask_set_cpu(i, &cpu_offline); + } +#endif + /* Parse SW CINTC entries one by one */ ret = acpi_table_parse_madt(ACPI_MADT_TYPE_SW_CINTC, acpi_parse_sw_cintc, 0); diff --git a/arch/sw_64/kernel/asm-offsets.c b/arch/sw_64/kernel/asm-offsets.c index 1130dbb71b3d8f4b574bbde72c7a05756c721a08..5b0c2187ab5aaa551c2807db5644fb00ee3290f8 100644 --- a/arch/sw_64/kernel/asm-offsets.c +++ b/arch/sw_64/kernel/asm-offsets.c @@ -104,6 +104,7 @@ void foo(void) DEFINE(PT_REGS_PS, offsetof(struct pt_regs, ps)); DEFINE(PT_REGS_ORIG_R0, offsetof(struct pt_regs, orig_r0)); DEFINE(PT_REGS_ORIG_R19, offsetof(struct pt_regs, orig_r19)); + DEFINE(PT_REGS_CAUSE, offsetof(struct pt_regs, cause)); DEFINE(PT_REGS_HM_PS, offsetof(struct pt_regs, hm_ps)); DEFINE(PT_REGS_HM_PC, offsetof(struct pt_regs, hm_pc)); DEFINE(PT_REGS_HM_GP, offsetof(struct pt_regs, hm_gp)); diff --git a/arch/sw_64/kernel/cpuautoplug.c b/arch/sw_64/kernel/cpuautoplug.c index 4333747dc51fba8b3c76b8057123813dc18bc738..fcac5fa27244d8b6b77ff602aa7b00146dcdeeaa 100644 --- a/arch/sw_64/kernel/cpuautoplug.c +++ b/arch/sw_64/kernel/cpuautoplug.c @@ -492,15 +492,4 @@ static int __init cpuautoplug_init(void) return ret; } - -static void __exit cpuautoplug_exit(void) -{ - cancel_delayed_work_sync(&ap_info.work); - platform_driver_unregister(&platform_driver); - sysfs_remove_group(&cpu_subsys.dev_root->kobj, &cpuclass_attr_group); -} - late_initcall(cpuautoplug_init); -module_exit(cpuautoplug_exit); - -MODULE_DESCRIPTION("cpuautoplug driver for SW64"); diff --git a/arch/sw_64/kernel/entry_c4.S b/arch/sw_64/kernel/entry_c4.S index c31143645b6f982deba3fe3769aaa7f9534d6114..219016ef05b20f57bf60e83b0015ff7434bd2e2d 100644 --- a/arch/sw_64/kernel/entry_c4.S +++ b/arch/sw_64/kernel/entry_c4.S @@ -14,6 +14,123 @@ .text .set noat + .macro SAVE_ALL_NMI + csrw $sp, CSR_NMI_SCRATCH + csrr $sp, CSR_NMI_STACK + + ldi $sp, -PT_REGS_SIZE($sp) + stl $0, PT_REGS_R0($sp) + stl $1, PT_REGS_R1($sp) + stl $2, PT_REGS_R2($sp) + stl $3, PT_REGS_R3($sp) + stl $4, PT_REGS_R4($sp) + stl $5, PT_REGS_R5($sp) + stl $6, PT_REGS_R6($sp) + stl $7, PT_REGS_R7($sp) + stl $8, PT_REGS_R8($sp) + stl $9, PT_REGS_R9($sp) + stl $10, PT_REGS_R10($sp) + stl $11, PT_REGS_R11($sp) + stl $12, PT_REGS_R12($sp) + stl $13, PT_REGS_R13($sp) + stl $14, PT_REGS_R14($sp) + stl $15, PT_REGS_R15($sp) + stl $16, PT_REGS_R16($sp) + stl $17, PT_REGS_R17($sp) + stl $18, PT_REGS_R18($sp) + stl $19, PT_REGS_R19($sp) + stl $20, PT_REGS_R20($sp) + stl $21, PT_REGS_R21($sp) + stl $22, PT_REGS_R22($sp) + stl $23, PT_REGS_R23($sp) + stl $24, PT_REGS_R24($sp) + stl $25, PT_REGS_R25($sp) + stl $26, PT_REGS_R26($sp) + stl $27, PT_REGS_R27($sp) + stl $28, PT_REGS_R28($sp) + stl $29, PT_REGS_GP($sp) + + /* Due to a flaw in the CSR design, in some cases the + * read CSR instruction is sent before the write instruction, + * so it needs to be read twice to ensure that the correct + * CSR value is read. Don`t delete it! + */ + csrr $1, CSR_NMI_SCRATCH + csrr $1, CSR_NMI_SCRATCH + csrr $2, CSR_PS + csrr $3, CSR_PC + csrr $4, CSR_CAUSE + csrr $16, CSR_EARG0 + csrr $17, CSR_EARG1 + csrr $18, CSR_EARG2 + stl $16, PT_REGS_EARG0($sp) + stl $17, PT_REGS_EARG1($sp) + stl $18, PT_REGS_EARG2($sp) + + stl $1, PT_REGS_SP($sp) + stl $2, PT_REGS_PS($sp) + stl $3, PT_REGS_PC($sp) + stl $4, PT_REGS_CAUSE($sp) + ldi $1, NO_SYSCALL + stl $1, PT_REGS_ORIG_R0($sp) + csrr $8, CSR_KTP +#ifdef CONFIG_FRAME_POINTER + ldi $sp, -STACKFRAME_SIZE($sp) + stl $3, STACKFRAME_PC($sp) + stl $15, STACKFRAME_FP($sp) + mov $sp, $15 +#endif + br $27, 1f +1: ldgp $29, 0($27) + call $26, save_nmi_ctx + ldl $16, (PT_REGS_EARG0 + STACKFRAME_SIZE)($sp) + ldl $17, (PT_REGS_EARG1 + STACKFRAME_SIZE)($sp) + ldl $18, (PT_REGS_EARG2 + STACKFRAME_SIZE)($sp) + .endm + + .macro RESTORE_ALL_NMI + call $26, restore_nmi_ctx + + ldi $sp, STACKFRAME_SIZE($sp) + + ldl $1, PT_REGS_PS($sp) + ldl $2, PT_REGS_PC($sp) + csrw $1, CSR_PS + csrw $2, CSR_PC + + ldl $0, PT_REGS_R0($sp) + ldl $1, PT_REGS_R1($sp) + ldl $2, PT_REGS_R2($sp) + ldl $3, PT_REGS_R3($sp) + ldl $4, PT_REGS_R4($sp) + ldl $5, PT_REGS_R5($sp) + ldl $6, PT_REGS_R6($sp) + ldl $7, PT_REGS_R7($sp) + ldl $8, PT_REGS_R8($sp) + ldl $9, PT_REGS_R9($sp) + ldl $10, PT_REGS_R10($sp) + ldl $11, PT_REGS_R11($sp) + ldl $12, PT_REGS_R12($sp) + ldl $13, PT_REGS_R13($sp) + ldl $14, PT_REGS_R14($sp) + ldl $15, PT_REGS_R15($sp) + ldl $16, PT_REGS_R16($sp) + ldl $17, PT_REGS_R17($sp) + ldl $18, PT_REGS_R18($sp) + ldl $19, PT_REGS_R19($sp) + ldl $20, PT_REGS_R20($sp) + ldl $21, PT_REGS_R21($sp) + ldl $22, PT_REGS_R22($sp) + ldl $23, PT_REGS_R23($sp) + ldl $24, PT_REGS_R24($sp) + ldl $25, PT_REGS_R25($sp) + ldl $26, PT_REGS_R26($sp) + ldl $27, PT_REGS_R27($sp) + ldl $28, PT_REGS_R28($sp) + ldl $29, PT_REGS_GP($sp) + ldl $sp, PT_REGS_SP($sp) + .endm + .macro SAVE_ALL csrw $sp, CSR_SP csrw $1, CSR_SCRATCH @@ -66,6 +183,7 @@ csrr $1, CSR_SP csrr $2, CSR_PS csrr $3, CSR_PC + csrr $4, CSR_CAUSE csrr $16, CSR_EARG0 csrr $17, CSR_EARG1 csrr $18, CSR_EARG2 @@ -76,6 +194,7 @@ stl $1, PT_REGS_SP($sp) stl $2, PT_REGS_PS($sp) stl $3, PT_REGS_PC($sp) + stl $4, PT_REGS_CAUSE($sp) ldi $1, NO_SYSCALL stl $1, PT_REGS_ORIG_R0($sp) csrr $8, CSR_KTP @@ -144,6 +263,18 @@ * Non-syscall kernel entry points. */ + .align 4 + .globl entNMI + .ent entNMI +entNMI: + SAVE_ALL_NMI + br $27, 1f +1: ldgp $29, 0($27) + ldi $19, STACKFRAME_SIZE($sp) + call $26, do_entInt + br ret_from_nmi + .end entNMI + .align 4 .globl entInt .ent entInt @@ -258,6 +389,16 @@ entSys: br ret_from_sys_call .end entSys + .align 4 + .globl ret_from_nmi + .ent ret_from_nmi +ret_from_nmi: + br $27, 1f +1: ldgp $29, 0($27) + RESTORE_ALL_NMI + sys_call HMC_rti_nmi + .end ret_from_nmi + .align 4 .globl ret_from_sys_call .ent ret_from_sys_call diff --git a/arch/sw_64/kernel/irq.c b/arch/sw_64/kernel/irq.c index b0f15d81fab9707f2c7ac13e5c12af79b6cc22eb..bd6dca2f3a09895c8d847a268db1e99fae1ee042 100644 --- a/arch/sw_64/kernel/irq.c +++ b/arch/sw_64/kernel/irq.c @@ -98,9 +98,7 @@ handle_irq(int irq) return; } - irq_enter(); generic_handle_irq_desc(desc); - irq_exit(); } #ifdef CONFIG_HOTPLUG_CPU @@ -165,7 +163,17 @@ void __init init_IRQ(void) * Just in case the platform init_irq() causes interrupts/mchecks * (as is the case with RAWHIDE, at least). */ + struct page __maybe_unused *nmi_stack_page = alloc_pages_node( + cpu_to_node(smp_processor_id()), + THREADINFO_GFP, THREAD_SIZE_ORDER); + unsigned long nmi_stack __maybe_unused = nmi_stack_page ? + (unsigned long)page_address(nmi_stack_page) : 0; + wrent(entInt, 0); + if (IS_ENABLED(CONFIG_SUBARCH_C4) && is_in_host()) { + sw64_write_csr_imb(nmi_stack + THREAD_SIZE, CSR_NMI_STACK); + wrent(entNMI, 6); + } sw64_init_irq(); irqchip_init(); 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/setup.c b/arch/sw_64/kernel/setup.c index 7d373fc67c6255741e129cfca2a144c100550429..c2b21a2b1a258dbf78c07aa78b07283d34eb7df6 100644 --- a/arch/sw_64/kernel/setup.c +++ b/arch/sw_64/kernel/setup.c @@ -705,7 +705,6 @@ setup_arch(char **cmdline_p) setup_cpu_info(); setup_run_mode(); setup_chip_ops(); - sw64_chip_init->early_init.setup_core_map(&core_start); if (is_guest_or_emul()) get_vt_smp_info(); @@ -747,13 +746,10 @@ setup_arch(char **cmdline_p) /* Parse the ACPI tables for possible boot-time configuration */ acpi_boot_table_init(); - if (acpi_disabled) { -#ifdef CONFIG_SMP - setup_smp(); -#else - store_cpu_data(0); -#endif - } + if (acpi_disabled) + device_tree_init(); + + setup_smp(); sw64_numa_init(); @@ -796,11 +792,9 @@ setup_arch(char **cmdline_p) #ifdef CONFIG_NUMA cpu_set_node(); #endif - device_tree_init(); } } - static int show_cpuinfo(struct seq_file *f, void *slot) { diff --git a/arch/sw_64/kernel/smp.c b/arch/sw_64/kernel/smp.c index 2ee8424867cfa70dc8fb613a52429330e2729d32..b6532691f65b09a7946f7401335d6f687b273111 100644 --- a/arch/sw_64/kernel/smp.c +++ b/arch/sw_64/kernel/smp.c @@ -7,6 +7,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -20,6 +24,12 @@ struct smp_rcb_struct *smp_rcb; extern struct cpuinfo_sw64 cpu_data[NR_CPUS]; +static nodemask_t nodes_found_map = NODE_MASK_NONE; + /* maps to convert between physical node ID and logical node ID */ +static int pnode_to_lnode_map[MAX_NUMNODES] + = { [0 ... MAX_NUMNODES - 1] = NUMA_NO_NODE }; +static int lnode_to_pnode_map[MAX_NUMNODES] + = { [0 ... MAX_NUMNODES - 1] = NUMA_NO_NODE }; #define smp_debug 0 #define DBGS(fmt, arg...) \ @@ -63,6 +73,7 @@ static void upshift_freq(void) if (is_guest_or_emul()) return; + cpu_num = sw64_chip->get_cpu_num(); for (i = 0; i < cpu_num; i++) { sw64_io_write(i, CLU_LV2_SELH, -1UL); @@ -74,11 +85,21 @@ static void upshift_freq(void) static void downshift_freq(void) { unsigned long value; - int cpuid, core_id, node_id; + int core_id, node_id, cpu; + int cpuid = smp_processor_id(); + struct cpu_topology *cpu_topo = &cpu_topology[cpuid]; if (is_guest_or_emul()) return; - cpuid = smp_processor_id(); + + for_each_online_cpu(cpu) { + 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)) + return; + } + core_id = rcid_to_core_id(cpu_to_rcid(cpuid)); node_id = rcid_to_domain_id(cpu_to_rcid(cpuid)); @@ -102,6 +123,9 @@ static void downshift_freq(void) { } void smp_callin(void) { int cpuid; + struct page __maybe_unused *nmi_stack_page; + unsigned long __maybe_unused nmi_stack; + save_ktp(); upshift_freq(); cpuid = smp_processor_id(); @@ -129,6 +153,17 @@ void smp_callin(void) /* update csr:ptbr */ update_ptbr_sys(virt_to_phys(init_mm.pgd)); + if (IS_ENABLED(CONFIG_SUBARCH_C4) && is_in_host()) { + nmi_stack_page = alloc_pages_node( + cpu_to_node(smp_processor_id()), + THREADINFO_GFP, + THREAD_SIZE_ORDER); + nmi_stack = nmi_stack_page ? + (unsigned long)page_address(nmi_stack_page) : 0; + sw64_write_csr_imb(nmi_stack + THREAD_SIZE, CSR_NMI_STACK); + wrent(entNMI, 6); + } + /* inform the notifiers about the new cpu */ notify_cpu_starting(cpuid); @@ -230,6 +265,145 @@ void __init smp_rcb_init(struct smp_rcb_struct *smp_rcb_base_addr) mb(); } +static int __init sw64_of_core_version(const struct device_node *dn, + int *version) +{ + if (!dn || !version) + return -EINVAL; + + if (of_device_is_compatible(dn, "sw64,xuelang")) { + *version = CORE_VERSION_C3B; + return 0; + } + + if (of_device_is_compatible(dn, "sw64,junzhang")) { + *version = CORE_VERSION_C4; + return 0; + } + + return -EINVAL; +} + +static void __fdt_map_pnode_to_lnode(int pnode, int lnode) +{ + if (pnode_to_lnode_map[pnode] == NUMA_NO_NODE || lnode < pnode_to_lnode_map[pnode]) + pnode_to_lnode_map[pnode] = lnode; + if (lnode_to_pnode_map[lnode] == NUMA_NO_NODE || pnode < lnode_to_pnode_map[lnode]) + lnode_to_pnode_map[lnode] = pnode; +} + +static int fdt_map_pnode_to_lnode(int pnode) +{ + int lnode; + + if (pnode < 0 || pnode >= MAX_NUMNODES || numa_off) + return NUMA_NO_NODE; + lnode = pnode_to_lnode_map[pnode]; + + if (lnode == NUMA_NO_NODE) { + if (nodes_weight(nodes_found_map) >= MAX_NUMNODES) + return NUMA_NO_NODE; + lnode = first_unset_node(nodes_found_map); + __fdt_map_pnode_to_lnode(pnode, lnode); + node_set(lnode, nodes_found_map); + } + + return lnode; +} + +static int __init fdt_setup_smp(void) +{ + struct device_node *dn = NULL; + u64 boot_flag_address; + u32 rcid, logical_core_id = 0; + int ret, i, version, lnode, pnode; + + /* Clean the map from logical core ID to physical core ID */ + for (i = 0; i < ARRAY_SIZE(__cpu_to_rcid); ++i) + set_rcid_map(i, -1); + + /* Clean core mask */ + init_cpu_possible(cpu_none_mask); + init_cpu_present(cpu_none_mask); + +#ifdef CONFIG_SUBARCH_C4 + if (is_guest_or_emul()) { + int vt_smp_cpu_num; + + vt_smp_cpu_num = sw64_io_read(0, VT_ONLINE_CPU); + for (i = vt_smp_cpu_num; i < KVM_MAX_VCPUS; i++) + cpumask_set_cpu(i, &cpu_offline); + } +#endif + while ((dn = of_find_node_by_type(dn, "cpu"))) { + if (!of_device_is_available(dn)) { + pr_info("OF: Core is not available\n"); + continue; + } + + ret = of_property_read_u32(dn, "reg", &rcid); + if (ret) { + pr_err("OF: Found core without rcid\n"); + return -ENODEV; + } + + if (logical_core_id >= nr_cpu_ids) { + pr_err("OF: Core [0x%x] exceeds max core num [%u]\n", + rcid, nr_cpu_ids); + return -ENODEV; + } + + if (is_rcid_duplicate(rcid)) { + pr_err("OF: Duplicate core [0x%x]\n", rcid); + return -EINVAL; + } + + ret = sw64_of_core_version(dn, &version); + if (ret) { + pr_err("OF: No valid core version found\n"); + return ret; + } + + ret = of_property_read_u64(dn, "sw64,boot_flag_address", + &boot_flag_address); + if (ret) { + pr_err("OF: No boot_flag_address found\n"); + return ret; + } + + set_rcid_map(logical_core_id, rcid); + set_cpu_possible(logical_core_id, true); + store_cpu_data(logical_core_id); + + if (!cpumask_test_cpu(logical_core_id, &cpu_offline)) + set_cpu_present(logical_core_id, true); + + rcid_information_init(version); + + smp_rcb_init(__va(boot_flag_address)); + + /* Set core affinity */ + pnode = of_node_to_nid(dn); + lnode = fdt_map_pnode_to_lnode(pnode); + + early_map_cpu_to_node(logical_core_id, lnode); + + logical_core_id++; + } + + /* No valid cpu node found */ + if (!num_possible_cpus()) + return -EINVAL; + + /* It's time to update nr_cpu_ids */ + nr_cpu_ids = num_possible_cpus(); + + pr_info("OF: Detected %u possible CPU(s), %u CPU(s) are present\n", + nr_cpu_ids, num_present_cpus()); + + return 0; +} + /* * Called from setup_arch. Detect an SMP system and which processors * are present. @@ -238,10 +412,29 @@ void __init setup_smp(void) { int i = 0, num = 0; + /* First try SMP initialization via ACPI */ + if (!acpi_disabled) + return; + + /* Next try SMP initialization via device tree */ + if (!fdt_setup_smp()) + return; + + /* Fallback to legacy SMP initialization */ + + /* Clean the map from logical core ID to physical core ID */ + for (i = 0; i < ARRAY_SIZE(__cpu_to_rcid); ++i) + set_rcid_map(i, -1); + + /* Clean core mask */ init_cpu_possible(cpu_none_mask); + init_cpu_present(cpu_none_mask); + + /* Legacy core detect */ + sw64_chip_init->early_init.setup_core_map(&core_start); /* For unified kernel, NR_CPUS is the maximum possible value */ - for (; i < NR_CPUS; i++) { + for (i = 0; i < NR_CPUS; i++) { if (cpu_to_rcid(i) != -1) { set_cpu_possible(num, true); store_cpu_data(num); @@ -447,9 +640,7 @@ void handle_ipi(struct pt_regs *regs) break; case IPI_CALL_FUNC: - irq_enter(); generic_smp_call_function_interrupt(); - irq_exit(); break; case IPI_CPU_STOP: @@ -669,6 +860,7 @@ void arch_cpu_idle_dead(void) if (is_in_guest()) { hcall(HCALL_SET_CLOCKEVENT, 0, 0, 0); hcall(HCALL_STOP, 0, 0, 0); + return; } else { wrtimer(0); } diff --git a/arch/sw_64/kernel/traps.c b/arch/sw_64/kernel/traps.c index c0d0a442fda46c0c8cda8d83052b1a4b2616eb29..62c7df54b6a976d07c506b7131dca6e47a11c74b 100644 --- a/arch/sw_64/kernel/traps.c +++ b/arch/sw_64/kernel/traps.c @@ -275,6 +275,8 @@ do_entIF(unsigned long inst_type, unsigned long va, struct pt_regs *regs) switch (type) { case IF_BREAKPOINT: /* gdb do pc-4 for sigtrap */ + if (ptrace_cancel_bpt(current)) + regs->pc -= 4; force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)regs->pc); return; @@ -2004,6 +2006,25 @@ asmlinkage void do_entSys(struct pt_regs *regs) syscall_trace_leave(); } +struct nmi_ctx { + unsigned long csr_sp; + unsigned long csr_scratch; +}; + +DEFINE_PER_CPU(struct nmi_ctx, nmi_context); + +void save_nmi_ctx(void) +{ + this_cpu_write(nmi_context.csr_sp, sw64_read_csr(CSR_SP)); + this_cpu_write(nmi_context.csr_scratch, sw64_read_csr(CSR_SCRATCH)); +} + +void restore_nmi_ctx(void) +{ + sw64_write_csr_imb(this_cpu_read(nmi_context.csr_sp), CSR_SP); + sw64_write_csr_imb(this_cpu_read(nmi_context.csr_scratch), CSR_SCRATCH); +} + void trap_init(void) { diff --git a/arch/sw_64/kvm/entry_core4.S b/arch/sw_64/kvm/entry_core4.S index 46036abc696ce874d1ce2b0ee671fb7f792a2a35..48325cc7c2c50e4cf0faa82425d2342f35356652 100644 --- a/arch/sw_64/kvm/entry_core4.S +++ b/arch/sw_64/kvm/entry_core4.S @@ -264,6 +264,8 @@ $setfpec_over: csrr $18, CSR_EARG2 ldi $19, -PT_REGS_SIZE(sp) + csrr $1, CSR_CAUSE + stl $1, PT_REGS_CAUSE($19) call $26, do_entInt ldl $26, VCPU_RET_RA(sp) ldl $0, VCPU_RET_R0(sp) diff --git a/arch/sw_64/kvm/sw64.c b/arch/sw_64/kvm/sw64.c index 3d57d6b7a0487e61f544977df59ae26bf96a1b87..d1ac7c76546d94c090b5f7d5c1184b0d3b7c8801 100644 --- a/arch/sw_64/kvm/sw64.c +++ b/arch/sw_64/kvm/sw64.c @@ -37,6 +37,21 @@ static unsigned long get_new_vpn_context(struct kvm_vcpu *vcpu, long cpu) return next; } +int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e, + struct kvm *kvm, int irq_source_id, + int level, bool line_status) +{ + switch (e->type) { + case KVM_IRQ_ROUTING_MSI: + if (!kvm_set_msi(e, kvm, irq_source_id, level, line_status)) + return 0; + break; + default: + break; + } + return -EWOULDBLOCK; +} + int vcpu_interrupt_line(struct kvm_vcpu *vcpu, int number, bool level) { set_bit(number, (vcpu->arch.irqs_pending)); @@ -164,6 +179,12 @@ struct dfx_sw64_kvm_stats_debugfs_item dfx_sw64_debugfs_entries[] = { int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) { + if (vcpu->arch.restart) + return 1; + + if (vcpu->arch.vcb.vcpu_irq_disabled) + return 0; + return ((!bitmap_empty(vcpu->arch.irqs_pending, SWVM_IRQS) || !vcpu->arch.halted) && !vcpu->arch.power_off); } diff --git a/arch/sw_64/pci/msi.c b/arch/sw_64/pci/msi.c index eeb01e63e636c1111e9b7b80a0dc07dec4c392a2..98dfb1c3b3e7ce8ba10dae90bbeec3bb3a0b81cf 100644 --- a/arch/sw_64/pci/msi.c +++ b/arch/sw_64/pci/msi.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include #include #include #include @@ -19,16 +18,3 @@ void sw64_irq_noop(struct irq_data *d) void arch_teardown_msi_irq(unsigned int irq) { } - -static int __init msi_init(void) -{ - return 0; -} - -static void __exit msi_exit(void) -{ -} - -module_init(msi_init); -module_exit(msi_exit); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/clocksource/timer-sw64.c b/drivers/clocksource/timer-sw64.c index 72a5b05d496a0ffab25ae745ce3104c70cf0c880..875e2feb853a756ec90c5c53e4be1069ba9efbfa 100644 --- a/drivers/clocksource/timer-sw64.c +++ b/drivers/clocksource/timer-sw64.c @@ -418,7 +418,6 @@ void sw64_timer_interrupt(void) { struct clock_event_device *evt = this_cpu_ptr(&timer_events); - irq_enter(); if (!evt->event_handler) { pr_warn("Spurious local timer interrupt on cpu %d\n", smp_processor_id()); @@ -429,6 +428,4 @@ void sw64_timer_interrupt(void) inc_irq_stat(timer_irqs_event); evt->event_handler(evt); - - irq_exit(); } diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ddde1a12885579cb01fa3bc66e5869a044c95411..4851ea1568682ef3d4abc00c3e5be7e6588a2a89 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -241,6 +241,7 @@ config GPIO_SUNWAY depends on SW64 select GPIO_GENERIC select GENERIC_IRQ_CHIP + default y if ACPI help Say Y or M here to build support for the Sunway GPIO block. diff --git a/drivers/irqchip/irq-sunway-cpu.c b/drivers/irqchip/irq-sunway-cpu.c index e1c270f1bb10a6dda0349ecf293dbb0375a70685..2f0d101daeb0aaed32d761b613c34de8f4a42c97 100644 --- a/drivers/irqchip/irq-sunway-cpu.c +++ b/drivers/irqchip/irq-sunway-cpu.c @@ -181,16 +181,23 @@ asmlinkage void do_entInt(unsigned long type, unsigned long vector, struct pt_regs *old_regs; extern char __idle_start[], __idle_end[]; + /* restart idle routine if it is interrupted */ + if (regs->pc > (u64)__idle_start && regs->pc < (u64)__idle_end) + regs->pc = (u64)__idle_start; + if (regs->cause != -2) + irq_enter(); + else + nmi_enter(); + old_regs = set_irq_regs(regs); + #ifdef CONFIG_SUBARCH_C4 if (pme_state == PME_WFW) { pme_state = PME_PENDING; - return; + goto out; } if (pme_state == PME_PENDING) { - old_regs = set_irq_regs(regs); handle_device_interrupt(vector); - set_irq_regs(old_regs); pme_state = PME_CLEAR; } #endif @@ -205,80 +212,69 @@ asmlinkage void do_entInt(unsigned long type, unsigned long vector, } } - /* restart idle routine if it is interrupted */ - if (regs->pc > (u64)__idle_start && regs->pc < (u64)__idle_end) - regs->pc = (u64)__idle_start; - switch (type & 0xffff) { case INT_MSI: - old_regs = set_irq_regs(regs); if (is_guest_or_emul()) vt_handle_pci_msi_interrupt(type, vector, irq_arg); else handle_pci_msi_interrupt(type, vector, irq_arg); - set_irq_regs(old_regs); - return; + goto out; case INT_INTx: - old_regs = set_irq_regs(regs); handle_device_interrupt(vector); - set_irq_regs(old_regs); - return; + goto out; case INT_IPI: #ifdef CONFIG_SMP handle_ipi(regs); - return; + goto out; #else irq_err_count++; pr_crit("Interprocessor interrupt? You must be kidding!\n"); -#endif break; +#endif case INT_RTC: - old_regs = set_irq_regs(regs); sw64_timer_interrupt(); - set_irq_regs(old_regs); - return; + goto out; case INT_VT_SERIAL: case INT_VT_HOTPLUG: case INT_VT_GPIOA_PIN0: - old_regs = set_irq_regs(regs); handle_irq(type); - set_irq_regs(old_regs); - return; + goto out; #if defined(CONFIG_SUBARCH_C3B) case INT_PC0: perf_irq(PMC_PC0, regs); - return; + goto out; case INT_PC1: perf_irq(PMC_PC1, regs); - return; + goto out; #elif defined(CONFIG_SUBARCH_C4) case INT_PC: perf_irq(PMC_PC0, regs); - return; + goto out; #endif case INT_DEV: handle_dev_int(regs); - return; + goto out; case INT_FAULT: - old_regs = set_irq_regs(regs); handle_fault_int(); - set_irq_regs(old_regs); - return; + goto out; case INT_MT: - old_regs = set_irq_regs(regs); handle_mt_int(); - set_irq_regs(old_regs); - return; + goto out; case INT_NMI: - old_regs = set_irq_regs(regs); handle_nmi_int(); - set_irq_regs(old_regs); - return; + goto out; default: pr_crit("Hardware intr %ld %lx? uh?\n", type, vector); } pr_crit("PC = %016lx PS = %04lx\n", regs->pc, regs->ps); + +out: + set_irq_regs(old_regs); + if (regs->cause != -2) + irq_exit(); + else + nmi_exit(); } EXPORT_SYMBOL(do_entInt); diff --git a/drivers/irqchip/irq-sunway-msi-vt.c b/drivers/irqchip/irq-sunway-msi-vt.c index d5213725c918ffa9e4644029e366832f47cd2f34..1f475c785f1caff60f2031f346df1ae35f21afb3 100644 --- a/drivers/irqchip/irq-sunway-msi-vt.c +++ b/drivers/irqchip/irq-sunway-msi-vt.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include diff --git a/drivers/misc/sunway-ged.c b/drivers/misc/sunway-ged.c index 5167700369622d2498d7c8e347386d3b93462373..7d0b6f7fc6829e6f5e3cca192fbd14dd1418d357 100644 --- a/drivers/misc/sunway-ged.c +++ b/drivers/misc/sunway-ged.c @@ -12,14 +12,23 @@ #include #include +/* offset should be the same as QEMU */ #define OFFSET_START_ADDR 0 #define OFFSET_LENGTH 8 #define OFFSET_STATUS 16 #define OFFSET_SLOT 24 +#define OFFSET_CPUID 32 + +#define OFFSET_NODE 40 + /* Memory hotplug event */ #define SUNWAY_MEMHOTPLUG_ADD 0x1 #define SUNWAY_MEMHOTPLUG_REMOVE 0x2 +/* Cpu hotplug event */ +#define SUNWAY_CPUHOTPLUG_ADD 0x4 +#define SUNWAY_CPUHOTPLUG_REMOVE 0x8 + struct sunway_memory_device { struct sunway_ged_device *device; @@ -29,6 +38,7 @@ struct sunway_memory_device { u64 start_addr; /* Memory Range start physical addr */ u64 length; /* Memory Range length */ u64 slot; /* Memory Range slot */ + u64 node; /* Memory Range node */ unsigned int enabled:1; }; @@ -59,7 +69,7 @@ static int sunway_memory_enable_device(struct sunway_memory_device *mem_device) lock_device_hotplug(); /* suppose node = 0, fix me! */ - result = __add_memory(0, mem_device->start_addr, mem_device->length, MHP_NONE); + result = __add_memory(mem_device->node, mem_device->start_addr, mem_device->length, MHP_NONE); unlock_device_hotplug(); /* * If the memory block has been used by the kernel, add_memory() @@ -85,28 +95,10 @@ static int sunway_memory_enable_device(struct sunway_memory_device *mem_device) return 0; } -static int sunway_memory_get_meminfo(struct sunway_memory_device *mem_device) -{ - struct sunway_ged_device *geddev; - - if (!mem_device) - return -EINVAL; - - if (mem_device->enabled) - return 0; - - geddev = mem_device->device; - - mem_device->start_addr = readq(geddev->membase + OFFSET_START_ADDR); - mem_device->length = readq(geddev->membase + OFFSET_LENGTH); - - return 0; -} - static void sunway_memory_device_remove(struct sunway_ged_device *device) { struct sunway_memory_device *mem_dev, *n; - unsigned long start_addr, length, slot; + unsigned long start_addr, length, slot, node; if (!device) return; @@ -114,6 +106,7 @@ static void sunway_memory_device_remove(struct sunway_ged_device *device) start_addr = readq(device->membase + OFFSET_START_ADDR); length = readq(device->membase + OFFSET_LENGTH); slot = readq(device->membase + OFFSET_SLOT); + node = readq(device->membase + OFFSET_NODE); list_for_each_entry_safe(mem_dev, n, &device->dev_list, list) { if (!mem_dev->enabled) @@ -122,7 +115,7 @@ static void sunway_memory_device_remove(struct sunway_ged_device *device) if ((start_addr == mem_dev->start_addr) && (length == mem_dev->length)) { /* suppose node = 0, fix me! */ - remove_memory(0, start_addr, length); + remove_memory(node, start_addr, length); list_del(&mem_dev->list); kfree(mem_dev); } @@ -150,6 +143,7 @@ static int sunway_memory_device_add(struct sunway_ged_device *device) mem_device->start_addr = readq(device->membase + OFFSET_START_ADDR); mem_device->length = readq(device->membase + OFFSET_LENGTH); mem_device->slot = readq(device->membase + OFFSET_SLOT); + mem_device->node = readq(device->membase + OFFSET_NODE); result = sunway_memory_enable_device(mem_device); if (result) { @@ -165,12 +159,52 @@ static int sunway_memory_device_add(struct sunway_ged_device *device) return 1; } +static int sunway_cpu_device_add(struct sunway_ged_device *device) +{ + struct device *dev; + int cpuid; + + cpuid = readq(device->membase + OFFSET_CPUID); + + if (!device) + return -EINVAL; + set_cpu_present(cpuid, true); + dev = get_cpu_device(cpuid); + if (device_attach(dev) >= 0) + return 1; + dev_err(dev, "Processor driver could not be attached\n"); + set_cpu_present(cpuid, false); + return 0; +} + +static void sunway_cpu_device_del(struct sunway_ged_device *device) +{ + struct device *dev; + int cpuid; + + cpuid = readq(device->membase + OFFSET_CPUID); + + if (!device) + return; + set_cpu_present(cpuid, false); + dev = get_cpu_device(cpuid); + device_release_driver(dev); + + writeq(cpuid, device->membase + OFFSET_CPUID); +} + static irqreturn_t sunwayged_ist(int irq, void *data) { struct sunway_ged_device *sunwayged_dev = data; unsigned int status; - status = readl(sunwayged_dev->membase + OFFSET_STATUS); + status = readq(sunwayged_dev->membase + OFFSET_STATUS); + /* through IO status to add or remove cpu */ + if (status & SUNWAY_CPUHOTPLUG_ADD) + sunway_cpu_device_add(sunwayged_dev); + + if (status & SUNWAY_CPUHOTPLUG_REMOVE) + sunway_cpu_device_del(sunwayged_dev); /* through IO status to add or remove memory device */ if (status & SUNWAY_MEMHOTPLUG_ADD) diff --git a/drivers/pci/controller/pci-sunway.c b/drivers/pci/controller/pci-sunway.c index 5914d3cfcbf00926a94c7a1adf871d427498385a..2b7af37958641c479428a1f241d167d3d597108a 100644 --- a/drivers/pci/controller/pci-sunway.c +++ b/drivers/pci/controller/pci-sunway.c @@ -19,7 +19,7 @@ void set_devint_wken(int node) #ifdef CONFIG_UNCORE_JUNZHANG void set_adr_int(int node) { - sw64_io_write(node, ADR_INT_CONFIG, (0x0 << 16 | 0x3f)); + sw64_io_write(node, ADR_INT_CONFIG, (CORE0_CID << 16 | 0x3f)); sw64_io_write(node, ADR_CTL, 0xc); } #endif diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index f7cf4fd36898d38a224d4a5eae65d6b604597a5f..a539321bb43cb6a34672272e5d8a39862c8da3f9 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -465,6 +465,9 @@ static int sw64_is_fake_mcount(Elf64_Rel const *rp) Elf64_Addr current_r_offset = _w(rp->r_offset); int is_fake; + if (Elf_r_sym(rp) == 0) + return 1; + is_fake = (old_r_offset != ~(Elf64_Addr)0) && (current_r_offset - old_r_offset == SW64_FAKEMCOUNT_OFFSET); old_r_offset = current_r_offset;