Skip to content

Commit

Permalink
Merge tag 'loongarch-fixes-6.14-2' of git://git.kernel.org/pub/scm/li…
Browse files Browse the repository at this point in the history
…nux/kernel/git/chenhuacai/linux-loongson

Pull LoongArch fixes from Huacai Chen:
 "Fix bugs in kernel build, hibernation, memory management and KVM"

* tag 'loongarch-fixes-6.14-2' of git://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson:
  LoongArch: KVM: Fix GPA size issue about VM
  LoongArch: KVM: Reload guest CSR registers after sleep
  LoongArch: KVM: Add interrupt checking for AVEC
  LoongArch: Set hugetlb mmap base address aligned with pmd size
  LoongArch: Set max_pfn with the PFN of the last page
  LoongArch: Use polling play_dead() when resuming from hibernation
  LoongArch: Eliminate superfluous get_numa_distances_cnt()
  LoongArch: Convert unreachable() to BUG()
  • Loading branch information
Linus Torvalds committed Mar 8, 2025
2 parents 2a52007 + 6bdbb73 commit 2e51e0a
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 18 deletions.
12 changes: 0 additions & 12 deletions arch/loongarch/kernel/acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,18 +249,6 @@ static __init int setup_node(int pxm)
return acpi_map_pxm_to_node(pxm);
}

/*
* Callback for SLIT parsing. pxm_to_node() returns NUMA_NO_NODE for
* I/O localities since SRAT does not list them. I/O localities are
* not supported at this point.
*/
unsigned int numa_distance_cnt;

static inline unsigned int get_numa_distances_cnt(struct acpi_table_slit *slit)
{
return slit->locality_count;
}

