162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2010 IBM Corp, Benjamin Herrenschmidt <benh@kernel.crashing.org> 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Generic idle routine for 64 bits e500 processors 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/threads.h> 962306a36Sopenharmony_ci#include <asm/reg.h> 1062306a36Sopenharmony_ci#include <asm/ppc_asm.h> 1162306a36Sopenharmony_ci#include <asm/asm-offsets.h> 1262306a36Sopenharmony_ci#include <asm/ppc-opcode.h> 1362306a36Sopenharmony_ci#include <asm/processor.h> 1462306a36Sopenharmony_ci#include <asm/thread_info.h> 1562306a36Sopenharmony_ci#include <asm/epapr_hcalls.h> 1662306a36Sopenharmony_ci#include <asm/hw_irq.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* 64-bit version only for now */ 1962306a36Sopenharmony_ci.macro BOOK3E_IDLE name loop 2062306a36Sopenharmony_ci_GLOBAL(\name) 2162306a36Sopenharmony_ci /* Save LR for later */ 2262306a36Sopenharmony_ci mflr r0 2362306a36Sopenharmony_ci std r0,16(r1) 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci /* Hard disable interrupts */ 2662306a36Sopenharmony_ci wrteei 0 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci /* Now check if an interrupt came in while we were soft disabled 2962306a36Sopenharmony_ci * since we may otherwise lose it (doorbells etc...). 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ci lbz r3,PACAIRQHAPPENED(r13) 3262306a36Sopenharmony_ci cmpwi cr0,r3,0 3362306a36Sopenharmony_ci bne 2f 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci /* Now we are going to mark ourselves as soft and hard enabled in 3662306a36Sopenharmony_ci * order to be able to take interrupts while asleep. We inform lockdep 3762306a36Sopenharmony_ci * of that. We don't actually turn interrupts on just yet tho. 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ci#ifdef CONFIG_TRACE_IRQFLAGS 4062306a36Sopenharmony_ci stdu r1,-128(r1) 4162306a36Sopenharmony_ci bl trace_hardirqs_on 4262306a36Sopenharmony_ci addi r1,r1,128 4362306a36Sopenharmony_ci#endif 4462306a36Sopenharmony_ci li r0,IRQS_ENABLED 4562306a36Sopenharmony_ci stb r0,PACAIRQSOFTMASK(r13) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci /* Interrupts will make use return to LR, so get something we want 4862306a36Sopenharmony_ci * in there 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_ci bl 1f 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci /* And return (interrupts are on) */ 5362306a36Sopenharmony_ci ld r0,16(r1) 5462306a36Sopenharmony_ci mtlr r0 5562306a36Sopenharmony_ci blr 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci1: /* Let's set the _TLF_NAPPING flag so interrupts make us return 5862306a36Sopenharmony_ci * to the right spot 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci ld r11, PACACURRENT(r13) 6162306a36Sopenharmony_ci ld r10,TI_LOCAL_FLAGS(r11) 6262306a36Sopenharmony_ci ori r10,r10,_TLF_NAPPING 6362306a36Sopenharmony_ci std r10,TI_LOCAL_FLAGS(r11) 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* We can now re-enable hard interrupts and go to sleep */ 6662306a36Sopenharmony_ci wrteei 1 6762306a36Sopenharmony_ci \loop 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci2: 7062306a36Sopenharmony_ci lbz r10,PACAIRQHAPPENED(r13) 7162306a36Sopenharmony_ci ori r10,r10,PACA_IRQ_HARD_DIS 7262306a36Sopenharmony_ci stb r10,PACAIRQHAPPENED(r13) 7362306a36Sopenharmony_ci blr 7462306a36Sopenharmony_ci.endm 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci.macro BOOK3E_IDLE_LOOP 7762306a36Sopenharmony_ci1: 7862306a36Sopenharmony_ci PPC_WAIT_v203 7962306a36Sopenharmony_ci b 1b 8062306a36Sopenharmony_ci.endm 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* epapr_ev_idle_start below is patched with the proper hcall 8362306a36Sopenharmony_ci opcodes during kernel initialization */ 8462306a36Sopenharmony_ci.macro EPAPR_EV_IDLE_LOOP 8562306a36Sopenharmony_ciidle_loop: 8662306a36Sopenharmony_ci LOAD_REG_IMMEDIATE(r11, EV_HCALL_TOKEN(EV_IDLE)) 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci.global epapr_ev_idle_start 8962306a36Sopenharmony_ciepapr_ev_idle_start: 9062306a36Sopenharmony_ci li r3, -1 9162306a36Sopenharmony_ci nop 9262306a36Sopenharmony_ci nop 9362306a36Sopenharmony_ci nop 9462306a36Sopenharmony_ci b idle_loop 9562306a36Sopenharmony_ci.endm 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ciBOOK3E_IDLE epapr_ev_idle EPAPR_EV_IDLE_LOOP 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ciBOOK3E_IDLE e500_idle BOOK3E_IDLE_LOOP 100