Commit 3f90ac70 authored by Tang Jinyang's avatar Tang Jinyang Committed by guzitao
Browse files

sw64: work around suspend for C4

Sunway inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IB73UR



--------------------------------

This patch introduces a light weight sleep mechanism to work
around suspend for Core4.

Signed-off-by: default avatarTang Jinyang <tangjinyang@wxiat.com>
Reviewed-by: default avatarHe Sheng <hesheng@wxiat.com>
Signed-off-by: default avatarGu Zitao <guzitao@wxiat.com>
parent cb64795d
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -43,6 +43,13 @@ extern struct sw64_chip_ops *sw64_chip;
extern struct sw64_chip_init_ops *sw64_chip_init;
#ifdef CONFIG_PM
extern struct syscore_ops io_syscore_ops;

#define PME_CLEAR	0
#define PME_WFW		1	/* wait for wake */
#define	PME_PENDING	2

extern int pme_state;

#endif

DECLARE_PER_CPU(unsigned long, hard_node_id);
+3 −0
Original line number Diff line number Diff line
@@ -116,6 +116,9 @@ enum {
	SI_FAULT_INT_EN =	SPBU_BASE | 0x3200UL,
	ADR_CTL =		SPBU_BASE | 0x3600UL,
	MC_ONLINE =		SPBU_BASE | 0x3780UL,
	CLK_CTL =               SPBU_BASE | 0x3b80UL,
	CLU_LV2_SELH =          SPBU_BASE | 0x3a00UL,
	CLU_LV2_SELL =          SPBU_BASE | 0x3b00UL,
	PIU_TOP0_CONFIG =	SPBU_BASE | 0x4c80UL,
	PIU_TOP1_CONFIG =	SPBU_BASE | 0x4d00UL,
	SOFT_INFO0 =		SPBU_BASE | 0xa000UL,
+40 −0
Original line number Diff line number Diff line
@@ -60,12 +60,26 @@ void smp_callin(void)
{
	int cpuid = smp_processor_id();

#ifdef CONFIG_SUBARCH_C4
	/* LV2 select PLL1 */
	int i, cpu_num;

	cpu_num = sw64_chip->get_cpu_num();

	for (i = 0; i < cpu_num; i++) {
		sw64_io_write(i, CLU_LV2_SELH, -1UL);
		sw64_io_write(i, CLU_LV2_SELL, -1UL);
		udelay(1000);
	}
#endif

	local_irq_disable();

	if (cpu_online(cpuid)) {
		pr_err("??, cpu 0x%x already present??\n", cpuid);
		BUG();
	}

	set_cpu_online(cpuid, true);

	/* Set trap vectors.  */
@@ -322,8 +336,10 @@ 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
	/* send reset signal */
	if (is_in_host()) {
		reset_cpu(cpu);
@@ -602,6 +618,22 @@ void __cpu_die(unsigned int cpu)

void arch_cpu_idle_dead(void)
{
#ifdef CONFIG_SUBARCH_C4
	/* LV2 select PLL0 */
	int cpuid = smp_processor_id();
	int core_id = rcid_to_core_id(cpu_to_rcid(cpuid));
	int node_id = rcid_to_domain_id(cpu_to_rcid(cpuid));
	unsigned long value;

	if (core_id > 31) {
		value = 1UL << (2 * (core_id - 32));
		sw64_io_write(node_id, CLU_LV2_SELH, value);
	} else {
		value = 1UL << (2 * core_id);
		sw64_io_write(node_id, CLU_LV2_SELL, value);
	}
#endif

	idle_task_exit();
	mb();
	__this_cpu_write(cpu_state, CPU_DEAD);
@@ -616,10 +648,18 @@ 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

#else
	asm volatile("memb");
	asm volatile("halt");
+10 −0
Original line number Diff line number Diff line
@@ -4,6 +4,8 @@
#include <asm/suspend.h>
#include <asm/sw64_init.h>

#define	PME_EN	0x2

struct processor_state suspend_state;

static int native_suspend_state_valid(suspend_state_t pm_state)
@@ -36,7 +38,15 @@ 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

	wrtp(current_thread_info()->pcb.tp);

	disable_local_timer();
+16 −0
Original line number Diff line number Diff line
@@ -153,12 +153,28 @@ static void handle_dev_int(struct pt_regs *regs)
	sw64_io_write(node, DEV_INT_CONFIG, config_val);
}

int pme_state;

asmlinkage void do_entInt(unsigned long type, unsigned long vector,
			  unsigned long irq_arg, struct pt_regs *regs)
{
	struct pt_regs *old_regs;
	extern char __idle_start[], __idle_end[];

#ifdef CONFIG_SUBARCH_C4
	if (pme_state == PME_WFW) {
		pme_state = PME_PENDING;
		return;
	}

	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

	if (is_guest_or_emul()) {
		if ((type & 0xffff) > 15) {
			vector = type;