void __init numa_set_distance(int from, int to, int distance)
{
if ((u8)distance != distance || (from == to && distance != LOCAL_DISTANCE)) {
Expand Down
4 changes: 2 additions & 2 deletions arch/loongarch/kernel/machine_kexec.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,14 @@ void kexec_reboot(void)
/* All secondary cpus go to kexec_smp_wait */
if (smp_processor_id() > 0) {
relocated_kexec_smp_wait(NULL);
unreachable();
BUG();
}
#endif

do_kexec = (void *)reboot_code_buffer;
do_kexec(efi_boot, cmdline_ptr, systable_ptr, start_addr, first_ind_entry);

unreachable();
BUG();
}


Expand Down
3 changes: 3 additions & 0 deletions arch/loongarch/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,9 @@ static void __init check_kernel_sections_mem(void)
*/
static void __init arch_mem_init(char **cmdline_p)
{
/* Recalculate max_low_pfn for "mem=xxx" */
max_pfn = max_low_pfn = PHYS_PFN(memblock_end_of_DRAM());

if (usermem)
pr_info("User-defined physical RAM map overwrite\n");

Expand Down
47 changes: 46 additions & 1 deletion arch/loongarch/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <linux/smp.h>
#include <linux/threads.h>
#include <linux/export.h>
#include <linux/suspend.h>
#include <linux/syscore_ops.h>
#include <linux/time.h>
#include <linux/tracepoint.h>
Expand Down Expand Up @@ -423,7 +424,7 @@ void loongson_cpu_die(unsigned int cpu)
mb();
}

void __noreturn arch_cpu_idle_dead(void)
static void __noreturn idle_play_dead(void)
{
register uint64_t addr;
register void (*init_fn)(void);
Expand All @@ -447,6 +448,50 @@ void __noreturn arch_cpu_idle_dead(void)
BUG();
}

#ifdef CONFIG_HIBERNATION
static void __noreturn poll_play_dead(void)
{
register uint64_t addr;
register void (*init_fn)(void);

idle_task_exit();
__this_cpu_write(cpu_state, CPU_DEAD);

__smp_mb();
do {
__asm__ __volatile__("nop\n\t");
addr = iocsr_read64(LOONGARCH_IOCSR_MBUF0);
} while (addr == 0);

init_fn = (void *)TO_CACHE(addr);
iocsr_write32(0xffffffff, LOONGARCH_IOCSR_IPI_CLEAR);

init_fn();
BUG();
}
#endif

static void (*play_dead)(void) = idle_play_dead;

void __noreturn arch_cpu_idle_dead(void)
{
play_dead();
BUG(); /* play_dead() doesn't return */
}

#ifdef CONFIG_HIBERNATION
int hibernate_resume_nonboot_cpu_disable(void)
{
int ret;

play_dead = poll_play_dead;
ret = suspend_disable_secondary_cpus();
play_dead = idle_play_dead;

return ret;
}
#endif

#endif

/*
Expand Down
6 changes: 6 additions & 0 deletions arch/loongarch/kvm/exit.c
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,12 @@ static int kvm_handle_rdwr_fault(struct kvm_vcpu *vcpu, bool write)
struct kvm_run *run = vcpu->run;
unsigned long badv = vcpu->arch.badv;

/* Inject ADE exception if exceed max GPA size */
if (unlikely(badv >= vcpu->kvm->arch.gpa_size)) {
kvm_queue_exception(vcpu, EXCCODE_ADE, EXSUBCODE_ADEM);
return RESUME_GUEST;
}

ret = kvm_handle_mm_fault(vcpu, badv, write);
if (ret) {
/* Treat as MMIO */
Expand Down
7 changes: 7 additions & 0 deletions arch/loongarch/kvm/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,13 @@ int kvm_arch_enable_virtualization_cpu(void)
kvm_debug("GCFG:%lx GSTAT:%lx GINTC:%lx GTLBC:%lx",
read_csr_gcfg(), read_csr_gstat(), read_csr_gintc(), read_csr_gtlbc());

/*
* HW Guest CSR registers are lost after CPU suspend and resume.
* Clear last_vcpu so that Guest CSR registers forced to reload
* from vCPU SW state.
*/
this_cpu_ptr(vmcs)->last_vcpu = NULL;

return 0;
}

Expand Down
2 changes: 1 addition & 1 deletion arch/loongarch/kvm/vcpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ static int kvm_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
{
int ret = RESUME_GUEST;
unsigned long estat = vcpu->arch.host_estat;
u32 intr = estat & 0x1fff; /* Ignore NMI */
u32 intr = estat & CSR_ESTAT_IS;
u32 ecode = (estat & CSR_ESTAT_EXC) >> CSR_ESTAT_EXC_SHIFT;

vcpu->mode = OUTSIDE_GUEST_MODE;
Expand Down
6 changes: 5 additions & 1 deletion arch/loongarch/kvm/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
if (kvm_pvtime_supported())
kvm->arch.pv_features |= BIT(KVM_FEATURE_STEAL_TIME);

kvm->arch.gpa_size = BIT(cpu_vabits - 1);
/*
* cpu_vabits means user address space only (a half of total).
* GPA size of VM is the same with the size of user address space.
*/
kvm->arch.gpa_size = BIT(cpu_vabits);
kvm->arch.root_level = CONFIG_PGTABLE_LEVELS - 1;
kvm->arch.invalid_ptes[0] = 0;
kvm->arch.invalid_ptes[1] = (unsigned long)invalid_pte_table;
Expand Down
6 changes: 5 additions & 1 deletion arch/loongarch/mm/mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright (C) 2020-2022 Loongson Technology Corporation Limited
*/
#include <linux/export.h>
#include <linux/hugetlb.h>
#include <linux/io.h>
#include <linux/kfence.h>
#include <linux/memblock.h>
Expand Down Expand Up @@ -63,8 +64,11 @@ static unsigned long arch_get_unmapped_area_common(struct file *filp,
}

info.length = len;
info.align_mask = do_color_align ? (PAGE_MASK & SHM_ALIGN_MASK) : 0;
info.align_offset = pgoff << PAGE_SHIFT;
if (filp && is_file_hugepages(filp))
info.align_mask = huge_page_mask_align(filp);
else
info.align_mask = do_color_align ? (PAGE_MASK & SHM_ALIGN_MASK) : 0;

if (dir == DOWN) {
info.flags = VM_UNMAPPED_AREA_TOPDOWN;
Expand Down

0 comments on commit 2e51e0a

Please sign in to comment.