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