xref: /OK3568_Linux_fs/kernel/arch/powerpc/include/asm/dbell.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0-or-later */
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright 2009 Freescale Semiconductor, Inc.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * provides masks and opcode images for use by code generation, emulation
6*4882a593Smuzhiyun  * and for instructions that older assemblers might not know about
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun #ifndef _ASM_POWERPC_DBELL_H
9*4882a593Smuzhiyun #define _ASM_POWERPC_DBELL_H
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/smp.h>
12*4882a593Smuzhiyun #include <linux/threads.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include <asm/cputhreads.h>
15*4882a593Smuzhiyun #include <asm/ppc-opcode.h>
16*4882a593Smuzhiyun #include <asm/feature-fixups.h>
17*4882a593Smuzhiyun #include <asm/kvm_ppc.h>
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #define PPC_DBELL_MSG_BRDCAST	(0x04000000)
20*4882a593Smuzhiyun #define PPC_DBELL_TYPE(x)	(((x) & 0xf) << (63-36))
21*4882a593Smuzhiyun #define PPC_DBELL_TYPE_MASK	PPC_DBELL_TYPE(0xf)
22*4882a593Smuzhiyun #define PPC_DBELL_LPID(x)	((x) << (63 - 49))
23*4882a593Smuzhiyun #define PPC_DBELL_PIR_MASK	0x3fff
24*4882a593Smuzhiyun enum ppc_dbell {
25*4882a593Smuzhiyun 	PPC_DBELL = 0,		/* doorbell */
26*4882a593Smuzhiyun 	PPC_DBELL_CRIT = 1,	/* critical doorbell */
27*4882a593Smuzhiyun 	PPC_G_DBELL = 2,	/* guest doorbell */
28*4882a593Smuzhiyun 	PPC_G_DBELL_CRIT = 3,	/* guest critical doorbell */
29*4882a593Smuzhiyun 	PPC_G_DBELL_MC = 4,	/* guest mcheck doorbell */
30*4882a593Smuzhiyun 	PPC_DBELL_SERVER = 5,	/* doorbell on server */
31*4882a593Smuzhiyun };
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #ifdef CONFIG_PPC_BOOK3S
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun #define PPC_DBELL_MSGTYPE		PPC_DBELL_SERVER
36*4882a593Smuzhiyun 
_ppc_msgsnd(u32 msg)37*4882a593Smuzhiyun static inline void _ppc_msgsnd(u32 msg)
38*4882a593Smuzhiyun {
39*4882a593Smuzhiyun 	__asm__ __volatile__ (ASM_FTR_IFSET(PPC_MSGSND(%1), PPC_MSGSNDP(%1), %0)
40*4882a593Smuzhiyun 				: : "i" (CPU_FTR_HVMODE), "r" (msg));
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun /* sync before sending message */
ppc_msgsnd_sync(void)44*4882a593Smuzhiyun static inline void ppc_msgsnd_sync(void)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun 	__asm__ __volatile__ ("sync" : : : "memory");
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun /* sync after taking message interrupt */
ppc_msgsync(void)50*4882a593Smuzhiyun static inline void ppc_msgsync(void)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun 	/* sync is not required when taking messages from the same core */
53*4882a593Smuzhiyun 	__asm__ __volatile__ (ASM_FTR_IFSET(PPC_MSGSYNC " ; lwsync", "", %0)
54*4882a593Smuzhiyun 				: : "i" (CPU_FTR_HVMODE|CPU_FTR_ARCH_300));
55*4882a593Smuzhiyun }
56*4882a593Smuzhiyun 
_ppc_msgclr(u32 msg)57*4882a593Smuzhiyun static inline void _ppc_msgclr(u32 msg)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 	__asm__ __volatile__ (ASM_FTR_IFSET(PPC_MSGCLR(%1), PPC_MSGCLRP(%1), %0)
60*4882a593Smuzhiyun 				: : "i" (CPU_FTR_HVMODE), "r" (msg));
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun 
ppc_msgclr(enum ppc_dbell type)63*4882a593Smuzhiyun static inline void ppc_msgclr(enum ppc_dbell type)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun 	u32 msg = PPC_DBELL_TYPE(type);
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	_ppc_msgclr(msg);
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun #else /* CONFIG_PPC_BOOK3S */
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun #define PPC_DBELL_MSGTYPE		PPC_DBELL
73*4882a593Smuzhiyun 
_ppc_msgsnd(u32 msg)74*4882a593Smuzhiyun static inline void _ppc_msgsnd(u32 msg)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun 	__asm__ __volatile__ (PPC_MSGSND(%0) : : "r" (msg));
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun /* sync before sending message */
ppc_msgsnd_sync(void)80*4882a593Smuzhiyun static inline void ppc_msgsnd_sync(void)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	__asm__ __volatile__ ("sync" : : : "memory");
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun /* sync after taking message interrupt */
ppc_msgsync(void)86*4882a593Smuzhiyun static inline void ppc_msgsync(void)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun #endif /* CONFIG_PPC_BOOK3S */
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun extern void doorbell_exception(struct pt_regs *regs);
93*4882a593Smuzhiyun 
ppc_msgsnd(enum ppc_dbell type,u32 flags,u32 tag)94*4882a593Smuzhiyun static inline void ppc_msgsnd(enum ppc_dbell type, u32 flags, u32 tag)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun 	u32 msg = PPC_DBELL_TYPE(type) | (flags & PPC_DBELL_MSG_BRDCAST) |
97*4882a593Smuzhiyun 			(tag & 0x07ffffff);
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	_ppc_msgsnd(msg);
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun #ifdef CONFIG_SMP
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun /*
105*4882a593Smuzhiyun  * Doorbells must only be used if CPU_FTR_DBELL is available.
106*4882a593Smuzhiyun  * msgsnd is used in HV, and msgsndp is used in !HV.
107*4882a593Smuzhiyun  *
108*4882a593Smuzhiyun  * These should be used by platform code that is aware of restrictions.
109*4882a593Smuzhiyun  * Other arch code should use ->cause_ipi.
110*4882a593Smuzhiyun  *
111*4882a593Smuzhiyun  * doorbell_global_ipi() sends a dbell to any target CPU.
112*4882a593Smuzhiyun  * Must be used only by architectures that address msgsnd target
113*4882a593Smuzhiyun  * by PIR/get_hard_smp_processor_id.
114*4882a593Smuzhiyun  */
doorbell_global_ipi(int cpu)115*4882a593Smuzhiyun static inline void doorbell_global_ipi(int cpu)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	u32 tag = get_hard_smp_processor_id(cpu);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	kvmppc_set_host_ipi(cpu);
120*4882a593Smuzhiyun 	/* Order previous accesses vs. msgsnd, which is treated as a store */
121*4882a593Smuzhiyun 	ppc_msgsnd_sync();
122*4882a593Smuzhiyun 	ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag);
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun /*
126*4882a593Smuzhiyun  * doorbell_core_ipi() sends a dbell to a target CPU in the same core.
127*4882a593Smuzhiyun  * Must be used only by architectures that address msgsnd target
128*4882a593Smuzhiyun  * by TIR/cpu_thread_in_core.
129*4882a593Smuzhiyun  */
doorbell_core_ipi(int cpu)130*4882a593Smuzhiyun static inline void doorbell_core_ipi(int cpu)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun 	u32 tag = cpu_thread_in_core(cpu);
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	kvmppc_set_host_ipi(cpu);
135*4882a593Smuzhiyun 	/* Order previous accesses vs. msgsnd, which is treated as a store */
136*4882a593Smuzhiyun 	ppc_msgsnd_sync();
137*4882a593Smuzhiyun 	ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag);
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun /*
141*4882a593Smuzhiyun  * Attempt to cause a core doorbell if destination is on the same core.
142*4882a593Smuzhiyun  * Returns 1 on success, 0 on failure.
143*4882a593Smuzhiyun  */
doorbell_try_core_ipi(int cpu)144*4882a593Smuzhiyun static inline int doorbell_try_core_ipi(int cpu)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	int this_cpu = get_cpu();
147*4882a593Smuzhiyun 	int ret = 0;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	if (cpumask_test_cpu(cpu, cpu_sibling_mask(this_cpu))) {
150*4882a593Smuzhiyun 		doorbell_core_ipi(cpu);
151*4882a593Smuzhiyun 		ret = 1;
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	put_cpu();
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	return ret;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun #endif /* CONFIG_SMP */
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun #endif /* _ASM_POWERPC_DBELL_H */
162