]>
Commit | Line | Data |
---|---|---|
9fa1db4c | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
e7fc5146 TK |
2 | /* |
3 | * Adjunct processor (AP) interfaces | |
4 | * | |
5 | * Copyright IBM Corp. 2017 | |
6 | * | |
e7fc5146 TK |
7 | * Author(s): Tony Krowiak <akrowia@linux.vnet.ibm.com> |
8 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | |
9 | * Harald Freudenberger <freude@de.ibm.com> | |
10 | */ | |
11 | ||
12 | #ifndef _ASM_S390_AP_H_ | |
13 | #define _ASM_S390_AP_H_ | |
14 | ||
15 | /** | |
16 | * The ap_qid_t identifier of an ap queue. | |
17 | * If the AP facilities test (APFT) facility is available, | |
18 | * card and queue index are 8 bit values, otherwise | |
19 | * card index is 6 bit and queue index a 4 bit value. | |
20 | */ | |
21 | typedef unsigned int ap_qid_t; | |
22 | ||
af4a7227 HF |
23 | #define AP_MKQID(_card, _queue) (((_card) & 0xff) << 8 | ((_queue) & 0xff)) |
24 | #define AP_QID_CARD(_qid) (((_qid) >> 8) & 0xff) | |
25 | #define AP_QID_QUEUE(_qid) ((_qid) & 0xff) | |
e7fc5146 TK |
26 | |
27 | /** | |
28 | * struct ap_queue_status - Holds the AP queue status. | |
29 | * @queue_empty: Shows if queue is empty | |
30 | * @replies_waiting: Waiting replies | |
31 | * @queue_full: Is 1 if the queue is full | |
32 | * @irq_enabled: Shows if interrupts are enabled for the AP | |
33 | * @response_code: Holds the 8 bit response code | |
34 | * | |
35 | * The ap queue status word is returned by all three AP functions | |
36 | * (PQAP, NQAP and DQAP). There's a set of flags in the first | |
37 | * byte, followed by a 1 byte response code. | |
38 | */ | |
39 | struct ap_queue_status { | |
40 | unsigned int queue_empty : 1; | |
41 | unsigned int replies_waiting : 1; | |
42 | unsigned int queue_full : 1; | |
43 | unsigned int _pad1 : 4; | |
44 | unsigned int irq_enabled : 1; | |
45 | unsigned int response_code : 8; | |
46 | unsigned int _pad2 : 16; | |
47 | }; | |
48 | ||
f1b0a434 HF |
49 | /** |
50 | * ap_intructions_available() - Test if AP instructions are available. | |
51 | * | |
9b97e9f5 | 52 | * Returns true if the AP instructions are installed, otherwise false. |
f1b0a434 | 53 | */ |
9b97e9f5 | 54 | static inline bool ap_instructions_available(void) |
f1b0a434 HF |
55 | { |
56 | register unsigned long reg0 asm ("0") = AP_MKQID(0, 0); | |
2395103b HF |
57 | register unsigned long reg1 asm ("1") = 0; |
58 | register unsigned long reg2 asm ("2") = 0; | |
f1b0a434 HF |
59 | |
60 | asm volatile( | |
61 | " .long 0xb2af0000\n" /* PQAP(TAPQ) */ | |
2395103b | 62 | "0: la %0,1\n" |
f1b0a434 HF |
63 | "1:\n" |
64 | EX_TABLE(0b, 1b) | |
2395103b | 65 | : "+d" (reg1), "+d" (reg2) |
f1b0a434 HF |
66 | : "d" (reg0) |
67 | : "cc"); | |
9b97e9f5 | 68 | return reg1 != 0; |
f1b0a434 HF |
69 | } |
70 | ||
71 | /** | |
72 | * ap_tapq(): Test adjunct processor queue. | |
73 | * @qid: The AP queue number | |
74 | * @info: Pointer to queue descriptor | |
75 | * | |
76 | * Returns AP queue status structure. | |
77 | */ | |
78 | static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info) | |
79 | { | |
80 | register unsigned long reg0 asm ("0") = qid; | |
81 | register struct ap_queue_status reg1 asm ("1"); | |
82 | register unsigned long reg2 asm ("2"); | |
83 | ||
84 | asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */ | |
85 | : "=d" (reg1), "=d" (reg2) | |
86 | : "d" (reg0) | |
87 | : "cc"); | |
88 | if (info) | |
89 | *info = reg2; | |
90 | return reg1; | |
91 | } | |
92 | ||
e7fc5146 TK |
93 | /** |
94 | * ap_test_queue(): Test adjunct processor queue. | |
95 | * @qid: The AP queue number | |
96 | * @tbit: Test facilities bit | |
97 | * @info: Pointer to queue descriptor | |
98 | * | |
99 | * Returns AP queue status structure. | |
100 | */ | |
f1b0a434 HF |
101 | static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, |
102 | int tbit, | |
103 | unsigned long *info) | |
104 | { | |
105 | if (tbit) | |
106 | qid |= 1UL << 23; /* set T bit*/ | |
107 | return ap_tapq(qid, info); | |
108 | } | |
e7fc5146 | 109 | |
f1b0a434 HF |
110 | /** |
111 | * ap_pqap_rapq(): Reset adjunct processor queue. | |
112 | * @qid: The AP queue number | |
113 | * | |
114 | * Returns AP queue status structure. | |
115 | */ | |
116 | static inline struct ap_queue_status ap_rapq(ap_qid_t qid) | |
117 | { | |
118 | register unsigned long reg0 asm ("0") = qid | (1UL << 24); | |
119 | register struct ap_queue_status reg1 asm ("1"); | |
120 | ||
121 | asm volatile( | |
122 | ".long 0xb2af0000" /* PQAP(RAPQ) */ | |
123 | : "=d" (reg1) | |
124 | : "d" (reg0) | |
125 | : "cc"); | |
126 | return reg1; | |
127 | } | |
128 | ||
129 | /** | |
130 | * ap_pqap_zapq(): Reset and zeroize adjunct processor queue. | |
131 | * @qid: The AP queue number | |
132 | * | |
133 | * Returns AP queue status structure. | |
134 | */ | |
135 | static inline struct ap_queue_status ap_zapq(ap_qid_t qid) | |
136 | { | |
137 | register unsigned long reg0 asm ("0") = qid | (2UL << 24); | |
138 | register struct ap_queue_status reg1 asm ("1"); | |
139 | ||
140 | asm volatile( | |
141 | ".long 0xb2af0000" /* PQAP(ZAPQ) */ | |
142 | : "=d" (reg1) | |
143 | : "d" (reg0) | |
144 | : "cc"); | |
145 | return reg1; | |
146 | } | |
147 | ||
148 | /** | |
149 | * struct ap_config_info - convenience struct for AP crypto | |
150 | * config info as returned by the ap_qci() function. | |
151 | */ | |
050349b5 HF |
152 | struct ap_config_info { |
153 | unsigned int apsc : 1; /* S bit */ | |
154 | unsigned int apxa : 1; /* N bit */ | |
155 | unsigned int qact : 1; /* C bit */ | |
156 | unsigned int rc8a : 1; /* R bit */ | |
157 | unsigned char _reserved1 : 4; | |
158 | unsigned char _reserved2[3]; | |
159 | unsigned char Na; /* max # of APs - 1 */ | |
160 | unsigned char Nd; /* max # of Domains - 1 */ | |
161 | unsigned char _reserved3[10]; | |
162 | unsigned int apm[8]; /* AP ID mask */ | |
7379e652 HF |
163 | unsigned int aqm[8]; /* AP (usage) queue mask */ |
164 | unsigned int adm[8]; /* AP (control) domain mask */ | |
050349b5 HF |
165 | unsigned char _reserved4[16]; |
166 | } __aligned(8); | |
167 | ||
f1b0a434 HF |
168 | /** |
169 | * ap_qci(): Get AP configuration data | |
050349b5 | 170 | * |
f1b0a434 | 171 | * Returns 0 on success, or -EOPNOTSUPP. |
050349b5 | 172 | */ |
f1b0a434 HF |
173 | static inline int ap_qci(struct ap_config_info *config) |
174 | { | |
175 | register unsigned long reg0 asm ("0") = 4UL << 24; | |
176 | register unsigned long reg1 asm ("1") = -EOPNOTSUPP; | |
177 | register struct ap_config_info *reg2 asm ("2") = config; | |
178 | ||
179 | asm volatile( | |
180 | ".long 0xb2af0000\n" /* PQAP(QCI) */ | |
181 | "0: la %0,0\n" | |
182 | "1:\n" | |
183 | EX_TABLE(0b, 1b) | |
184 | : "+d" (reg1) | |
185 | : "d" (reg0), "d" (reg2) | |
186 | : "cc", "memory"); | |
187 | ||
188 | return reg1; | |
189 | } | |
050349b5 | 190 | |
46fde9a9 HF |
191 | /* |
192 | * struct ap_qirq_ctrl - convenient struct for easy invocation | |
f1b0a434 HF |
193 | * of the ap_aqic() function. This struct is passed as GR1 |
194 | * parameter to the PQAP(AQIC) instruction. For details please | |
195 | * see the AR documentation. | |
46fde9a9 HF |
196 | */ |
197 | struct ap_qirq_ctrl { | |
198 | unsigned int _res1 : 8; | |
f1b0a434 HF |
199 | unsigned int zone : 8; /* zone info */ |
200 | unsigned int ir : 1; /* ir flag: enable (1) or disable (0) irq */ | |
46fde9a9 | 201 | unsigned int _res2 : 4; |
f1b0a434 | 202 | unsigned int gisc : 3; /* guest isc field */ |
46fde9a9 | 203 | unsigned int _res3 : 6; |
f1b0a434 | 204 | unsigned int gf : 2; /* gisa format */ |
46fde9a9 | 205 | unsigned int _res4 : 1; |
f1b0a434 | 206 | unsigned int gisa : 27; /* gisa origin */ |
46fde9a9 | 207 | unsigned int _res5 : 1; |
f1b0a434 | 208 | unsigned int isc : 3; /* irq sub class */ |
46fde9a9 HF |
209 | }; |
210 | ||
211 | /** | |
f1b0a434 | 212 | * ap_aqic(): Control interruption for a specific AP. |
46fde9a9 | 213 | * @qid: The AP queue number |
f1b0a434 | 214 | * @qirqctrl: struct ap_qirq_ctrl (64 bit value) |
46fde9a9 HF |
215 | * @ind: The notification indicator byte |
216 | * | |
217 | * Returns AP queue status. | |
f1b0a434 HF |
218 | */ |
219 | static inline struct ap_queue_status ap_aqic(ap_qid_t qid, | |
220 | struct ap_qirq_ctrl qirqctrl, | |
221 | void *ind) | |
222 | { | |
223 | register unsigned long reg0 asm ("0") = qid | (3UL << 24); | |
159491f3 HF |
224 | register union { |
225 | unsigned long value; | |
226 | struct ap_qirq_ctrl qirqctrl; | |
227 | struct ap_queue_status status; | |
228 | } reg1 asm ("1"); | |
f1b0a434 HF |
229 | register void *reg2 asm ("2") = ind; |
230 | ||
159491f3 HF |
231 | reg1.qirqctrl = qirqctrl; |
232 | ||
f1b0a434 HF |
233 | asm volatile( |
234 | ".long 0xb2af0000" /* PQAP(AQIC) */ | |
159491f3 HF |
235 | : "+d" (reg1) |
236 | : "d" (reg0), "d" (reg2) | |
f1b0a434 | 237 | : "cc"); |
159491f3 HF |
238 | |
239 | return reg1.status; | |
f1b0a434 HF |
240 | } |
241 | ||
242 | /* | |
243 | * union ap_qact_ap_info - used together with the | |
244 | * ap_aqic() function to provide a convenient way | |
245 | * to handle the ap info needed by the qact function. | |
246 | */ | |
247 | union ap_qact_ap_info { | |
248 | unsigned long val; | |
249 | struct { | |
250 | unsigned int : 3; | |
251 | unsigned int mode : 3; | |
252 | unsigned int : 26; | |
253 | unsigned int cat : 8; | |
254 | unsigned int : 8; | |
255 | unsigned char ver[2]; | |
256 | }; | |
257 | }; | |
258 | ||
259 | /** | |
260 | * ap_qact(): Query AP combatibility type. | |
261 | * @qid: The AP queue number | |
262 | * @apinfo: On input the info about the AP queue. On output the | |
263 | * alternate AP queue info provided by the qact function | |
264 | * in GR2 is stored in. | |
46fde9a9 | 265 | * |
f1b0a434 | 266 | * Returns AP queue status. Check response_code field for failures. |
46fde9a9 | 267 | */ |
f1b0a434 HF |
268 | static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit, |
269 | union ap_qact_ap_info *apinfo) | |
270 | { | |
271 | register unsigned long reg0 asm ("0") = qid | (5UL << 24) | |
272 | | ((ifbit & 0x01) << 22); | |
159491f3 HF |
273 | register union { |
274 | unsigned long value; | |
275 | struct ap_queue_status status; | |
276 | } reg1 asm ("1"); | |
f1b0a434 HF |
277 | register unsigned long reg2 asm ("2"); |
278 | ||
159491f3 HF |
279 | reg1.value = apinfo->val; |
280 | ||
f1b0a434 HF |
281 | asm volatile( |
282 | ".long 0xb2af0000" /* PQAP(QACT) */ | |
159491f3 | 283 | : "+d" (reg1), "=d" (reg2) |
f1b0a434 HF |
284 | : "d" (reg0) |
285 | : "cc"); | |
286 | apinfo->val = reg2; | |
159491f3 | 287 | return reg1.status; |
f1b0a434 HF |
288 | } |
289 | ||
290 | /** | |
291 | * ap_nqap(): Send message to adjunct processor queue. | |
292 | * @qid: The AP queue number | |
293 | * @psmid: The program supplied message identifier | |
294 | * @msg: The message text | |
295 | * @length: The message length | |
296 | * | |
297 | * Returns AP queue status structure. | |
298 | * Condition code 1 on NQAP can't happen because the L bit is 1. | |
299 | * Condition code 2 on NQAP also means the send is incomplete, | |
300 | * because a segment boundary was reached. The NQAP is repeated. | |
301 | */ | |
302 | static inline struct ap_queue_status ap_nqap(ap_qid_t qid, | |
303 | unsigned long long psmid, | |
304 | void *msg, size_t length) | |
305 | { | |
306 | register unsigned long reg0 asm ("0") = qid | 0x40000000UL; | |
307 | register struct ap_queue_status reg1 asm ("1"); | |
308 | register unsigned long reg2 asm ("2") = (unsigned long) msg; | |
309 | register unsigned long reg3 asm ("3") = (unsigned long) length; | |
310 | register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32); | |
311 | register unsigned long reg5 asm ("5") = psmid & 0xffffffff; | |
312 | ||
313 | asm volatile ( | |
314 | "0: .long 0xb2ad0042\n" /* NQAP */ | |
315 | " brc 2,0b" | |
316 | : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3) | |
317 | : "d" (reg4), "d" (reg5) | |
318 | : "cc", "memory"); | |
319 | return reg1; | |
320 | } | |
321 | ||
322 | /** | |
323 | * ap_dqap(): Receive message from adjunct processor queue. | |
324 | * @qid: The AP queue number | |
325 | * @psmid: Pointer to program supplied message identifier | |
326 | * @msg: The message text | |
327 | * @length: The message length | |
328 | * | |
329 | * Returns AP queue status structure. | |
330 | * Condition code 1 on DQAP means the receive has taken place | |
331 | * but only partially. The response is incomplete, hence the | |
332 | * DQAP is repeated. | |
333 | * Condition code 2 on DQAP also means the receive is incomplete, | |
334 | * this time because a segment boundary was reached. Again, the | |
335 | * DQAP is repeated. | |
336 | * Note that gpr2 is used by the DQAP instruction to keep track of | |
337 | * any 'residual' length, in case the instruction gets interrupted. | |
338 | * Hence it gets zeroed before the instruction. | |
339 | */ | |
340 | static inline struct ap_queue_status ap_dqap(ap_qid_t qid, | |
341 | unsigned long long *psmid, | |
342 | void *msg, size_t length) | |
343 | { | |
344 | register unsigned long reg0 asm("0") = qid | 0x80000000UL; | |
345 | register struct ap_queue_status reg1 asm ("1"); | |
346 | register unsigned long reg2 asm("2") = 0UL; | |
347 | register unsigned long reg4 asm("4") = (unsigned long) msg; | |
348 | register unsigned long reg5 asm("5") = (unsigned long) length; | |
349 | register unsigned long reg6 asm("6") = 0UL; | |
350 | register unsigned long reg7 asm("7") = 0UL; | |
351 | ||
352 | ||
353 | asm volatile( | |
354 | "0: .long 0xb2ae0064\n" /* DQAP */ | |
355 | " brc 6,0b\n" | |
356 | : "+d" (reg0), "=d" (reg1), "+d" (reg2), | |
357 | "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7) | |
358 | : : "cc", "memory"); | |
359 | *psmid = (((unsigned long long) reg6) << 32) + reg7; | |
360 | return reg1; | |
361 | } | |
46fde9a9 | 362 | |
0d9c038f TK |
363 | /* |
364 | * Interface to tell the AP bus code that a configuration | |
365 | * change has happened. The bus code should at least do | |
366 | * an ap bus resource rescan. | |
367 | */ | |
368 | #if IS_ENABLED(CONFIG_ZCRYPT) | |
369 | void ap_bus_cfg_chg(void); | |
370 | #else | |
371 | static inline void ap_bus_cfg_chg(void){}; | |
372 | #endif | |
373 | ||
e7fc5146 | 374 | #endif /* _ASM_S390_AP_H_ */ |