]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
0db78559 MS |
2 | /* |
3 | * Copyright IBM Corp. 2016 | |
4 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> | |
5 | * | |
6 | * Adjunct processor bus inline assemblies. | |
7 | */ | |
8 | ||
9 | #ifndef _AP_ASM_H_ | |
10 | #define _AP_ASM_H_ | |
11 | ||
12 | #include <asm/isc.h> | |
13 | ||
14 | /** | |
15 | * ap_intructions_available() - Test if AP instructions are available. | |
16 | * | |
17 | * Returns 0 if the AP instructions are installed. | |
18 | */ | |
19 | static inline int ap_instructions_available(void) | |
20 | { | |
21 | register unsigned long reg0 asm ("0") = AP_MKQID(0, 0); | |
22 | register unsigned long reg1 asm ("1") = -ENODEV; | |
23 | register unsigned long reg2 asm ("2") = 0UL; | |
24 | ||
25 | asm volatile( | |
26 | " .long 0xb2af0000\n" /* PQAP(TAPQ) */ | |
27 | "0: la %1,0\n" | |
28 | "1:\n" | |
29 | EX_TABLE(0b, 1b) | |
30 | : "+d" (reg0), "+d" (reg1), "+d" (reg2) : : "cc"); | |
31 | return reg1; | |
32 | } | |
33 | ||
34 | /** | |
35 | * ap_tapq(): Test adjunct processor queue. | |
36 | * @qid: The AP queue number | |
37 | * @info: Pointer to queue descriptor | |
38 | * | |
39 | * Returns AP queue status structure. | |
40 | */ | |
41 | static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info) | |
42 | { | |
43 | register unsigned long reg0 asm ("0") = qid; | |
44 | register struct ap_queue_status reg1 asm ("1"); | |
45 | register unsigned long reg2 asm ("2") = 0UL; | |
46 | ||
47 | asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */ | |
48 | : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc"); | |
49 | if (info) | |
50 | *info = reg2; | |
51 | return reg1; | |
52 | } | |
53 | ||
54 | /** | |
55 | * ap_pqap_rapq(): Reset adjunct processor queue. | |
56 | * @qid: The AP queue number | |
57 | * | |
58 | * Returns AP queue status structure. | |
59 | */ | |
60 | static inline struct ap_queue_status ap_rapq(ap_qid_t qid) | |
61 | { | |
62 | register unsigned long reg0 asm ("0") = qid | 0x01000000UL; | |
63 | register struct ap_queue_status reg1 asm ("1"); | |
64 | register unsigned long reg2 asm ("2") = 0UL; | |
65 | ||
66 | asm volatile( | |
67 | ".long 0xb2af0000" /* PQAP(RAPQ) */ | |
68 | : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc"); | |
69 | return reg1; | |
70 | } | |
71 | ||
72 | /** | |
46fde9a9 | 73 | * ap_aqic(): Control interruption for a specific AP. |
0db78559 | 74 | * @qid: The AP queue number |
46fde9a9 | 75 | * @qirqctrl: struct ap_qirq_ctrl (64 bit value) |
0db78559 MS |
76 | * @ind: The notification indicator byte |
77 | * | |
78 | * Returns AP queue status. | |
79 | */ | |
46fde9a9 HF |
80 | static inline struct ap_queue_status ap_aqic(ap_qid_t qid, |
81 | struct ap_qirq_ctrl qirqctrl, | |
82 | void *ind) | |
0db78559 MS |
83 | { |
84 | register unsigned long reg0 asm ("0") = qid | (3UL << 24); | |
46fde9a9 | 85 | register struct ap_qirq_ctrl reg1_in asm ("1") = qirqctrl; |
0db78559 MS |
86 | register struct ap_queue_status reg1_out asm ("1"); |
87 | register void *reg2 asm ("2") = ind; | |
88 | ||
89 | asm volatile( | |
90 | ".long 0xb2af0000" /* PQAP(AQIC) */ | |
91 | : "+d" (reg0), "+d" (reg1_in), "=d" (reg1_out), "+d" (reg2) | |
92 | : | |
93 | : "cc"); | |
94 | return reg1_out; | |
95 | } | |
96 | ||
97 | /** | |
98 | * ap_qci(): Get AP configuration data | |
99 | * | |
100 | * Returns 0 on success, or -EOPNOTSUPP. | |
101 | */ | |
102 | static inline int ap_qci(void *config) | |
103 | { | |
104 | register unsigned long reg0 asm ("0") = 0x04000000UL; | |
105 | register unsigned long reg1 asm ("1") = -EINVAL; | |
106 | register void *reg2 asm ("2") = (void *) config; | |
107 | ||
108 | asm volatile( | |
109 | ".long 0xb2af0000\n" /* PQAP(QCI) */ | |
110 | "0: la %1,0\n" | |
111 | "1:\n" | |
112 | EX_TABLE(0b, 1b) | |
113 | : "+d" (reg0), "+d" (reg1), "+d" (reg2) | |
114 | : | |
d0350268 | 115 | : "cc", "memory"); |
0db78559 MS |
116 | |
117 | return reg1; | |
118 | } | |
119 | ||
120 | /** | |
121 | * ap_nqap(): Send message to adjunct processor queue. | |
122 | * @qid: The AP queue number | |
123 | * @psmid: The program supplied message identifier | |
124 | * @msg: The message text | |
125 | * @length: The message length | |
126 | * | |
127 | * Returns AP queue status structure. | |
128 | * Condition code 1 on NQAP can't happen because the L bit is 1. | |
129 | * Condition code 2 on NQAP also means the send is incomplete, | |
130 | * because a segment boundary was reached. The NQAP is repeated. | |
131 | */ | |
132 | static inline struct ap_queue_status ap_nqap(ap_qid_t qid, | |
133 | unsigned long long psmid, | |
134 | void *msg, size_t length) | |
135 | { | |
0db78559 MS |
136 | register unsigned long reg0 asm ("0") = qid | 0x40000000UL; |
137 | register struct ap_queue_status reg1 asm ("1"); | |
138 | register unsigned long reg2 asm ("2") = (unsigned long) msg; | |
139 | register unsigned long reg3 asm ("3") = (unsigned long) length; | |
140 | register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32); | |
141 | register unsigned long reg5 asm ("5") = psmid & 0xffffffff; | |
142 | ||
143 | asm volatile ( | |
144 | "0: .long 0xb2ad0042\n" /* NQAP */ | |
145 | " brc 2,0b" | |
146 | : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3) | |
57c52ae7 HC |
147 | : "d" (reg4), "d" (reg5) |
148 | : "cc", "memory"); | |
0db78559 MS |
149 | return reg1; |
150 | } | |
151 | ||
152 | /** | |
153 | * ap_dqap(): Receive message from adjunct processor queue. | |
154 | * @qid: The AP queue number | |
155 | * @psmid: Pointer to program supplied message identifier | |
156 | * @msg: The message text | |
157 | * @length: The message length | |
158 | * | |
159 | * Returns AP queue status structure. | |
160 | * Condition code 1 on DQAP means the receive has taken place | |
161 | * but only partially. The response is incomplete, hence the | |
162 | * DQAP is repeated. | |
163 | * Condition code 2 on DQAP also means the receive is incomplete, | |
164 | * this time because a segment boundary was reached. Again, the | |
165 | * DQAP is repeated. | |
166 | * Note that gpr2 is used by the DQAP instruction to keep track of | |
167 | * any 'residual' length, in case the instruction gets interrupted. | |
168 | * Hence it gets zeroed before the instruction. | |
169 | */ | |
170 | static inline struct ap_queue_status ap_dqap(ap_qid_t qid, | |
171 | unsigned long long *psmid, | |
172 | void *msg, size_t length) | |
173 | { | |
0db78559 MS |
174 | register unsigned long reg0 asm("0") = qid | 0x80000000UL; |
175 | register struct ap_queue_status reg1 asm ("1"); | |
176 | register unsigned long reg2 asm("2") = 0UL; | |
177 | register unsigned long reg4 asm("4") = (unsigned long) msg; | |
178 | register unsigned long reg5 asm("5") = (unsigned long) length; | |
179 | register unsigned long reg6 asm("6") = 0UL; | |
180 | register unsigned long reg7 asm("7") = 0UL; | |
181 | ||
182 | ||
183 | asm volatile( | |
184 | "0: .long 0xb2ae0064\n" /* DQAP */ | |
185 | " brc 6,0b\n" | |
186 | : "+d" (reg0), "=d" (reg1), "+d" (reg2), | |
57c52ae7 HC |
187 | "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7) |
188 | : : "cc", "memory"); | |
0db78559 MS |
189 | *psmid = (((unsigned long long) reg6) << 32) + reg7; |
190 | return reg1; | |
191 | } | |
192 | ||
193 | #endif /* _AP_ASM_H_ */ |