1
2
3
4
5
6
7
8
9
10
11
12#ifndef _ASM_S390_AP_H_
13#define _ASM_S390_AP_H_
14
15
16
17
18
19
20
21typedef unsigned int ap_qid_t;
22
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)
26
27
28
29
30
31
32
33
34
35
36
37
38
39struct 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
49
50
51
52
53
54static inline bool ap_instructions_available(void)
55{
56 unsigned long reg0 = AP_MKQID(0, 0);
57 unsigned long reg1 = 0;
58
59 asm volatile(
60 " lgr 0,%[reg0]\n"
61 " lghi 1,0\n"
62 " lghi 2,0\n"
63 " .long 0xb2af0000\n"
64 "0: la %[reg1],1\n"
65 "1:\n"
66 EX_TABLE(0b, 1b)
67 : [reg1] "+&d" (reg1)
68 : [reg0] "d" (reg0)
69 : "cc", "0", "1", "2");
70 return reg1 != 0;
71}
72
73
74
75
76
77
78
79
80static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info)
81{
82 struct ap_queue_status reg1;
83 unsigned long reg2;
84
85 asm volatile(
86 " lgr 0,%[qid]\n"
87 " lghi 2,0\n"
88 " .long 0xb2af0000\n"
89 " lgr %[reg1],1\n"
90 " lgr %[reg2],2\n"
91 : [reg1] "=&d" (reg1), [reg2] "=&d" (reg2)
92 : [qid] "d" (qid)
93 : "cc", "0", "1", "2");
94 if (info)
95 *info = reg2;
96 return reg1;
97}
98
99
100
101
102
103
104
105
106
107static inline struct ap_queue_status ap_test_queue(ap_qid_t qid,
108 int tbit,
109 unsigned long *info)
110{
111 if (tbit)
112 qid |= 1UL << 23;
113 return ap_tapq(qid, info);
114}
115
116
117
118
119
120
121
122static inline struct ap_queue_status ap_rapq(ap_qid_t qid)
123{
124 unsigned long reg0 = qid | (1UL << 24);
125 struct ap_queue_status reg1;
126
127 asm volatile(
128 " lgr 0,%[reg0]\n"
129 " .long 0xb2af0000\n"
130 " lgr %[reg1],1\n"
131 : [reg1] "=&d" (reg1)
132 : [reg0] "d" (reg0)
133 : "cc", "0", "1");
134 return reg1;
135}
136
137
138
139
140
141
142
143static inline struct ap_queue_status ap_zapq(ap_qid_t qid)
144{
145 unsigned long reg0 = qid | (2UL << 24);
146 struct ap_queue_status reg1;
147
148 asm volatile(
149 " lgr 0,%[reg0]\n"
150 " .long 0xb2af0000\n"
151 " lgr %[reg1],1\n"
152 : [reg1] "=&d" (reg1)
153 : [reg0] "d" (reg0)
154 : "cc", "0", "1");
155 return reg1;
156}
157
158
159
160
161
162struct ap_config_info {
163 unsigned int apsc : 1;
164 unsigned int apxa : 1;
165 unsigned int qact : 1;
166 unsigned int rc8a : 1;
167 unsigned char _reserved1 : 4;
168 unsigned char _reserved2[3];
169 unsigned char Na;
170 unsigned char Nd;
171 unsigned char _reserved3[10];
172 unsigned int apm[8];
173 unsigned int aqm[8];
174 unsigned int adm[8];
175 unsigned char _reserved4[16];
176} __aligned(8);
177
178
179
180
181
182
183static inline int ap_qci(struct ap_config_info *config)
184{
185 unsigned long reg0 = 4UL << 24;
186 unsigned long reg1 = -EOPNOTSUPP;
187 struct ap_config_info *reg2 = config;
188
189 asm volatile(
190 " lgr 0,%[reg0]\n"
191 " lgr 2,%[reg2]\n"
192 " .long 0xb2af0000\n"
193 "0: la %[reg1],0\n"
194 "1:\n"
195 EX_TABLE(0b, 1b)
196 : [reg1] "+&d" (reg1)
197 : [reg0] "d" (reg0), [reg2] "d" (reg2)
198 : "cc", "memory", "0", "2");
199
200 return reg1;
201}
202
203
204
205
206
207
208
209struct ap_qirq_ctrl {
210 unsigned int _res1 : 8;
211 unsigned int zone : 8;
212 unsigned int ir : 1;
213 unsigned int _res2 : 4;
214 unsigned int gisc : 3;
215 unsigned int _res3 : 6;
216 unsigned int gf : 2;
217 unsigned int _res4 : 1;
218 unsigned int gisa : 27;
219 unsigned int _res5 : 1;
220 unsigned int isc : 3;
221};
222
223
224
225
226
227
228
229
230
231static inline struct ap_queue_status ap_aqic(ap_qid_t qid,
232 struct ap_qirq_ctrl qirqctrl,
233 void *ind)
234{
235 unsigned long reg0 = qid | (3UL << 24);
236 union {
237 unsigned long value;
238 struct ap_qirq_ctrl qirqctrl;
239 struct ap_queue_status status;
240 } reg1;
241 void *reg2 = ind;
242
243 reg1.qirqctrl = qirqctrl;
244
245 asm volatile(
246 " lgr 0,%[reg0]\n"
247 " lgr 1,%[reg1]\n"
248 " lgr 2,%[reg2]\n"
249 " .long 0xb2af0000\n"
250 " lgr %[reg1],1\n"
251 : [reg1] "+&d" (reg1)
252 : [reg0] "d" (reg0), [reg2] "d" (reg2)
253 : "cc", "0", "1", "2");
254
255 return reg1.status;
256}
257
258
259
260
261
262
263union ap_qact_ap_info {
264 unsigned long val;
265 struct {
266 unsigned int : 3;
267 unsigned int mode : 3;
268 unsigned int : 26;
269 unsigned int cat : 8;
270 unsigned int : 8;
271 unsigned char ver[2];
272 };
273};
274
275
276
277
278
279
280
281
282
283
284static inline struct ap_queue_status ap_qact(ap_qid_t qid, int ifbit,
285 union ap_qact_ap_info *apinfo)
286{
287 unsigned long reg0 = qid | (5UL << 24) | ((ifbit & 0x01) << 22);
288 union {
289 unsigned long value;
290 struct ap_queue_status status;
291 } reg1;
292 unsigned long reg2;
293
294 reg1.value = apinfo->val;
295
296 asm volatile(
297 " lgr 0,%[reg0]\n"
298 " lgr 1,%[reg1]\n"
299 " .long 0xb2af0000\n"
300 " lgr %[reg1],1\n"
301 " lgr %[reg2],2\n"
302 : [reg1] "+&d" (reg1), [reg2] "=&d" (reg2)
303 : [reg0] "d" (reg0)
304 : "cc", "0", "1", "2");
305 apinfo->val = reg2;
306 return reg1.status;
307}
308
309
310
311
312
313
314
315
316
317
318
319
320
321static inline struct ap_queue_status ap_nqap(ap_qid_t qid,
322 unsigned long long psmid,
323 void *msg, size_t length)
324{
325 unsigned long reg0 = qid | 0x40000000UL;
326 union register_pair nqap_r1, nqap_r2;
327 struct ap_queue_status reg1;
328
329 nqap_r1.even = (unsigned int)(psmid >> 32);
330 nqap_r1.odd = psmid & 0xffffffff;
331 nqap_r2.even = (unsigned long)msg;
332 nqap_r2.odd = (unsigned long)length;
333
334 asm volatile (
335 " lgr 0,%[reg0]\n"
336 "0: .insn rre,0xb2ad0000,%[nqap_r1],%[nqap_r2]\n"
337 " brc 2,0b\n"
338 " lgr %[reg1],1\n"
339 : [reg0] "+&d" (reg0), [reg1] "=&d" (reg1),
340 [nqap_r2] "+&d" (nqap_r2.pair)
341 : [nqap_r1] "d" (nqap_r1.pair)
342 : "cc", "memory", "0", "1");
343 return reg1;
344}
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376static inline struct ap_queue_status ap_dqap(ap_qid_t qid,
377 unsigned long long *psmid,
378 void *msg, size_t length,
379 size_t *reslength,
380 unsigned long *resgr0)
381{
382 unsigned long reg0 = resgr0 && *resgr0 ? *resgr0 : qid | 0x80000000UL;
383 struct ap_queue_status reg1;
384 unsigned long reg2;
385 union register_pair rp1, rp2;
386
387 rp1.even = 0UL;
388 rp1.odd = 0UL;
389 rp2.even = (unsigned long)msg;
390 rp2.odd = (unsigned long)length;
391
392 asm volatile(
393 " lgr 0,%[reg0]\n"
394 " lghi 2,0\n"
395 "0: ltgr %N[rp2],%N[rp2]\n"
396 " jz 2f\n"
397 "1: .insn rre,0xb2ae0000,%[rp1],%[rp2]\n"
398 " brc 6,0b\n"
399 "2: lgr %[reg0],0\n"
400 " lgr %[reg1],1\n"
401 " lgr %[reg2],2\n"
402 : [reg0] "+&d" (reg0), [reg1] "=&d" (reg1), [reg2] "=&d" (reg2),
403 [rp1] "+&d" (rp1.pair), [rp2] "+&d" (rp2.pair)
404 :
405 : "cc", "memory", "0", "1", "2");
406
407 if (reslength)
408 *reslength = reg2;
409 if (reg2 != 0 && rp2.odd == 0) {
410
411
412
413
414
415 reg1.response_code = 0xFF;
416 if (resgr0)
417 *resgr0 = reg0;
418 } else {
419 *psmid = (((unsigned long long)rp1.even) << 32) + rp1.odd;
420 if (resgr0)
421 *resgr0 = 0;
422 }
423
424 return reg1;
425}
426
427
428
429
430
431
432#if IS_ENABLED(CONFIG_ZCRYPT)
433void ap_bus_cfg_chg(void);
434#else
435static inline void ap_bus_cfg_chg(void){}
436#endif
437
438#endif
439