diff --git a/arch/loongarch/kernel/smp.c b/arch/loongarch/kernel/smp.c index f5a94559d44129fe908c4603ec4ace93ecdf87dc..abf6484fac707ab4d547d9388cbcd36b7dc7ab49 100644 --- a/arch/loongarch/kernel/smp.c +++ b/arch/loongarch/kernel/smp.c @@ -310,16 +310,29 @@ void play_dead(void) register void (*init_fn)(void); idle_task_exit(); - local_irq_enable(); + /* + * vcpu can be woken up from idle emulation in vm if irq is disabled + */ + if (!cpu_has_hypervisor) + local_irq_enable(); set_csr_ecfg(ECFGF_IPI); __this_cpu_write(cpu_state, CPU_DEAD); __smp_mb(); do { __asm__ __volatile__("idle 0\n\t"); - addr = iocsr_read64(LOONGARCH_IOCSR_MBUF0); + /* + * mailbox info is wroten from other CPU with IPI send method + * in function csr_mail_send, only 4 bytes can be wroten with + * IPI send method in one time. + * + * High 4 bytes is sent and then low 4 bytes for 8 bytes mail + * sending method. Here low 4 bytes is read by the first. + */ + addr = iocsr_read32(LOONGARCH_IOCSR_MBUF0); } while (addr == 0); + addr = iocsr_read64(LOONGARCH_IOCSR_MBUF0); init_fn = (void *)TO_CACHE(addr); iocsr_write32(0xffffffff, LOONGARCH_IOCSR_IPI_CLEAR); diff --git a/arch/loongarch/kernel/time.c b/arch/loongarch/kernel/time.c index 18fa38705da7a2acee3a3ee630ebcbc6461ef047..b2e8108bee1013eb4d745218188f065f3863748d 100644 --- a/arch/loongarch/kernel/time.c +++ b/arch/loongarch/kernel/time.c @@ -59,21 +59,6 @@ static int constant_set_state_oneshot(struct clock_event_device *evt) return 0; } -static int constant_set_state_oneshot_stopped(struct clock_event_device *evt) -{ - unsigned long timer_config; - - raw_spin_lock(&state_lock); - - timer_config = csr_read64(LOONGARCH_CSR_TCFG); - timer_config &= ~CSR_TCFG_EN; - csr_write64(timer_config, LOONGARCH_CSR_TCFG); - - raw_spin_unlock(&state_lock); - - return 0; -} - static int constant_set_state_periodic(struct clock_event_device *evt) { unsigned long period; @@ -93,6 +78,14 @@ static int constant_set_state_periodic(struct clock_event_device *evt) static int constant_set_state_shutdown(struct clock_event_device *evt) { + unsigned long timer_config; + + raw_spin_lock(&state_lock); + timer_config = csr_read64(LOONGARCH_CSR_TCFG); + timer_config &= ~CSR_TCFG_EN; + csr_write64(timer_config, LOONGARCH_CSR_TCFG); + raw_spin_unlock(&state_lock); + return 0; } @@ -161,7 +154,7 @@ int constant_clockevent_init(void) cd->rating = 320; cd->cpumask = cpumask_of(cpu); cd->set_state_oneshot = constant_set_state_oneshot; - cd->set_state_oneshot_stopped = constant_set_state_oneshot_stopped; + cd->set_state_oneshot_stopped = constant_set_state_shutdown; cd->set_state_periodic = constant_set_state_periodic; cd->set_state_shutdown = constant_set_state_shutdown; cd->set_next_event = constant_timer_next_event;